mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 16:52:14 +00:00
Compare commits
1008 Commits
options
...
openbsd-fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8499e02c6 | ||
|
|
adf3d62786 | ||
|
|
22c2ad08c9 | ||
|
|
1bbdde8d04 | ||
|
|
e0158d8006 | ||
|
|
07af239503 | ||
|
|
8826a7502d | ||
|
|
e1e594540f | ||
|
|
15d0275b87 | ||
|
|
1e41629759 | ||
|
|
7777db84a8 | ||
|
|
b20e874701 | ||
|
|
606d4d89e4 | ||
|
|
05e8eb3005 | ||
|
|
efd5cc85a5 | ||
|
|
e68491df4d | ||
|
|
02044bcad7 | ||
|
|
41a4a5acc9 | ||
|
|
fae23e60b1 | ||
|
|
34cfc32311 | ||
|
|
4d28e34dfa | ||
|
|
0501b88d7e | ||
|
|
9515f4e1df | ||
|
|
26906fe9f9 | ||
|
|
e8b59f66e6 | ||
|
|
9561ebad1c | ||
|
|
755a3ec78d | ||
|
|
5f80218655 | ||
|
|
3719df39cd | ||
|
|
67a2f97633 | ||
|
|
8b3e90234b | ||
|
|
8044857bb9 | ||
|
|
414d0d6b84 | ||
|
|
2c372461e8 | ||
|
|
2b436127ee | ||
|
|
c342762484 | ||
|
|
c2da58e548 | ||
|
|
aea22dbf6b | ||
|
|
084a85fc6e | ||
|
|
2171367d97 | ||
|
|
67a92df441 | ||
|
|
c773ee16cf | ||
|
|
274fc3163a | ||
|
|
44cae64d49 | ||
|
|
55e2460967 | ||
|
|
bcdd91188c | ||
|
|
e455a12e2c | ||
|
|
e8b5bf17f0 | ||
|
|
20510abc65 | ||
|
|
0058a9c69f | ||
|
|
a26f4fe3c5 | ||
|
|
ff5b383833 | ||
|
|
0379ee6668 | ||
|
|
193384a450 | ||
|
|
406cd3ecf3 | ||
|
|
c6951ff773 | ||
|
|
f2330c195a | ||
|
|
2ae279bd15 | ||
|
|
7a17af0f5c | ||
|
|
768944672f | ||
|
|
46acb247f5 | ||
|
|
08e3549713 | ||
|
|
029ad735fe | ||
|
|
03a348ebdd | ||
|
|
f289f26c87 | ||
|
|
8d9aa1e31d | ||
|
|
1873f34435 | ||
|
|
5f795d9e62 | ||
|
|
f17be678f2 | ||
|
|
b9fc531507 | ||
|
|
69c2c25729 | ||
|
|
8ab2332327 | ||
|
|
ea69cda6d8 | ||
|
|
6b75b4039f | ||
|
|
3c1beb40f6 | ||
|
|
e51970e3bb | ||
|
|
f3f8548dea | ||
|
|
4b7a00d4cf | ||
|
|
c11f31d77e | ||
|
|
3769ec01f4 | ||
|
|
af47f4677c | ||
|
|
cf14d54343 | ||
|
|
b81cac8042 | ||
|
|
c92cce3652 | ||
|
|
d270712fba | ||
|
|
7b6b93691f | ||
|
|
507768e230 | ||
|
|
502dc48753 | ||
|
|
402acc151a | ||
|
|
0503b0997c | ||
|
|
8d372cb510 | ||
|
|
bfb1ebb5bd | ||
|
|
c005adc8fc | ||
|
|
5cab462710 | ||
|
|
ccd46dc692 | ||
|
|
b3c8c3a8da | ||
|
|
4dd6f28094 | ||
|
|
d73f228469 | ||
|
|
ccd1717588 | ||
|
|
9a4aeab97e | ||
|
|
d66dce11bd | ||
|
|
fc38699a4b | ||
|
|
a859c5151c | ||
|
|
8c2f403841 | ||
|
|
6fb2702a79 | ||
|
|
6cd4244f05 | ||
|
|
0c42a58eac | ||
|
|
f269236d38 | ||
|
|
4b413d34f4 | ||
|
|
1403af769b | ||
|
|
964f6d3f7e | ||
|
|
bccf42a3ec | ||
|
|
70c7ae694f | ||
|
|
1fdd405a3f | ||
|
|
af2e884352 | ||
|
|
1fbd8bb5e1 | ||
|
|
09ba5e8d47 | ||
|
|
2c6304b563 | ||
|
|
e79c5f5edd | ||
|
|
7a9ab79162 | ||
|
|
0c1c6dfa90 | ||
|
|
4f9f4c398a | ||
|
|
e4a3e305b4 | ||
|
|
9d51e1cd32 | ||
|
|
f1302430cb | ||
|
|
6f0d6a2e24 | ||
|
|
57b67e0173 | ||
|
|
bbc7eb82e5 | ||
|
|
744e9d95b3 | ||
|
|
bc9a98787e | ||
|
|
0fdd448c67 | ||
|
|
5fcf5465ce | ||
|
|
1dc9d8689e | ||
|
|
dc915be11d | ||
|
|
d7df60938e | ||
|
|
765650aed3 | ||
|
|
f12bc25122 | ||
|
|
32a2c2297c | ||
|
|
3258e3a11c | ||
|
|
ba7e8db9bb | ||
|
|
3211afda4a | ||
|
|
d3f006acd4 | ||
|
|
99633a6e42 | ||
|
|
1e614ee43e | ||
|
|
0e3358705d | ||
|
|
27a35f452d | ||
|
|
8fff7283ed | ||
|
|
611dac143f | ||
|
|
8d93576b94 | ||
|
|
f703845011 | ||
|
|
abd052e09f | ||
|
|
a3304564c6 | ||
|
|
5865c6b449 | ||
|
|
4c872c0a0d | ||
|
|
feabbee098 | ||
|
|
a5b6e70c39 | ||
|
|
347fc68476 | ||
|
|
61ff12c8da | ||
|
|
bd8e81153c | ||
|
|
5fde6bec9f | ||
|
|
cf64f7dc6a | ||
|
|
8355c3e1b6 | ||
|
|
de797e388d | ||
|
|
fc33435f8b | ||
|
|
f45ec624db | ||
|
|
9682056278 | ||
|
|
a00115b454 | ||
|
|
3db86ac69f | ||
|
|
5ffb6bf8da | ||
|
|
2c5a38bfbe | ||
|
|
f28a6406ae | ||
|
|
7a1820d546 | ||
|
|
6bc5add9a7 | ||
|
|
f876ba81e6 | ||
|
|
e943f8fb9c | ||
|
|
bc55a93dce | ||
|
|
2eee42d5e6 | ||
|
|
2d2b124647 | ||
|
|
50986cc330 | ||
|
|
09f0a2c547 | ||
|
|
13af16bfec | ||
|
|
7745fdc687 | ||
|
|
d36f481392 | ||
|
|
011380c28a | ||
|
|
ebd4e723c3 | ||
|
|
b8108c508f | ||
|
|
ecf3dde88c | ||
|
|
4761b375d0 | ||
|
|
ae6a9e6639 | ||
|
|
2c35167d9b | ||
|
|
b68900ca1c | ||
|
|
ba7fe11193 | ||
|
|
b0da4ad10c | ||
|
|
c1b6eb4eb8 | ||
|
|
4ef1792b0a | ||
|
|
1a6956134a | ||
|
|
eb6bce0910 | ||
|
|
9a1c6991c9 | ||
|
|
352b6cf89f | ||
|
|
317b1b7c62 | ||
|
|
a7b65bfc44 | ||
|
|
ee945a6b95 | ||
|
|
992de7b6ea | ||
|
|
6e597b5c8a | ||
|
|
1a1d677d76 | ||
|
|
c1fb7758b2 | ||
|
|
e24af699cf | ||
|
|
e585864cf4 | ||
|
|
69a0615530 | ||
|
|
26f4584e1e | ||
|
|
43e845a691 | ||
|
|
4d59330067 | ||
|
|
f59c1c180e | ||
|
|
618c931188 | ||
|
|
727881649c | ||
|
|
dd4bf8d857 | ||
|
|
9d006cdd94 | ||
|
|
442a6ed8d8 | ||
|
|
686945f46f | ||
|
|
8979836f32 | ||
|
|
4dfc1bd4fd | ||
|
|
f90edf44e1 | ||
|
|
f56e42fd2e | ||
|
|
b9420be981 | ||
|
|
548ea7d999 | ||
|
|
f453d93e83 | ||
|
|
693a33010d | ||
|
|
faad3fa4df | ||
|
|
4e2e580b4c | ||
|
|
d60ea9c4d3 | ||
|
|
a911da2c1f | ||
|
|
f0c98aa97f | ||
|
|
062ac9beb2 | ||
|
|
fb48747fc8 | ||
|
|
f2a0367605 | ||
|
|
3163496b70 | ||
|
|
4e64224ef1 | ||
|
|
25669a78de | ||
|
|
910192e2ad | ||
|
|
15984e3288 | ||
|
|
6aa704c208 | ||
|
|
62d40caddd | ||
|
|
d63d502b40 | ||
|
|
3a401dd306 | ||
|
|
3893a96c6e | ||
|
|
76c393fb8e | ||
|
|
4fce3c8184 | ||
|
|
54b698dcbd | ||
|
|
1f45677518 | ||
|
|
1493e365ed | ||
|
|
5e5e0b8641 | ||
|
|
932ac3038e | ||
|
|
00bc1ccf47 | ||
|
|
257da990d5 | ||
|
|
c6a812e401 | ||
|
|
f93290d3d4 | ||
|
|
a46ab25046 | ||
|
|
1b61ba6ea7 | ||
|
|
27f79e1774 | ||
|
|
0fbfa1cdc1 | ||
|
|
47c4496d05 | ||
|
|
c473251709 | ||
|
|
7bdf11f550 | ||
|
|
dbcc946dac | ||
|
|
e0e801cbb4 | ||
|
|
4943c74e8e | ||
|
|
0733217423 | ||
|
|
397e685053 | ||
|
|
610b337fa3 | ||
|
|
bbb7dced5c | ||
|
|
ab82e78c3d | ||
|
|
a295cd8635 | ||
|
|
b8bcfa2e11 | ||
|
|
ed659bf129 | ||
|
|
4cadf1d333 | ||
|
|
220bec28bf | ||
|
|
ee3c2cfeeb | ||
|
|
221550a848 | ||
|
|
b7821ccf09 | ||
|
|
1f464b3eb5 | ||
|
|
5abb4f4a23 | ||
|
|
722bd31cdb | ||
|
|
e358dc52a2 | ||
|
|
d54788a385 | ||
|
|
4a5d711c86 | ||
|
|
d11e327ab0 | ||
|
|
edaf70a7a7 | ||
|
|
dc8ba65c77 | ||
|
|
ea26c7b2bd | ||
|
|
4d1c438d91 | ||
|
|
d231979a6c | ||
|
|
a3e8600e40 | ||
|
|
c1d0f1be76 | ||
|
|
10c93d88a1 | ||
|
|
5f80e72e9c | ||
|
|
d26ef52519 | ||
|
|
f4d2c260d4 | ||
|
|
e32651a260 | ||
|
|
71aa7d9c00 | ||
|
|
ed3b066da1 | ||
|
|
83380dad79 | ||
|
|
5ad5e82577 | ||
|
|
3acc1a3fa8 | ||
|
|
9bb088ed5d | ||
|
|
cd4ef692e1 | ||
|
|
268795f3c0 | ||
|
|
f8f9c2323c | ||
|
|
0c3ded6636 | ||
|
|
20b328dbf1 | ||
|
|
a60203dac3 | ||
|
|
6d08cb369e | ||
|
|
8dc5ee22f5 | ||
|
|
f7053f31ec | ||
|
|
a13a60d428 | ||
|
|
fa2a522ef2 | ||
|
|
2b39b56efb | ||
|
|
5a283e5200 | ||
|
|
3d5f449052 | ||
|
|
aefb990a7a | ||
|
|
3d092498b2 | ||
|
|
7d7476343a | ||
|
|
e08374ed95 | ||
|
|
155ebdcf1f | ||
|
|
a9925a5d6d | ||
|
|
741d3f4a07 | ||
|
|
f195243a81 | ||
|
|
8c5ab02192 | ||
|
|
b526ac7ce5 | ||
|
|
8222a57744 | ||
|
|
aa3ae06ab7 | ||
|
|
1b4d67170f | ||
|
|
e3594034eb | ||
|
|
ee983eba64 | ||
|
|
0eb4685558 | ||
|
|
7cf1a3b8e6 | ||
|
|
c0a1a82361 | ||
|
|
532951902f | ||
|
|
642c2d369f | ||
|
|
d7a721ee0d | ||
|
|
baa8d3fe7c | ||
|
|
42bdfb5545 | ||
|
|
0f053c323e | ||
|
|
036c9fc4d1 | ||
|
|
b2a96a3e13 | ||
|
|
1dbb3626a9 | ||
|
|
d79e1f2443 | ||
|
|
605dcd19d8 | ||
|
|
6b6a6fa61c | ||
|
|
295e2bdd9c | ||
|
|
dd1513846b | ||
|
|
7a94abfaf2 | ||
|
|
b55a09479c | ||
|
|
5afb20760c | ||
|
|
eec87e1dd9 | ||
|
|
f250a33fb4 | ||
|
|
570cf83a96 | ||
|
|
d52d244f83 | ||
|
|
04ab646f12 | ||
|
|
31c65b5442 | ||
|
|
ebbb6d8b36 | ||
|
|
b9c0140a26 | ||
|
|
27f587a4be | ||
|
|
7f6061c956 | ||
|
|
2f32c95341 | ||
|
|
a8029fc191 | ||
|
|
9f4bd9bce3 | ||
|
|
71f844c24f | ||
|
|
b0b6d67e6f | ||
|
|
3a2576a4d8 | ||
|
|
34eaa262dd | ||
|
|
ce3b3d8f99 | ||
|
|
429f2ba95c | ||
|
|
0c2e7387c8 | ||
|
|
2a2ea4b92d | ||
|
|
873ab2558d | ||
|
|
03571d4eaf | ||
|
|
46ab3ba9b8 | ||
|
|
3aba1f6eb1 | ||
|
|
44771769fa | ||
|
|
8704416941 | ||
|
|
f48392399f | ||
|
|
80f81117aa | ||
|
|
9cff55215d | ||
|
|
2e4b3c2406 | ||
|
|
b510b6a9d9 | ||
|
|
046b96186f | ||
|
|
1df2e67bc4 | ||
|
|
6cf69e2797 | ||
|
|
d3e4cbf3b3 | ||
|
|
e67e49c891 | ||
|
|
29a43b17e4 | ||
|
|
6d10c3a807 | ||
|
|
668579ed6f | ||
|
|
8af828cd43 | ||
|
|
590cc10b42 | ||
|
|
3bc11ce3ac | ||
|
|
603441ecc3 | ||
|
|
612a953369 | ||
|
|
1554773d39 | ||
|
|
dd003bf2b0 | ||
|
|
0341e08297 | ||
|
|
5853345715 | ||
|
|
41f8b1cf00 | ||
|
|
56ae00c7a4 | ||
|
|
f58882c956 | ||
|
|
3f14ebc755 | ||
|
|
1502de1001 | ||
|
|
8541cae396 | ||
|
|
38fa1fd040 | ||
|
|
ba15f760ab | ||
|
|
5e3e8f977e | ||
|
|
6182876d4f | ||
|
|
5bfd2ee08c | ||
|
|
c91b227c47 | ||
|
|
6a4d2ff721 | ||
|
|
6bf37ea8e8 | ||
|
|
ad38cdfada | ||
|
|
167ee79fa9 | ||
|
|
6b83d0b9dd | ||
|
|
16d16d40be | ||
|
|
f5f0866745 | ||
|
|
408cff1997 | ||
|
|
09faec4732 | ||
|
|
5ab43529b7 | ||
|
|
97f5b3c049 | ||
|
|
6dd3e0bdb4 | ||
|
|
eba5cb7be2 | ||
|
|
f4c51bcd5a | ||
|
|
410c0d592e | ||
|
|
40df7899b2 | ||
|
|
51083a8fa8 | ||
|
|
fe3cb0efc7 | ||
|
|
e0dd3b9658 | ||
|
|
d7d84f3952 | ||
|
|
6ccce9104a | ||
|
|
984c0c5b71 | ||
|
|
43523fcf8b | ||
|
|
cf7ad36438 | ||
|
|
ca994c1972 | ||
|
|
0a554c92b5 | ||
|
|
fa81cecffc | ||
|
|
977b76f6aa | ||
|
|
fc1acb82d9 | ||
|
|
db7af9f87d | ||
|
|
a350cc346b | ||
|
|
9fa86d3d65 | ||
|
|
e426f2bfac | ||
|
|
6b173117aa | ||
|
|
ecbc93408f | ||
|
|
6ba9a48d15 | ||
|
|
519c0a636a | ||
|
|
82195c61af | ||
|
|
c604e3a20e | ||
|
|
b27d0170ba | ||
|
|
98fd4eecf0 | ||
|
|
3799315ce7 | ||
|
|
b9431ba492 | ||
|
|
c0dca35615 | ||
|
|
790d79db9c | ||
|
|
5de0a795d1 | ||
|
|
cbaa913e3d | ||
|
|
5786162fb5 | ||
|
|
78c44dd560 | ||
|
|
23ff67d83d | ||
|
|
476c6ccd95 | ||
|
|
28126b3432 | ||
|
|
ed8388d091 | ||
|
|
43c402a5da | ||
|
|
9ff2f6f3ef | ||
|
|
b2a0fadaca | ||
|
|
3c4057204e | ||
|
|
717ac47510 | ||
|
|
4f6f4eb391 | ||
|
|
99e04036c7 | ||
|
|
519e339365 | ||
|
|
d2c930470f | ||
|
|
d5709ae747 | ||
|
|
d2ab81b1b9 | ||
|
|
885557fe01 | ||
|
|
b5b758f89a | ||
|
|
2a954eb809 | ||
|
|
0edff5449a | ||
|
|
417ea77f2f | ||
|
|
9e3fdc9669 | ||
|
|
66c2867371 | ||
|
|
caa7b2fcc8 | ||
|
|
6263e74bcd | ||
|
|
faae08ee64 | ||
|
|
2314e19f12 | ||
|
|
cfd0fc055c | ||
|
|
849b5d0f30 | ||
|
|
d13df2a194 | ||
|
|
86fc3b0b4d | ||
|
|
4733ca719f | ||
|
|
296f12eb64 | ||
|
|
96d3470e37 | ||
|
|
2265c98d81 | ||
|
|
060e5c2526 | ||
|
|
b4894807f1 | ||
|
|
2aa5e1461c | ||
|
|
61fa15fa48 | ||
|
|
92508e06a1 | ||
|
|
e85f0d0816 | ||
|
|
5e90c8de9b | ||
|
|
a486a25a07 | ||
|
|
f8c0dd4da5 | ||
|
|
ee6870bfbc | ||
|
|
0422b6bfb8 | ||
|
|
7fc41b2815 | ||
|
|
a49f1f6e2d | ||
|
|
af54484bc2 | ||
|
|
ebcb30e4bd | ||
|
|
5371c9813b | ||
|
|
9a833c610d | ||
|
|
c99ebfee7a | ||
|
|
34861366e0 | ||
|
|
e6722c452c | ||
|
|
b1e38842fb | ||
|
|
bcc9826e67 | ||
|
|
b6c6753b87 | ||
|
|
0d008a88fc | ||
|
|
f92ec53968 | ||
|
|
00a87d0a67 | ||
|
|
462334639c | ||
|
|
7129182044 | ||
|
|
03fbed44ad | ||
|
|
0277c4fcec | ||
|
|
4bc1ae6ff8 | ||
|
|
266c4503aa | ||
|
|
80479b6b70 | ||
|
|
823a346a08 | ||
|
|
8f3a7b9c63 | ||
|
|
2ebcc07892 | ||
|
|
a673cd9643 | ||
|
|
12971db132 | ||
|
|
94be279992 | ||
|
|
12cded5995 | ||
|
|
0c16a0e5b3 | ||
|
|
e4a6fde7b9 | ||
|
|
92d2bebaaf | ||
|
|
7e7a8cbc1d | ||
|
|
4f767f4bfe | ||
|
|
63f714ae2f | ||
|
|
1b3b9b707c | ||
|
|
f64bc8a6d4 | ||
|
|
102834130d | ||
|
|
fdc6a11cbc | ||
|
|
19b20f55ce | ||
|
|
60d072ce46 | ||
|
|
34f05b9276 | ||
|
|
1b476b0430 | ||
|
|
b294710e60 | ||
|
|
f8cd325d1b | ||
|
|
2a6c23e173 | ||
|
|
d7768b7221 | ||
|
|
b8821eac57 | ||
|
|
d20b64cf37 | ||
|
|
f0ddd6ca29 | ||
|
|
574d9e09d6 | ||
|
|
7085a50f36 | ||
|
|
0485459da2 | ||
|
|
318439af2e | ||
|
|
4d52ff362f | ||
|
|
8d48d9cbfa | ||
|
|
f25c31c847 | ||
|
|
192191ecfb | ||
|
|
3eacae5e38 | ||
|
|
14b294c10c | ||
|
|
881da4f9e2 | ||
|
|
3aeb6601cd | ||
|
|
8a7c37617e | ||
|
|
2758e8d438 | ||
|
|
b5a6b4b945 | ||
|
|
ac94f81b77 | ||
|
|
06747d7dd3 | ||
|
|
fb9b9215e0 | ||
|
|
eed0505f6e | ||
|
|
8f6aa8bcff | ||
|
|
6f9cabbd04 | ||
|
|
355d20faf3 | ||
|
|
15c4a64a81 | ||
|
|
49ec65a735 | ||
|
|
7cdea96caf | ||
|
|
8bf7da3b6b | ||
|
|
c1ad9d1227 | ||
|
|
1b6ccb6d39 | ||
|
|
e2e2b5ddb2 | ||
|
|
b4584dd0b0 | ||
|
|
55e5d178bd | ||
|
|
f778702257 | ||
|
|
b4ff07cfcb | ||
|
|
d43858078f | ||
|
|
f2cf918be5 | ||
|
|
54dd027a64 | ||
|
|
1ea894ab30 | ||
|
|
92c45f4b61 | ||
|
|
03cba8f5bd | ||
|
|
97f08ba0b3 | ||
|
|
c843815c6c | ||
|
|
b5785b3370 | ||
|
|
a6e5a5a619 | ||
|
|
2d627f633b | ||
|
|
ef486764ac | ||
|
|
fce3962376 | ||
|
|
5a40a0ee9c | ||
|
|
4bf795922d | ||
|
|
1646b240c7 | ||
|
|
d4f7bfaa6c | ||
|
|
bac06d2bc7 | ||
|
|
579499d9e8 | ||
|
|
b8c46bfc47 | ||
|
|
d234ce4f63 | ||
|
|
1be807e748 | ||
|
|
f4db2613eb | ||
|
|
bae6098e91 | ||
|
|
c40153fab1 | ||
|
|
e5eec4a5dc | ||
|
|
887bb8c482 | ||
|
|
0642bf5e70 | ||
|
|
513208a117 | ||
|
|
49247f0a83 | ||
|
|
ccb7dd482a | ||
|
|
08f40ff46b | ||
|
|
956f7b5fdf | ||
|
|
40d0f8c401 | ||
|
|
cbc7580fcd | ||
|
|
f96dfd6e8f | ||
|
|
ea24ebaf92 | ||
|
|
504e760760 | ||
|
|
c5e7cfb4f5 | ||
|
|
9904e3a5e8 | ||
|
|
191673b049 | ||
|
|
3a6d11f9b8 | ||
|
|
e022ad3742 | ||
|
|
16d9350992 | ||
|
|
5e1d7b6901 | ||
|
|
82d4cef182 | ||
|
|
5a112ea4bb | ||
|
|
b058e1cadf | ||
|
|
a8b28ef262 | ||
|
|
080f3fb074 | ||
|
|
997f10c7e9 | ||
|
|
4ced4d0933 | ||
|
|
eafe8e327a | ||
|
|
a4c89a3dec | ||
|
|
902390d57a | ||
|
|
5c55590922 | ||
|
|
0485932309 | ||
|
|
e1a3aded4e | ||
|
|
5b2d5c76c8 | ||
|
|
2c3c9e84a5 | ||
|
|
ad90ca6366 | ||
|
|
88952f0ab2 | ||
|
|
29cd54ea8c | ||
|
|
c2ee6da367 | ||
|
|
317801ca5e | ||
|
|
3923da14f7 | ||
|
|
5aa691cc3a | ||
|
|
04712d57f4 | ||
|
|
ed4c861e78 | ||
|
|
587eaa8054 | ||
|
|
78b5ea1f6b | ||
|
|
6412aa3ece | ||
|
|
68a3ba0c41 | ||
|
|
ecaba9efc1 | ||
|
|
fb682944d9 | ||
|
|
9c60e4987c | ||
|
|
59b361fb46 | ||
|
|
f3b2c0a67e | ||
|
|
69c04d5e29 | ||
|
|
78f4115a32 | ||
|
|
9b1b83f5e7 | ||
|
|
bd859e98d3 | ||
|
|
d7accdcf0c | ||
|
|
d159fea7b8 | ||
|
|
b5b91d578d | ||
|
|
498055bc8d | ||
|
|
502169a5ad | ||
|
|
42fbbbd8a6 | ||
|
|
dd0b26de4c | ||
|
|
10665bfaff | ||
|
|
2576ed166f | ||
|
|
9ad7413189 | ||
|
|
9cd405a66f | ||
|
|
fc6773d7d3 | ||
|
|
c3b707b709 | ||
|
|
57e9dfb705 | ||
|
|
4fd8887601 | ||
|
|
3cf4bf6480 | ||
|
|
256523d36e | ||
|
|
6ba8e88def | ||
|
|
f139f863a0 | ||
|
|
0938103427 | ||
|
|
e72127f9f8 | ||
|
|
eea73753b5 | ||
|
|
4f3b425073 | ||
|
|
dcb8a0266a | ||
|
|
99285a9de6 | ||
|
|
6cc31b93d8 | ||
|
|
d1ce19d848 | ||
|
|
f00895a9fc | ||
|
|
8d2bd87707 | ||
|
|
44162ecf22 | ||
|
|
d709c1cd07 | ||
|
|
90d2c0ceca | ||
|
|
9549ffe7e1 | ||
|
|
dd0edb4aee | ||
|
|
3029f4623a | ||
|
|
74606db379 | ||
|
|
81803868a3 | ||
|
|
eff42f91ef | ||
|
|
a25b6ca35b | ||
|
|
1c8323650d | ||
|
|
52f030a83c | ||
|
|
9cc651bdeb | ||
|
|
128cb0283d | ||
|
|
bb259f8f16 | ||
|
|
bb1bb431e5 | ||
|
|
41b7e30c18 | ||
|
|
f1c6909eb0 | ||
|
|
35fda5aa6a | ||
|
|
1f7f805858 | ||
|
|
d47b7f7ac4 | ||
|
|
2bc2531d2a | ||
|
|
c5798fdf7f | ||
|
|
5e43e7c07c | ||
|
|
6abce365c5 | ||
|
|
4fc4784506 | ||
|
|
900aab5d6d | ||
|
|
f61a61cf59 | ||
|
|
8e8d36772e | ||
|
|
ec04919825 | ||
|
|
6625999765 | ||
|
|
0d3688aca5 | ||
|
|
40be786c43 | ||
|
|
d4a0444223 | ||
|
|
f99cfe77f4 | ||
|
|
ed32531369 | ||
|
|
751af041cd | ||
|
|
a0ceebd59f | ||
|
|
b0b37f2ce6 | ||
|
|
cf1f904ae2 | ||
|
|
8aaf53d76d | ||
|
|
76c03ded89 | ||
|
|
e6fa19b4c5 | ||
|
|
92ee239891 | ||
|
|
c37e2a7524 | ||
|
|
a610fe74ff | ||
|
|
ea49952da2 | ||
|
|
a55946eb5d | ||
|
|
9f6c338631 | ||
|
|
60302c0017 | ||
|
|
08eaf8b7a1 | ||
|
|
cc70ec9362 | ||
|
|
b58ecc7c9d | ||
|
|
668cbcdaf4 | ||
|
|
6d7cbd0989 | ||
|
|
0764f788a6 | ||
|
|
2b95dd7011 | ||
|
|
ae380c30ad | ||
|
|
d2265890bd | ||
|
|
831d49c1b3 | ||
|
|
6935c53510 | ||
|
|
f30d90a179 | ||
|
|
55cfcecfb8 | ||
|
|
233f46a2cb | ||
|
|
342554b3d8 | ||
|
|
7aa812a0e1 | ||
|
|
c4ffd0c18d | ||
|
|
a411f06dc4 | ||
|
|
d085262076 | ||
|
|
0396740467 | ||
|
|
0fd7de9481 | ||
|
|
ba790dad0a | ||
|
|
f2e8776965 | ||
|
|
444d5eb702 | ||
|
|
3e12e989ab | ||
|
|
917030c3cd | ||
|
|
faf848bd8b | ||
|
|
d78c7901b3 | ||
|
|
09e98d8746 | ||
|
|
ab6e5b54ec | ||
|
|
b268e0e1fb | ||
|
|
996f4b357c | ||
|
|
8ce3e760dc | ||
|
|
6e60928b1f | ||
|
|
e27baa7628 | ||
|
|
337a6e3e83 | ||
|
|
bbfc334c93 | ||
|
|
1a9fa2cc2c | ||
|
|
1296e02372 | ||
|
|
585104605e | ||
|
|
d0c07b7c63 | ||
|
|
7c9ce7f8b9 | ||
|
|
c388f24d6e | ||
|
|
b1f50e953b | ||
|
|
852d8f3d9d | ||
|
|
2c026e43a8 | ||
|
|
51396227a0 | ||
|
|
75d3049199 | ||
|
|
3d9a8b2353 | ||
|
|
8097c2e07a | ||
|
|
d9231d466c | ||
|
|
153e05eac0 | ||
|
|
883b6ac937 | ||
|
|
764fff1f65 | ||
|
|
16ff42290a | ||
|
|
6adf1bf545 | ||
|
|
126659f2f9 | ||
|
|
90adf118ac | ||
|
|
63952fa2a6 | ||
|
|
2f00162817 | ||
|
|
28b402eed1 | ||
|
|
3f12d82e00 | ||
|
|
e01c1e0d37 | ||
|
|
c2602e86e9 | ||
|
|
e2a2a57820 | ||
|
|
547c04fc1f | ||
|
|
6ab2ed1723 | ||
|
|
79e26878b1 | ||
|
|
d15e7be16a | ||
|
|
3ab038fc0f | ||
|
|
66989a25f2 | ||
|
|
c748fff766 | ||
|
|
4772a08f89 | ||
|
|
054d7980ab | ||
|
|
4c6b0fff2a | ||
|
|
449eef0b98 | ||
|
|
3992965359 | ||
|
|
264b517b38 | ||
|
|
71c2fad8ce | ||
|
|
5b45fad163 | ||
|
|
e899189bf4 | ||
|
|
241883c9e4 | ||
|
|
aeee4e5dbb | ||
|
|
e08e095fd1 | ||
|
|
da34b4020d | ||
|
|
99001ccb50 | ||
|
|
f402f48138 | ||
|
|
1960360099 | ||
|
|
83019b5f70 | ||
|
|
76418ca191 | ||
|
|
f02e72304f | ||
|
|
4850ae493f | ||
|
|
77aecb43b8 | ||
|
|
66e576806f | ||
|
|
15445fd2bf | ||
|
|
6f49261c6e | ||
|
|
062b26e046 | ||
|
|
bb0fe86292 | ||
|
|
a3d3a98d5b | ||
|
|
950f16fe42 | ||
|
|
225b322e56 | ||
|
|
3e31d43d61 | ||
|
|
085adc07ec | ||
|
|
6aaefedf25 | ||
|
|
8df9c467e5 | ||
|
|
529d09f43b | ||
|
|
ce2a06f3a6 | ||
|
|
93a077e911 | ||
|
|
9ed2ebef27 | ||
|
|
7882bad799 | ||
|
|
92e1e04ae4 | ||
|
|
cf19c451fa | ||
|
|
74dd6570e3 | ||
|
|
826177a12e | ||
|
|
6712c54827 | ||
|
|
6a64b9e0bd | ||
|
|
34377ecad0 | ||
|
|
ae2b0a9024 | ||
|
|
712ebf772b | ||
|
|
7a99be71d3 | ||
|
|
210efd8dc5 | ||
|
|
ed15395f6d | ||
|
|
05443af621 | ||
|
|
a25665aeff | ||
|
|
ee4428c226 | ||
|
|
74814e46c1 | ||
|
|
f27898cdcd | ||
|
|
007dd97486 | ||
|
|
f0082aa797 | ||
|
|
ba14d9f870 | ||
|
|
684f9bcf11 | ||
|
|
51735a5640 | ||
|
|
d6b242c54a | ||
|
|
4075371cbe | ||
|
|
d5d2c7b2ff | ||
|
|
1ac22670c7 | ||
|
|
477a60ead3 | ||
|
|
9daf3b4717 | ||
|
|
9cab8d455a | ||
|
|
f1bd81d56e | ||
|
|
28dc0c8830 | ||
|
|
7e217fe012 | ||
|
|
04063ee076 | ||
|
|
384e712912 | ||
|
|
64bf929094 | ||
|
|
18ab3ae8c1 | ||
|
|
6c63771ca9 | ||
|
|
3a733827eb | ||
|
|
226b3bd1fc | ||
|
|
158565dbef | ||
|
|
a410059f6b | ||
|
|
3cf5cf49e3 | ||
|
|
deb6af4b2b | ||
|
|
b784a5b3cf | ||
|
|
f74523503d | ||
|
|
41ead2a2d6 | ||
|
|
aa048edd69 | ||
|
|
b15530152a | ||
|
|
3b4bf985f1 | ||
|
|
d218ba7b48 | ||
|
|
94f87c4615 | ||
|
|
99029b9cb7 | ||
|
|
ba5a6bfcf1 | ||
|
|
054bdc47c1 | ||
|
|
6b433c8788 | ||
|
|
cf2a196d40 | ||
|
|
843e56ec1a | ||
|
|
e4a00c9545 | ||
|
|
55b338ab7c | ||
|
|
f18b585740 | ||
|
|
87027b2176 | ||
|
|
e4a3d459c5 | ||
|
|
4d6e802fca | ||
|
|
2f6e83b4e4 | ||
|
|
da42203fef | ||
|
|
87cbedccd8 | ||
|
|
d561667301 | ||
|
|
9cfab7e19c | ||
|
|
4ca67407bb | ||
|
|
70dad97816 | ||
|
|
f14285e954 | ||
|
|
7c108c7540 | ||
|
|
ed8ef66310 | ||
|
|
988515d8d7 | ||
|
|
954ff35e3a | ||
|
|
389dd1adc1 | ||
|
|
167981e273 | ||
|
|
caa7348827 | ||
|
|
c529567a07 | ||
|
|
8729f409f3 | ||
|
|
4f46f43387 | ||
|
|
a69e8d1ebe | ||
|
|
94213f0312 | ||
|
|
22da39b201 | ||
|
|
2a7f5bb66f | ||
|
|
237d5d929f | ||
|
|
6a497ea6a1 | ||
|
|
663fc69691 | ||
|
|
2cb340fb6a | ||
|
|
ed045434a4 | ||
|
|
4ce19ef57e | ||
|
|
6525e639e2 | ||
|
|
f742bf4018 | ||
|
|
7c3640d8c3 | ||
|
|
30ebcfcda6 | ||
|
|
fc601c2e31 | ||
|
|
d1ae99bd1b | ||
|
|
1b0f0cf83e | ||
|
|
5d47a29bfe | ||
|
|
bba7968f7a | ||
|
|
ca1c83cee9 | ||
|
|
5e969baf6b | ||
|
|
684be37ad7 | ||
|
|
17446449a3 | ||
|
|
6f61869867 | ||
|
|
ff1a090026 | ||
|
|
029580c12e | ||
|
|
0d98efe98a | ||
|
|
9db6449044 | ||
|
|
a7d861d806 | ||
|
|
1b737392d0 | ||
|
|
db948e46cb | ||
|
|
56044b1140 | ||
|
|
c0130038e7 | ||
|
|
52ee999d41 | ||
|
|
9c0699ff72 | ||
|
|
c492c099ce | ||
|
|
f2b6cad7ee | ||
|
|
176437d789 | ||
|
|
15c04af3c4 | ||
|
|
ad9d2ce14d | ||
|
|
4f0444a06b | ||
|
|
68b8685d8e | ||
|
|
35ed7fdcc0 | ||
|
|
3edeb104f9 | ||
|
|
e79c9d4322 | ||
|
|
f70f61ccd1 | ||
|
|
6e0754e942 | ||
|
|
9b8f6c4906 | ||
|
|
43fae9108d | ||
|
|
b6a3123f47 | ||
|
|
fb73448cb7 | ||
|
|
8c7d82aa35 | ||
|
|
90f20addd7 | ||
|
|
6c31f3b1a0 | ||
|
|
c4ff1d2bef | ||
|
|
ac28e433a0 | ||
|
|
cceb5bf702 | ||
|
|
46191bc17e | ||
|
|
c893f6e627 | ||
|
|
162c23364d | ||
|
|
13fb61e21a | ||
|
|
0c183fb78f | ||
|
|
e67bd43eb0 | ||
|
|
c832c1443f | ||
|
|
a39fb6d79f |
75
.circleci/config.yml
Normal file
75
.circleci/config.yml
Normal file
@@ -0,0 +1,75 @@
|
||||
version: 2
|
||||
|
||||
jobs:
|
||||
build:
|
||||
environment:
|
||||
- BOOST_LIBRARY=process
|
||||
- CXX_STANDARD=gnu++11
|
||||
docker:
|
||||
- image: gcc:7
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Setting up Environment
|
||||
command: |
|
||||
echo 'export BOOST="$HOME/boost-local"' >> $BASH_ENV
|
||||
if [ $CIRCLE_BRANCH = "master" ]; then
|
||||
echo 'export BOOST_BRANCH="master"' >> $BASH_ENV;
|
||||
else
|
||||
echo 'export BOOST_BRANCH="develop"' >> $BASH_ENV;
|
||||
fi
|
||||
echo 'export BOOST_REMOVE="$BOOST/libs/$BOOST_LIBRARY"' >> $BASH_ENV
|
||||
HOME_SED_=$(echo $HOME | sed -e 's/\//\\\//g')
|
||||
echo 'export HOME_SED=$HOME_SED_' >> $BASH_ENV
|
||||
- run:
|
||||
name: install pre dependencies
|
||||
command: |
|
||||
apt-get update -yqq
|
||||
apt-get install git curl valgrind -y
|
||||
- run:
|
||||
name: Initializing git repo for boost
|
||||
command: |
|
||||
git init $BOOST
|
||||
cd $BOOST
|
||||
echo Testing $BRANCH_TO_TEST
|
||||
git remote add --no-tags -t $BOOST_BRANCH origin https://github.com/boostorg/boost.git
|
||||
git fetch --depth=1
|
||||
git checkout $BOOST_BRANCH
|
||||
git submodule update --init --merge
|
||||
git remote set-branches --add origin $BOOST_BRANCH
|
||||
git pull --recurse-submodules
|
||||
git submodule update --init
|
||||
git checkout $BOOST_BRANCH
|
||||
git submodule foreach "git reset --quiet --hard; git clean -fxd"
|
||||
git reset --hard; git clean -fxd
|
||||
git status
|
||||
rm -rf $BOOST_REMOVE
|
||||
mv $HOME/project $BOOST_REMOVE
|
||||
- run:
|
||||
name: Bootstrapping boost-build
|
||||
command: |
|
||||
cd $BOOST
|
||||
./bootstrap.sh
|
||||
./b2 headers
|
||||
- run:
|
||||
name: Building examples
|
||||
command: |
|
||||
cd $BOOST_REMOVE/example
|
||||
../../../b2 -j2 address-model=64 architecture=x86 toolset=gcc cxxflags="-std=gnu++14" -sBOOST_BUILD_PATH=. | tee example.log || FAILED=1
|
||||
sed -i -e "s/^..\/..\/..\/boost\/process\//\/root\/project\/include\/boost\/process\//gm" example.log
|
||||
python <(curl -s https://report.ci/annotate.py) --tool gcc --name "Circle CI Gcc Build" --input example.log
|
||||
exit $FAILED
|
||||
- run:
|
||||
name: Running Unit tests
|
||||
command: |
|
||||
cd $BOOST_REMOVE/test
|
||||
../../../b2 -j2 with-valgrind address-model=64 architecture=x86 testing.launcher=valgrind valgrind=on toolset=gcc cxxflags="--coverage -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. | tee test.log || FAILED=1
|
||||
../../../b2 -j2 without-valgrind address-model=64 architecture=x86 toolset=gcc cxxflags="--coverage -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. | tee no-valgrind.log || FAILED=1
|
||||
sed -i -e "s/^..\/..\/..\/boost\/process\//\/root\/project\/include\/boost\/process\//gm" test.log
|
||||
sed -i -e "s/^..\/..\/..\/boost\/process\//\/root\/project\/include\/boost\/process\//gm" no-valgrind.log
|
||||
|
||||
python <(curl -s https://report.ci/annotate.py) --tool gcc --input test.log
|
||||
python <(curl -s https://report.ci/annotate.py) --tool gcc --input no-valgrind.log
|
||||
bash <(curl -s https://codecov.io/bash) -x gcov > /dev/null || true
|
||||
echo "BUILD_RESULT: $FAILED"
|
||||
exit $FAILED
|
||||
38
.drone.star
Normal file
38
.drone.star
Normal file
@@ -0,0 +1,38 @@
|
||||
# Use, modification, and distribution are
|
||||
# subject to the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE.txt)
|
||||
#
|
||||
# Copyright Rene Rivera 2020.
|
||||
|
||||
# For Drone CI we use the Starlark scripting language to reduce duplication.
|
||||
# As the yaml syntax for Drone CI is rather limited.
|
||||
#
|
||||
#
|
||||
globalenv={'B2_CI_VERSION': '1', 'B2_VARIANT': 'release'}
|
||||
linuxglobalimage="cppalliance/droneubuntu1804:1"
|
||||
windowsglobalimage="cppalliance/dronevs2019"
|
||||
|
||||
def main(ctx):
|
||||
return [
|
||||
freebsd_cxx("gcc 11 freebsd", "g++-11", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '17,20', 'B2_LINKFLAGS': '-Wl,-rpath=/usr/local/lib/gcc11'}, globalenv=globalenv),
|
||||
freebsd_cxx("clang 14 freebsd", "clang++-14", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'clang-14', 'B2_CXXSTD': '17,20'}, globalenv=globalenv),
|
||||
linux_cxx("docs", "", packages="docbook docbook-xml docbook-xsl xsltproc libsaxonhe-java default-jre-headless flex libfl-dev bison unzip rsync", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv),
|
||||
linux_cxx("asan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_ASAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'DRONE_EXTRA_PRIVILEGED': 'True', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv, privileged=True),
|
||||
linux_cxx("ubsan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'ubsan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_UBSAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'B2_LINKFLAGS': '-fuse-ld=gold', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv),
|
||||
#linux_cxx("gcc 11 arm64", "g++-11", packages="g++-11", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", environment={ 'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '17ba079169m'}, arch="arm64", globalenv=globalenv),
|
||||
linux_cxx("GCC 10, Debug + Coverage", "g++-10", packages="g++-10 libssl-dev libffi-dev binutils-gold gdb",
|
||||
image="cppalliance/droneubuntu2004:1", buildtype="boost", buildscript="drone", environment={"GCOV": "gcov-10", "LCOV_VERSION": "1.15", "VARIANT": "process_coverage", "TOOLSET": "gcc", "COMPILER": "g++-10", "CXXSTD": "11", "DRONE_BEFORE_INSTALL" : "process_coverage", "CODECOV_TOKEN": {"from_secret": "codecov_token"}}, globalenv=globalenv, privileged=True),
|
||||
# A set of jobs based on the earlier .travis.yml configuration:
|
||||
linux_cxx("Default clang++ with libc++", "clang++-libc++", packages="libc++-dev", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "B2_TOOLSET": "clang-7", "B2_CXXSTD": "11", "VARIANT": "debug", "TOOLSET": "clang", "COMPILER": "clang++-libc++", "CXXSTD": "11", "CXX_FLAGS": "<cxxflags>-stdlib=libc++ <linkflags>-stdlib=libc++", "TRAVISCLANG" : "yes" }, globalenv=globalenv),
|
||||
linux_cxx("Default g++", "g++", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv),
|
||||
linux_cxx("Clang 3.8, UBasan", "clang++-3.8", packages="clang-3.8 libssl-dev", llvm_os="precise", llvm_ver="3.8", image="cppalliance/droneubuntu1604:1", buildtype="boost", buildscript="drone", environment={"VARIANT": "process_ubasan", "TOOLSET": "clang", "COMPILER": "clang++-3.8", "CXXSTD": "11", "UBSAN_OPTIONS": 'print_stacktrace=1', "DRONE_BEFORE_INSTALL": "UBasan" }, globalenv=globalenv),
|
||||
linux_cxx("gcc 6", "g++-6", packages="g++-6", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'B2_TOOLSET': 'gcc-6', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '902ba3cda1'}, globalenv=globalenv),
|
||||
linux_cxx("clang 3.8", "clang++-3.8", packages="clang-3.8", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu1604:1", environment={'B2_TOOLSET': 'clang', 'COMPILER': 'clang++-3.8', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '7b52009b64'}, globalenv=globalenv),
|
||||
osx_cxx("clang", "g++", packages="", buildtype="boost", buildscript="drone", environment={'B2_TOOLSET': 'clang', 'B2_CXXSTD': '11,17', 'DRONE_JOB_UUID': '91032ad7bb'}, globalenv=globalenv),
|
||||
linux_cxx("coverity", "g++", packages="", buildtype="coverity", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'Coverity Scan', 'B2_TOOLSET': 'clang', 'DRONE_JOB_UUID': '472b07b9fc'}, globalenv=globalenv),
|
||||
windows_cxx("msvc-14.1", "", image="cppalliance/dronevs2017", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "msvc-14.1", "CXXSTD": "11", "DEFINE" : "BOOST_BEAST_USE_STD_STRING_VIEW", "ADDRESS_MODEL": "64"}),
|
||||
windows_cxx("msvc-14.3", "", image="cppalliance/dronevs2022:1", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "msvc-14.3", "CXXSTD": "11", "DEFINE" : "BOOST_BEAST_USE_STD_STRING_VIEW", "ADDRESS_MODEL": "64"}),
|
||||
]
|
||||
|
||||
# from https://github.com/boostorg/boost-ci
|
||||
load("@boost_ci//ci/drone/:functions.star", "linux_cxx","windows_cxx","osx_cxx","freebsd_cxx")
|
||||
34
.drone/drone.bat
Executable file
34
.drone/drone.bat
Executable file
@@ -0,0 +1,34 @@
|
||||
@ECHO ON
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
if "%DRONE_JOB_BUILDTYPE%" == "boost" (
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
git clone https://github.com/boostorg/boost-ci.git boost-ci-cloned --depth 1
|
||||
cp -prf boost-ci-cloned/ci .
|
||||
rm -rf boost-ci-cloned
|
||||
|
||||
REM source ci/travis/install.sh
|
||||
REM The contents of install.sh below:
|
||||
|
||||
for /F %%i in ("%DRONE_REPO%") do @set SELF=%%~nxi
|
||||
SET BOOST_CI_TARGET_BRANCH=%DRONE_COMMIT_BRANCH%
|
||||
SET BOOST_CI_SRC_FOLDER=%cd%
|
||||
|
||||
call ci\common_install.bat
|
||||
|
||||
echo '==================================> COMPILE'
|
||||
|
||||
REM set B2_TARGETS=libs/!SELF!/test libs/!SELF!/example
|
||||
set B2_TARGETS=libs/!SELF!/test
|
||||
|
||||
cd !BOOST_ROOT!
|
||||
call bootstrap.bat
|
||||
b2 headers
|
||||
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/test libs/!SELF!/example -j3
|
||||
) else if "%DRONE_JOB_BUILDTYPE%" == "standalone-windows" (
|
||||
|
||||
REM not used
|
||||
|
||||
)
|
||||
199
.drone/drone.sh
Executable file
199
.drone/drone.sh
Executable file
@@ -0,0 +1,199 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2020 Rene Rivera, Sam Darwin
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set -xe
|
||||
|
||||
export TRAVIS_BUILD_DIR=$(pwd)
|
||||
export DRONE_BUILD_DIR=$(pwd)
|
||||
export TRAVIS_BRANCH=$DRONE_BRANCH
|
||||
export TRAVIS_EVENT_TYPE=$DRONE_BUILD_EVENT
|
||||
export VCS_COMMIT_ID=$DRONE_COMMIT
|
||||
export GIT_COMMIT=$DRONE_COMMIT
|
||||
export REPO_NAME=$DRONE_REPO
|
||||
export USER=$(whoami)
|
||||
export CC=${CC:-gcc}
|
||||
export PATH=~/.local/bin:/usr/local/bin:$PATH
|
||||
|
||||
common_install () {
|
||||
git clone https://github.com/boostorg/boost-ci.git boost-ci-cloned --depth 1
|
||||
cp -prf boost-ci-cloned/ci .
|
||||
rm -rf boost-ci-cloned
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
unset -f cd
|
||||
fi
|
||||
|
||||
export SELF=`basename $REPO_NAME`
|
||||
export BOOST_CI_TARGET_BRANCH="$TRAVIS_BRANCH"
|
||||
export BOOST_CI_SRC_FOLDER=$(pwd)
|
||||
|
||||
. ./ci/common_install.sh
|
||||
}
|
||||
|
||||
if [ "$DRONE_JOB_BUILDTYPE" == "boost" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
common_install
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
$BOOST_ROOT/libs/$SELF/ci/travis/build.sh
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "docs" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
export SELF=`basename $REPO_NAME`
|
||||
|
||||
pwd
|
||||
cd ..
|
||||
mkdir -p $HOME/cache && cd $HOME/cache
|
||||
if [ ! -d doxygen ]; then git clone -b 'Release_1_8_15' --depth 1 https://github.com/doxygen/doxygen.git && echo "not-cached" ; else echo "cached" ; fi
|
||||
cd doxygen
|
||||
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release
|
||||
cd build
|
||||
sudo make install
|
||||
cd ../..
|
||||
if [ ! -f saxonhe.zip ]; then wget -O saxonhe.zip https://sourceforge.net/projects/saxon/files/Saxon-HE/9.9/SaxonHE9-9-1-4J.zip/download && echo "not-cached" ; else echo "cached" ; fi
|
||||
unzip -o saxonhe.zip
|
||||
sudo rm /usr/share/java/Saxon-HE.jar
|
||||
sudo cp saxon9he.jar /usr/share/java/Saxon-HE.jar
|
||||
cd ..
|
||||
BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
git clone -b $BOOST_BRANCH https://github.com/boostorg/boost.git boost-root --depth 1
|
||||
cd boost-root
|
||||
export BOOST_ROOT=$(pwd)
|
||||
git submodule update --init libs/context
|
||||
git submodule update --init tools/boostbook
|
||||
git submodule update --init tools/boostdep
|
||||
git submodule update --init tools/docca
|
||||
git submodule update --init tools/quickbook
|
||||
rsync -av $TRAVIS_BUILD_DIR/ libs/$SELF
|
||||
python tools/boostdep/depinst/depinst.py ../tools/quickbook
|
||||
./bootstrap.sh
|
||||
./b2 headers
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
echo "using doxygen ; using boostbook ; using saxonhe ;" > tools/build/src/user-config.jam
|
||||
./b2 -j3 libs/$SELF/doc//boostrelease
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "codecov" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
common_install
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
cd $BOOST_ROOT/libs/$SELF
|
||||
ci/travis/codecov.sh
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "valgrind" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
common_install
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
cd $BOOST_ROOT/libs/$SELF
|
||||
ci/travis/valgrind.sh
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "standalone" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
# Installing cmake with apt-get, so not required here:
|
||||
# pip install --user cmake
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
export CXXFLAGS="-Wall -Wextra -Werror -std=c++17"
|
||||
mkdir __build_17
|
||||
cd __build_17
|
||||
cmake -DBOOST_JSON_STANDALONE=1 ..
|
||||
cmake --build .
|
||||
ctest -V .
|
||||
export CXXFLAGS="-Wall -Wextra -Werror -std=c++2a"
|
||||
mkdir ../__build_2a
|
||||
cd ../__build_2a
|
||||
cmake -DBOOST_JSON_STANDALONE=1 ..
|
||||
cmake --build .
|
||||
ctest -V .
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "coverity" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
common_install
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
if [ $VARIANT = "process_valgrind" ];
|
||||
then export USE_VALGRIND="testing.launcher=valgrind valgrind=on";
|
||||
fi ;
|
||||
|
||||
if [ -n "${COVERITY_SCAN_NOTIFICATION_EMAIL}" -a \( "$TRAVIS_BRANCH" = "develop" -o "$TRAVIS_BRANCH" = "master" \) -a \( "$DRONE_BUILD_EVENT" = "push" -o "$DRONE_BUILD_EVENT" = "cron" \) ] ; then
|
||||
cd $BOOST_ROOT/libs/$SELF
|
||||
ci/travis/coverity.sh
|
||||
fi
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "cmake-superproject" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
common_install
|
||||
|
||||
echo '==================================> COMPILE'
|
||||
|
||||
export CXXFLAGS="-Wall -Wextra -Werror"
|
||||
|
||||
mkdir __build_static
|
||||
cd __build_static
|
||||
cmake -DBOOST_ENABLE_CMAKE=1 -DBUILD_TESTING=ON -DBoost_VERBOSE=1 \
|
||||
-DBOOST_INCLUDE_LIBRARIES=$SELF ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure -R boost_$SELF
|
||||
|
||||
cd ..
|
||||
|
||||
mkdir __build_shared
|
||||
cd __build_shared
|
||||
cmake -DBOOST_ENABLE_CMAKE=1 -DBUILD_TESTING=ON -DBoost_VERBOSE=1 \
|
||||
-DBOOST_INCLUDE_LIBRARIES=$SELF -DBUILD_SHARED_LIBS=ON ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure -R boost_$SELF
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "cmake1" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
pip install --user cmake
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
export SELF=`basename $REPO_NAME`
|
||||
BOOST_BRANCH=develop && [ "$DRONE_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
mkdir -p libs/$SELF
|
||||
cp -r $DRONE_BUILD_DIR/* libs/$SELF
|
||||
# git submodule update --init tools/boostdep
|
||||
git submodule update --init --recursive
|
||||
|
||||
cd libs/$SELF
|
||||
|
||||
../../../b2 -sBOOST_BUILD_PATH=.
|
||||
../../../b2 $MULTITHREAD with-valgrind address-model=64 architecture=x86 $USE_VALGRIND toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
|
||||
../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
|
||||
|
||||
|
||||
|
||||
fi
|
||||
96
.gitattributes
vendored
Normal file
96
.gitattributes
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
* text=auto !eol svneol=native#text/plain
|
||||
*.gitattributes text svneol=native#text/plain
|
||||
|
||||
# Scriptish formats
|
||||
*.bat text svneol=native#text/plain
|
||||
*.bsh text svneol=native#text/x-beanshell
|
||||
*.cgi text svneol=native#text/plain
|
||||
*.cmd text svneol=native#text/plain
|
||||
*.js text svneol=native#text/javascript
|
||||
*.php text svneol=native#text/x-php
|
||||
*.pl text svneol=native#text/x-perl
|
||||
*.pm text svneol=native#text/x-perl
|
||||
*.py text svneol=native#text/x-python
|
||||
*.sh eol=lf svneol=LF#text/x-sh
|
||||
configure eol=lf svneol=LF#text/x-sh
|
||||
|
||||
# Image formats
|
||||
*.bmp binary svneol=unset#image/bmp
|
||||
*.gif binary svneol=unset#image/gif
|
||||
*.ico binary svneol=unset#image/ico
|
||||
*.jpeg binary svneol=unset#image/jpeg
|
||||
*.jpg binary svneol=unset#image/jpeg
|
||||
*.png binary svneol=unset#image/png
|
||||
*.tif binary svneol=unset#image/tiff
|
||||
*.tiff binary svneol=unset#image/tiff
|
||||
*.svg text svneol=native#image/svg%2Bxml
|
||||
|
||||
# Data formats
|
||||
*.pdf binary svneol=unset#application/pdf
|
||||
*.avi binary svneol=unset#video/avi
|
||||
*.doc binary svneol=unset#application/msword
|
||||
*.dsp text svneol=crlf#text/plain
|
||||
*.dsw text svneol=crlf#text/plain
|
||||
*.eps binary svneol=unset#application/postscript
|
||||
*.gz binary svneol=unset#application/gzip
|
||||
*.mov binary svneol=unset#video/quicktime
|
||||
*.mp3 binary svneol=unset#audio/mpeg
|
||||
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
|
||||
*.ps binary svneol=unset#application/postscript
|
||||
*.psd binary svneol=unset#application/photoshop
|
||||
*.rdf binary svneol=unset#text/rdf
|
||||
*.rss text svneol=unset#text/xml
|
||||
*.rtf binary svneol=unset#text/rtf
|
||||
*.sln text svneol=native#text/plain
|
||||
*.swf binary svneol=unset#application/x-shockwave-flash
|
||||
*.tgz binary svneol=unset#application/gzip
|
||||
*.vcproj text svneol=native#text/xml
|
||||
*.vcxproj text svneol=native#text/xml
|
||||
*.vsprops text svneol=native#text/xml
|
||||
*.wav binary svneol=unset#audio/wav
|
||||
*.xls binary svneol=unset#application/vnd.ms-excel
|
||||
*.zip binary svneol=unset#application/zip
|
||||
|
||||
# Text formats
|
||||
.htaccess text svneol=native#text/plain
|
||||
*.bbk text svneol=native#text/xml
|
||||
*.cmake text svneol=native#text/plain
|
||||
*.css text svneol=native#text/css
|
||||
*.dtd text svneol=native#text/xml
|
||||
*.htm text svneol=native#text/html
|
||||
*.html text svneol=native#text/html
|
||||
*.ini text svneol=native#text/plain
|
||||
*.log text svneol=native#text/plain
|
||||
*.mak text svneol=native#text/plain
|
||||
*.qbk text svneol=native#text/plain
|
||||
*.rst text svneol=native#text/plain
|
||||
*.sql text svneol=native#text/x-sql
|
||||
*.txt text svneol=native#text/plain
|
||||
*.xhtml text svneol=native#text/xhtml%2Bxml
|
||||
*.xml text svneol=native#text/xml
|
||||
*.xsd text svneol=native#text/xml
|
||||
*.xsl text svneol=native#text/xml
|
||||
*.xslt text svneol=native#text/xml
|
||||
*.xul text svneol=native#text/xul
|
||||
*.yml text svneol=native#text/plain
|
||||
boost-no-inspect text svneol=native#text/plain
|
||||
CHANGES text svneol=native#text/plain
|
||||
COPYING text svneol=native#text/plain
|
||||
INSTALL text svneol=native#text/plain
|
||||
Jamfile text svneol=native#text/plain
|
||||
Jamroot text svneol=native#text/plain
|
||||
Jamfile.v2 text svneol=native#text/plain
|
||||
Jamrules text svneol=native#text/plain
|
||||
Makefile* text svneol=native#text/plain
|
||||
README text svneol=native#text/plain
|
||||
TODO text svneol=native#text/plain
|
||||
|
||||
# Code formats
|
||||
*.c text svneol=native#text/plain
|
||||
*.cpp text svneol=native#text/plain
|
||||
*.h text svneol=native#text/plain
|
||||
*.hpp text svneol=native#text/plain
|
||||
*.ipp text svneol=native#text/plain
|
||||
*.tpp text svneol=native#text/plain
|
||||
*.jam text svneol=native#text/plain
|
||||
*.java text svneol=native#text/plain
|
||||
238
.github/workflows/ci.yml
vendored
Normal file
238
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- feature/**
|
||||
|
||||
env:
|
||||
UBSAN_OPTIONS: print_stacktrace=1
|
||||
|
||||
jobs:
|
||||
posix:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: gcc-5
|
||||
cxxstd: "11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
install: g++-5
|
||||
- toolset: gcc-6
|
||||
cxxstd: "11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
install: g++-6
|
||||
- toolset: gcc-7
|
||||
cxxstd: "11,14,17"
|
||||
os: ubuntu-18.04
|
||||
- toolset: gcc-10
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: g++-10
|
||||
- toolset: gcc-12
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: ubuntu-22.04
|
||||
install: g++-12
|
||||
- toolset: clang
|
||||
compiler: clang++-3.9
|
||||
cxxstd: "11,14"
|
||||
os: ubuntu-18.04
|
||||
install: clang-3.9
|
||||
- toolset: clang
|
||||
compiler: clang++-4.0
|
||||
cxxstd: "11,14"
|
||||
os: ubuntu-18.04
|
||||
install: clang-4.0
|
||||
- toolset: clang
|
||||
compiler: clang++-5.0
|
||||
cxxstd: "11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
install: clang-5.0
|
||||
- toolset: clang
|
||||
compiler: clang++-6.0
|
||||
cxxstd: "11,14,17"
|
||||
os: ubuntu-18.04
|
||||
install: clang-6.0
|
||||
- toolset: clang
|
||||
compiler: clang++-7
|
||||
cxxstd: "11,14,17"
|
||||
os: ubuntu-18.04
|
||||
install: clang-7
|
||||
- toolset: clang
|
||||
compiler: clang++-8
|
||||
cxxstd: "11,14,17"
|
||||
os: ubuntu-20.04
|
||||
install: clang-8
|
||||
- toolset: clang
|
||||
compiler: clang++-9
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: clang-9
|
||||
- toolset: clang
|
||||
compiler: clang++-10
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: clang-10
|
||||
- toolset: clang
|
||||
compiler: clang++-11
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: clang-11
|
||||
- toolset: clang
|
||||
compiler: clang++-12
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: clang-12
|
||||
- toolset: clang
|
||||
compiler: clang++-13
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: ubuntu-22.04
|
||||
install: clang-13
|
||||
- toolset: clang
|
||||
compiler: clang++-14
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: ubuntu-22.04
|
||||
install: clang-14
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: macos-11
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
- name: Create user-config.jam
|
||||
if: matrix.compiler
|
||||
run: |
|
||||
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release
|
||||
|
||||
alpine-linux:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: alpine:3.20.1
|
||||
steps:
|
||||
- name: Install packages
|
||||
run: apk add g++ git python3 linux-headers
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=gcc cxxstd=23 variant=debug,release
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: msvc-14.0
|
||||
cxxstd: "14,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.2
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.3
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
- toolset: clang-win
|
||||
cxxstd: "14,17,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
- toolset: gcc
|
||||
cxxstd: "11,14,17,2a"
|
||||
addrmd: 64
|
||||
os: windows-2019
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
cmd /c bootstrap
|
||||
b2 -d0 headers
|
||||
|
||||
- name: Run tests
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,4 +31,5 @@
|
||||
/notes.cpp
|
||||
/notes_p.txt
|
||||
.settings
|
||||
.DS_Store
|
||||
|
||||
|
||||
184
.travis.yml
184
.travis.yml
@@ -10,28 +10,6 @@
|
||||
#
|
||||
# File revision #6
|
||||
|
||||
env:
|
||||
global:
|
||||
# Autodetect Boost branch by using the following code: - BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE=''
|
||||
|
||||
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# By default is eaual to - BOOST_REMOVE=`basename $TRAVIS_BUILD_DIR`
|
||||
# This will force to use local repo content, instead of the Boost's default
|
||||
# not needed because process is not yet in boost.
|
||||
#- BOOST_REMOVE=process
|
||||
|
||||
matrix:
|
||||
- CXX_STANDARD=c++11 TOOLSET=gcc-5
|
||||
- CXX_STANDARD=c++1y TOOLSET=gcc-5
|
||||
|
||||
|
||||
###############################################################################################################
|
||||
# From this point and below code is same for all the Boost libs
|
||||
@@ -39,80 +17,120 @@ env:
|
||||
sudo: false
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
- gcc
|
||||
|
||||
os:
|
||||
- linux
|
||||
- linux
|
||||
- osx
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BADGE=linux
|
||||
- BADGE=osx
|
||||
global:
|
||||
# Autodetect Boost branch by using the following code: - BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE=''
|
||||
|
||||
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# By default is eaual to - BOOST_REMOVE=`basename $TRAVIS_BUILD_DIR`
|
||||
# This will force to use local repo content, instead of the Boost's default
|
||||
# not needed because process is not yet in boost.
|
||||
- BOOST_REMOVE=process
|
||||
- CXX_STANDARD=gnu++11
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: linux
|
||||
env: BADGE=osx
|
||||
- os: osx
|
||||
env: BADGE=linux
|
||||
|
||||
|
||||
|
||||
# Installing additional tools
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- valgrind
|
||||
- python-yaml
|
||||
- gcc-5
|
||||
- g++-5
|
||||
# - lcov
|
||||
- clang
|
||||
- valgrind
|
||||
- python-yaml
|
||||
- gcc-5
|
||||
- g++-5
|
||||
# - lcov
|
||||
- clang
|
||||
|
||||
before_install:
|
||||
# Set this to the name of the library
|
||||
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
|
||||
- echo "Testing $PROJECT_TO_TEST"
|
||||
# Cloning Boost libraries (fast nondeep cloning)
|
||||
- BOOST=$HOME/boost-local
|
||||
- git init $BOOST
|
||||
- cd $BOOST
|
||||
- if [ $(BRANCH_TO_TEST) = "master" ]; then
|
||||
BOOST_BRANCH=master;
|
||||
else BOOST_BRANCH=develop; fi
|
||||
- git remote add --no-tags -t $BOOST_BRANCH origin https://github.com/boostorg/boost.git
|
||||
- git fetch --depth=1
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule update --init --merge
|
||||
- git remote set-branches --add origin $BOOST_BRANCH
|
||||
- git pull --recurse-submodules
|
||||
- git submodule update --init
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
|
||||
- git reset --hard; git clean -fxd
|
||||
- git status
|
||||
# - rm -rf $BOOST/libs/$BOOST_REMOVE
|
||||
- mv $TRAVIS_BUILD_DIR/../$PROJECT_TO_TEST/ $BOOST/libs/$PROJECT_TO_TEST
|
||||
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
|
||||
- ./bootstrap.sh
|
||||
- ./b2 headers
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test
|
||||
|
||||
# Set this to the name of the library
|
||||
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
|
||||
- echo "Testing $PROJECT_TO_TEST"
|
||||
- if [ $TRAVIS_OS_NAME = "osx" ]; then brew install gcc5; brew install valgrind; brew install llvm; TOOLSET=clang; BOOST_TEST_CATCH_SYSTEM_ERRORS=no; MULTITHREAD=-j8; else TOOLSET=gcc-5; REPORT_CI=--boost-process-report-ci USE_VALGRIND="testing.launcher=valgrind valgrind=on"; fi
|
||||
# Cloning Boost libraries (fast nondeep cloning)
|
||||
- BOOST=$HOME/boost-local
|
||||
- git init $BOOST
|
||||
- cd $BOOST
|
||||
- echo Branch to test $BRANCH_TO_TEST
|
||||
- if [ $BRANCH_TO_TEST = "master" ]; then
|
||||
BOOST_BRANCH=master;
|
||||
else BOOST_BRANCH=develop; fi
|
||||
- git remote add --no-tags -t $BOOST_BRANCH origin https://github.com/boostorg/boost.git
|
||||
- git fetch --depth=1
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule update --init --merge
|
||||
- git remote set-branches --add origin $BOOST_BRANCH
|
||||
- git pull --recurse-submodules || true
|
||||
- git submodule update --init
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
|
||||
- git reset --hard; git clean -fxd
|
||||
- git status
|
||||
- echo "Removing $BOOST/libs/$BOOST_REMOVE"
|
||||
- rm -rf $BOOST/libs/$BOOST_REMOVE
|
||||
- mv $TRAVIS_BUILD_DIR/../$PROJECT_TO_TEST/ $BOOST/libs/$PROJECT_TO_TEST
|
||||
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
|
||||
- ./bootstrap.sh
|
||||
- ./b2 headers
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test
|
||||
- echo BOOST_TEST_CATCH_SYSTEM_ERRORS $BOOST_TEST_CATCH_SYSTEM_ERRORS
|
||||
script:
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
- ../../../b2 testing.launcher=valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
|
||||
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
- ../../../b2 $MULTITHREAD with-valgrind address-model=64 architecture=x86 $USE_VALGRIND toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
|
||||
- ../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
|
||||
after_success:
|
||||
# Copying Coveralls data to a separate folder
|
||||
- mkdir -p $TRAVIS_BUILD_DIR/coverals
|
||||
- find ../../../bin.v2/ -name "*.gcda" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
- find ../../../bin.v2/ -name "*.gcno" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
# Copying Coveralls data to a separate folder
|
||||
- mkdir -p $TRAVIS_BUILD_DIR/coverals
|
||||
- find ../../../bin.v2/ -name "*.gcda" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
- find ../../../bin.v2/ -name "*.gcno" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
|
||||
# Preparing Coveralls data by changind data format to a readable one
|
||||
- git clone https://github.com/linux-test-project/lcov.git lcov_dir
|
||||
- GCOV_VERSION=""
|
||||
- if [[ "$TOOLSET" == *"-"* ]]; then GCOV_VERSION="--gcov-tool gcov-${TOOLSET#*-}"; fi
|
||||
- LCOV="$BOOST/libs/$PROJECT_TO_TEST/test/lcov_dir/bin/lcov $GCOV_VERSION"
|
||||
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory ./ --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
# Preparing Coveralls data by changind data format to a readable one
|
||||
- git clone https://github.com/linux-test-project/lcov.git lcov_dir
|
||||
- GCOV_VERSION=""
|
||||
- if [[ "$TOOLSET" == *"-"* ]]; then GCOV_VERSION="--gcov-tool gcov-${TOOLSET#*-}"; fi
|
||||
- LCOV="$BOOST/libs/$PROJECT_TO_TEST/test/lcov_dir/bin/lcov $GCOV_VERSION"
|
||||
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory ./ --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
|
||||
# ... erasing /test/ /example/ folder data
|
||||
- cd $BOOST
|
||||
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$PROJECT_TO_TEST/test/*" $IGNORE_COVERAGE "*/$PROJECT_TO_TEST/tests/*" "*/$PROJECT_TO_TEST/examples/*" "*/$PROJECT_TO_TEST/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
# ... erasing /test/ /example/ folder data
|
||||
- cd $BOOST
|
||||
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "*.cpp" "/usr*" "*/$PROJECT_TO_TEST/test/*" $IGNORE_COVERAGE "*/$PROJECT_TO_TEST/tests/*" "*/$PROJECT_TO_TEST/examples/*" "*/$PROJECT_TO_TEST/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
|
||||
# ... erasing data that is not related to this project directly
|
||||
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$PROJECT_TO_TEST\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
|
||||
- echo $OTHER_LIBS
|
||||
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info"
|
||||
# ... erasing data that is not related to this project directly
|
||||
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/process\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
|
||||
- echo $OTHER_LIBS
|
||||
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info" > /dev/null
|
||||
|
||||
# Sending data to Coveralls
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- gem install coveralls-lcov
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
# Sending data to Coveralls
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- gem install coveralls-lcov
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
|
||||
after_script:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test
|
||||
- curl -s https://report.ci/report.py | python - --name="$BADGE test run"
|
||||
|
||||
72
CMakeLists.txt
Normal file
72
CMakeLists.txt
Normal file
@@ -0,0 +1,72 @@
|
||||
# Generated by `boostdep --cmake process`
|
||||
# Copyright 2020 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.16)
|
||||
|
||||
project(boost_process VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_process
|
||||
src/detail/environment_posix.cpp
|
||||
src/detail/environment_win.cpp
|
||||
src/detail/last_error.cpp
|
||||
src/detail/process_handle_windows.cpp
|
||||
src/detail/throw_error.cpp
|
||||
src/detail/utf8.cpp
|
||||
src/ext/cmd.cpp
|
||||
src/ext/cwd.cpp
|
||||
src/ext/env.cpp
|
||||
src/ext/exe.cpp
|
||||
src/ext/proc_info.cpp
|
||||
src/posix/close_handles.cpp
|
||||
src/windows/default_launcher.cpp
|
||||
src/environment.cpp
|
||||
src/error.cpp
|
||||
src/pid.cpp
|
||||
src/shell.cpp)
|
||||
|
||||
add_library(Boost::process ALIAS boost_process)
|
||||
|
||||
target_include_directories(boost_process PUBLIC include)
|
||||
target_link_libraries(boost_process
|
||||
PUBLIC
|
||||
Boost::algorithm
|
||||
Boost::asio
|
||||
Boost::config
|
||||
Boost::core
|
||||
Boost::filesystem
|
||||
Boost::fusion
|
||||
Boost::iterator
|
||||
Boost::move
|
||||
Boost::optional
|
||||
Boost::system
|
||||
Boost::tokenizer
|
||||
Boost::type_index
|
||||
Boost::winapi
|
||||
)
|
||||
|
||||
target_compile_definitions(boost_process
|
||||
PRIVATE BOOST_PROCESS_SOURCE=1
|
||||
)
|
||||
|
||||
if (BOOST_PROCESS_USE_STD_FS)
|
||||
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_USE_STD_FS=1 )
|
||||
else()
|
||||
target_link_libraries(boost_process PUBLIC Boost::filesystem)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(boost_process PUBLIC ntdll shell32 advapi32 user32)
|
||||
endif()
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_DYN_LINK)
|
||||
else()
|
||||
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_STATIC_LINK)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
22
README.md
22
README.md
@@ -1,17 +1,21 @@
|
||||
#[Boost Process (Boost.Process)](https://github.com/klemens-morgenstern/boost-process)
|
||||
# [Boost Process (Boost.Process)](https://github.com/boostorg/process)
|
||||
|
||||
Boost.process is not yet part of the [Boost C++ Libraries](http://github.com/boostorg). It is a library for comfortable management of processes.
|
||||
Boost.process is a library for comfortable management of processes, released with boost 1.64.0.
|
||||
|
||||
### Test results
|
||||
|
||||
Branches | Build | Tests coverage |
|
||||
----------------|-------------- | -------------- |
|
||||
Develop: | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://ci.appveyor.com/project/klemens-morgenstern/boost-process) | [](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=develop) |
|
||||
Master: | [] (https://travis-ci.org/klemens-morgenstern/boost-process) [](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) | [](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) |
|
||||
| Branches | Linux / Windows | Code coverage | Matrix |
|
||||
|----------|----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Develop: | [](https://drone.cpp.al/boostorg/process) | [](https://codecov.io/gh/boostorg/process) | [](http://www.boost.org/development/tests/develop/developer/process.html) |
|
||||
| Master: | [](https://drone.cpp.al/boostorg/process) | [](https://codecov.io/gh/boostorg/process) | [](http://www.boost.org/development/tests/master/developer/process.html) |
|
||||
|
||||
[Open Issues](https://github.com/klemens-morgenstern/boost-process/issues)
|
||||
|
||||
[Latest developer documentation](http://klemens-morgenstern.github.io/process/)
|
||||
|
||||
|
||||
|
||||
[Open Issues](https://github.com/boostorg/process/issues)
|
||||
|
||||
[Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/process.html)
|
||||
|
||||
### About
|
||||
This C++11 library is the current result of a long attempt to get a boost.process library, which is going on since 2006.
|
||||
@@ -21,4 +25,4 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org
|
||||
|
||||
### Dependency
|
||||
|
||||
This library requires boost 1.63. Since this is not released yet you can clone the winapi module from [here](https://github.com/boostorg/winapi) to get it to work. You will need to overwrite the current code in boost/libs/winapi.
|
||||
This library requires boost 1.64 with which it is released.
|
||||
|
||||
47
build.jam
Normal file
47
build.jam
Normal file
@@ -0,0 +1,47 @@
|
||||
# Copyright René Ferdinand Rivera Morell 2024
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
require-b2 5.2 ;
|
||||
|
||||
import feature : feature ;
|
||||
|
||||
feature boost.process.fs : boost std : optional propagated ;
|
||||
feature boost.process.disable-close-range : on off : optional ;
|
||||
|
||||
constant boost_dependencies :
|
||||
/boost/algorithm//boost_algorithm
|
||||
/boost/asio//boost_asio
|
||||
/boost/assert//boost_assert
|
||||
/boost/config//boost_config
|
||||
/boost/core//boost_core
|
||||
/boost/fusion//boost_fusion
|
||||
/boost/io//boost_io
|
||||
/boost/iterator//boost_iterator
|
||||
/boost/move//boost_move
|
||||
/boost/optional//boost_optional
|
||||
/boost/system//boost_system
|
||||
/boost/throw_exception//boost_throw_exception
|
||||
/boost/tokenizer//boost_tokenizer
|
||||
/boost/type_index//boost_type_index
|
||||
/boost/type_traits//boost_type_traits
|
||||
/boost/utility//boost_utility
|
||||
/boost/winapi//boost_winapi ;
|
||||
|
||||
project /boost/process
|
||||
: common-requirements
|
||||
<include>include
|
||||
: default-build
|
||||
<boost.process.fs>boost
|
||||
;
|
||||
|
||||
explicit
|
||||
[ alias boost_process : build//boost_process ]
|
||||
[ alias all : boost_process example example/v2 test ]
|
||||
;
|
||||
|
||||
call-if : boost-library process
|
||||
: install boost_process
|
||||
;
|
||||
|
||||
73
build/Jamfile
Normal file
73
build/Jamfile
Normal file
@@ -0,0 +1,73 @@
|
||||
# Copyright (c) 2024 Klemens D. Morgenstern
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import os ;
|
||||
import feature ;
|
||||
import-search /boost/config/checks ;
|
||||
import config : requires ;
|
||||
|
||||
project : requirements
|
||||
<define>BOOST_ASIO_NO_DEPRECATED
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
|
||||
<toolset>msvc:<cxxflags>/bigobj
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<target-os>linux:<linkflags>-lpthread
|
||||
: source-location ../src
|
||||
: common-requirements
|
||||
<library>$(boost_dependencies)
|
||||
<boost.process.fs>std:<define>BOOST_PROCESS_USE_STD_FS=1
|
||||
;
|
||||
|
||||
alias process_sources
|
||||
: detail/environment_posix.cpp
|
||||
detail/environment_win.cpp
|
||||
detail/last_error.cpp
|
||||
detail/process_handle_windows.cpp
|
||||
detail/throw_error.cpp
|
||||
detail/utf8.cpp
|
||||
ext/cmd.cpp
|
||||
ext/cwd.cpp
|
||||
ext/env.cpp
|
||||
ext/exe.cpp
|
||||
ext/proc_info.cpp
|
||||
posix/close_handles.cpp
|
||||
windows/default_launcher.cpp
|
||||
environment.cpp
|
||||
error.cpp
|
||||
pid.cpp
|
||||
shell.cpp
|
||||
;
|
||||
|
||||
lib shell32 ;
|
||||
lib advapi32 ;
|
||||
lib ntdll ;
|
||||
lib user32 ;
|
||||
lib ws2_32 ;
|
||||
|
||||
lib kvm ;
|
||||
lib procstat ;
|
||||
|
||||
lib boost_process
|
||||
: process_sources
|
||||
: requirements <define>BOOST_PROCESS_SOURCE=1
|
||||
<link>shared:<define>BOOST_PROCESS_DYN_LINK=1
|
||||
<boost.process.fs>boost:<library>/boost/filesystem//boost_filesystem
|
||||
<boost.process.disable-close-range>on:<define>BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE=1
|
||||
<target-os>windows:<library>shell32
|
||||
<target-os>windows:<library>user32
|
||||
<target-os>windows:<library>ntdll
|
||||
<target-os>windows:<library>advapi32
|
||||
<target-os>windows:<library>ws2_32
|
||||
<target-os>bsd:<library>kvm
|
||||
<target-os>freebsd:<library>kvm
|
||||
<target-os>freebsd:<library>procstat
|
||||
<target-os>netbsd:<library>kvm
|
||||
<target-os>openbsd:<library>kvm
|
||||
<target-os>solaris:<library>kvm
|
||||
: usage-requirements
|
||||
<link>shared:<define>BOOST_PROCESS_DYN_LINK=1
|
||||
<boost.process.fs>boost:<library>/boost/filesystem//boost_filesystem
|
||||
;
|
||||
@@ -11,21 +11,96 @@ using boostbook ;
|
||||
using quickbook ;
|
||||
using doxygen ;
|
||||
|
||||
doxygen autodoc
|
||||
|
||||
local images = [ glob images/*.svg ] ;
|
||||
install images : $(images) : <location>html/boost_process ;
|
||||
install images_glob : $(images) : <location>$(BOOST_ROOT)/doc/html/boost_process ;
|
||||
|
||||
import type ;
|
||||
type.register XMLPROCESSWORKAROUND : : XML ;
|
||||
import generators ;
|
||||
generators.register-standard common.copy : XML : XMLPROCESSWORKAROUND ;
|
||||
|
||||
xmlprocessworkaround posix_pseudocode : v1/posix_pseudocode.xml ;
|
||||
xmlprocessworkaround windows_pseudocode : v1/windows_pseudocode.xml ;
|
||||
|
||||
path-constant INCLUDES : ../include ;
|
||||
|
||||
doxygen reference_v1
|
||||
:
|
||||
../../../boost/process.hpp
|
||||
[ glob ../../../boost/process/*.hpp ]
|
||||
:
|
||||
<doxygen:param>PREDEFINED=BOOST_PROCESS_DOXYGEN
|
||||
$(INCLUDES)/boost/process/v1.hpp
|
||||
[ glob $(INCLUDES)/boost/process/v1/*.hpp ]
|
||||
:
|
||||
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
|
||||
<doxygen:param>"PREDEFINED=\\
|
||||
BOOST_PROCESS_DOXYGEN=1 \\
|
||||
BOOST_PROCESS_V1_INLINE=
|
||||
"
|
||||
<doxygen:param>HIDE_UNDOC_CLASSES=YES
|
||||
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
|
||||
<doxygen:param>EXAMPLE_PATH=.
|
||||
<dependency>posix_pseudocode
|
||||
<dependency>windows_pseudocode
|
||||
<xsl:path>.
|
||||
;
|
||||
|
||||
|
||||
|
||||
doxygen reference_v2
|
||||
:
|
||||
$(INCLUDES)/boost/process/v2.hpp
|
||||
[ glob $(INCLUDES)/boost/process/v2/*.hpp ]
|
||||
:
|
||||
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
|
||||
<doxygen:param>PROJECT_NAME="Process V2"
|
||||
<doxygen:param>PROJECT_BRIEF="The process library"
|
||||
<doxygen:param>MACRO_EXPANSION=YES
|
||||
<doxygen:param>EXPAND_ONLY_PREDEF=YES
|
||||
<doxygen:param>"PREDEFINED=\\
|
||||
GENERATING_DOCUMENTATION=1 \\
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE=boost::asio \\
|
||||
\"BOOST_PROCESS_V2_BEGIN_NAMESPACE=namespace boost { namespace process { namespace v2 { \" \\
|
||||
\"BOOST_PROCESS_V2_END_NAMESPACE= } } }\" \\
|
||||
BOOST_PROCESS_V2_NAMESPACE=boost::process::v2 \\
|
||||
BOOST_PROCESS_V2_DECL \\
|
||||
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(x,y)=deduced \\
|
||||
BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(X)=Token \\
|
||||
BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(E)=DEFAULT_TYPE \\
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN=DEFAULT \\
|
||||
BOOST_CONSTEXPR=constexpr \\
|
||||
BOOST_CXX14_CONSTEXPR=constexpr \\
|
||||
BOOST_PROCESS_V2_INLINE= \\
|
||||
BOOST_ATTRIBUTE_NODISCARD=[[nodiscard]]
|
||||
"
|
||||
<doxygen.doxproc.id>reference_v2
|
||||
<doxygen:param>SHOW_USED_FILES=NO
|
||||
<doxygen:param>SHOW_FILES=NO
|
||||
<doxygen:param>SHOW_NAMESPACES=YES
|
||||
<doxygen:param>CLASS_DIAGRAMS=NO
|
||||
<doxygen:param>SORT_MEMBERS_CTORS_1ST=YES
|
||||
<doxygen:param>HIDE_UNDOC_CLASSES=NO
|
||||
<xsl:path>.
|
||||
;
|
||||
|
||||
|
||||
boostbook standalone
|
||||
:
|
||||
process.qbk
|
||||
:
|
||||
<dependency>autodoc
|
||||
<dependency>reference_v1
|
||||
<dependency>reference_v2
|
||||
<dependency>images
|
||||
<dependency>images_glob
|
||||
<xsl:param>boost.root=../../../..
|
||||
<xsl:param>html.stylesheet=../../../../doc/src/boostbook.css
|
||||
;
|
||||
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: standalone/<format>docbook
|
||||
:
|
||||
: <dependency>images_glob
|
||||
: ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease ;
|
||||
explicit boostrelease ;
|
||||
@@ -8,4 +8,6 @@ A special thank you goes to [@http://www.intra2net.com/ Intra2net AG] (especiall
|
||||
|
||||
Great thanks also goes to Boris Schaeling, who despite having boost.process rejected, went on to work on it and maintained it up until this day and participated in the development of the current version.
|
||||
|
||||
Many Thanks, to [@https://github.com/time-killer-games Samuel Venable] for contributing the v2::ext functionality and all the research that went into it.
|
||||
|
||||
[endsect]
|
||||
|
||||
118
doc/images/plantuml.txt
Normal file
118
doc/images/plantuml.txt
Normal file
@@ -0,0 +1,118 @@
|
||||
Plantuml source file (for later edit)
|
||||
// Style
|
||||
|
||||
skinparam backgroundColor #FFFFFF
|
||||
|
||||
skinparam sequence {
|
||||
ActorBorderColor DeepSkyBlue
|
||||
ArrowColor #4a6484
|
||||
|
||||
LifeLineBorderColor #4a6484
|
||||
ParticipantBackgroundColor #91c6ff
|
||||
ParticipantBorderColor black
|
||||
BoxBorderColor black
|
||||
}
|
||||
|
||||
|
||||
//posix no error
|
||||
/**
|
||||
\plantuml
|
||||
activate Father
|
||||
|
||||
box "Child Process" #LightGrey
|
||||
participant Child
|
||||
participant Exe
|
||||
end box
|
||||
|
||||
Father->Father : on_setup
|
||||
activate Father
|
||||
deactivate Father
|
||||
Father->Child : fork
|
||||
activate Child
|
||||
Father -> Father : wait for error
|
||||
deactivate Father
|
||||
|
||||
|
||||
Child->Child : on_exec_setup
|
||||
activate Child
|
||||
deactivate Child
|
||||
Child->Exe : execve
|
||||
deactivate Child
|
||||
activate Father
|
||||
activate Exe
|
||||
|
||||
Father -> Father : on_success
|
||||
activate Father
|
||||
deactivate Father
|
||||
|
||||
\endplantuml */
|
||||
|
||||
//posix exec error
|
||||
/**
|
||||
\plantuml
|
||||
activate Father
|
||||
|
||||
Father->Father : on_setup
|
||||
activate Father
|
||||
deactivate Father
|
||||
Father->Child : fork
|
||||
activate Child
|
||||
Father -> Father : wait for error
|
||||
deactivate Father
|
||||
|
||||
Child->Child : on_exec_setup
|
||||
activate Child
|
||||
deactivate Child
|
||||
Child->Child : execve
|
||||
Child->Child : on_exec_error
|
||||
activate Child
|
||||
deactivate Child
|
||||
Child->Father : report
|
||||
deactivate Child
|
||||
activate Father
|
||||
Father -> Father : on_error
|
||||
activate Father
|
||||
deactivate Father
|
||||
\endplantuml
|
||||
|
||||
//posix fork error
|
||||
\plantuml
|
||||
activate Father
|
||||
|
||||
Father->Father : on_setup
|
||||
activate Father
|
||||
deactivate Father
|
||||
Father->Father : fork
|
||||
Father -> Father : on_fork_error
|
||||
activate Father
|
||||
deactivate Father
|
||||
Father -> Father : on_error
|
||||
activate Father
|
||||
deactivate Father
|
||||
\endplantuml
|
||||
|
||||
|
||||
//windows.
|
||||
\plantuml
|
||||
activate Father
|
||||
|
||||
Father->Father : on_setup
|
||||
activate Father
|
||||
deactivate Father
|
||||
Father->Child : CreateProcess
|
||||
activate Child
|
||||
|
||||
alt Successful Launch
|
||||
|
||||
Father -> Father : on_success
|
||||
activate Father
|
||||
deactivate Father
|
||||
|
||||
else Error during launch
|
||||
|
||||
Father -> Father : on_error
|
||||
activate Father
|
||||
deactivate Father
|
||||
|
||||
end
|
||||
\endplantuml
|
||||
1
doc/images/posix_exec_err.svg
Normal file
1
doc/images/posix_exec_err.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.9 KiB |
1
doc/images/posix_fork_err.svg
Normal file
1
doc/images/posix_fork_err.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="355px" preserveAspectRatio="none" style="width:142px;height:355px;" version="1.1" viewBox="0 0 142 355" width="142px" zoomAndPan="magnify"><defs><filter height="300%" id="f7wjnsf" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="259.5313" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="34" y="48.2969"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="77.2969"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="191.5625"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="263.6953"/><line style="stroke: #4A6484; stroke-width: 1.0; stroke-dasharray: 5.0,5.0;" x1="39" x2="39" y1="38.2969" y2="316.8281"/><rect fill="#91C6FF" filter="url(#f7wjnsf)" height="30.2969" style="stroke: #000000; stroke-width: 1.5;" width="58" x="8" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="44" x="15" y="22.9951">Father</text><rect fill="#91C6FF" filter="url(#f7wjnsf)" height="30.2969" style="stroke: #000000; stroke-width: 1.5;" width="58" x="8" y="315.8281"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="44" x="15" y="335.8232">Father</text><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="259.5313" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="34" y="48.2969"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="77.2969"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="191.5625"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="263.6953"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="49" x2="91" y1="69.4297" y2="69.4297"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="91" x2="91" y1="69.4297" y2="82.4297"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="50" x2="91" y1="82.4297" y2="82.4297"/><polygon fill="#4A6484" points="60,78.4297,50,82.4297,60,86.4297,56,82.4297" style="stroke: #4A6484; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="59" x="56" y="64.3638">on_setup</text><line style="stroke: #4A6484; stroke-width: 1.0;" x1="44" x2="86" y1="141.5625" y2="141.5625"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="86" x2="86" y1="141.5625" y2="154.5625"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="45" x2="86" y1="154.5625" y2="154.5625"/><polygon fill="#4A6484" points="55,150.5625,45,154.5625,55,158.5625,51,154.5625" style="stroke: #4A6484; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="24" x="51" y="136.4966">fork</text><line style="stroke: #4A6484; stroke-width: 1.0;" x1="49" x2="91" y1="183.6953" y2="183.6953"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="91" x2="91" y1="183.6953" y2="196.6953"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="50" x2="91" y1="196.6953" y2="196.6953"/><polygon fill="#4A6484" points="60,192.6953,50,196.6953,60,200.6953,56,196.6953" style="stroke: #4A6484; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="85" x="56" y="178.6294">on_fork_error</text><line style="stroke: #4A6484; stroke-width: 1.0;" x1="49" x2="91" y1="255.8281" y2="255.8281"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="91" x2="91" y1="255.8281" y2="268.8281"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="50" x2="91" y1="268.8281" y2="268.8281"/><polygon fill="#4A6484" points="60,264.8281,50,268.8281,60,272.8281,56,268.8281" style="stroke: #4A6484; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="54" x="56" y="250.7622">on_error</text></g></svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
1
doc/images/posix_success.svg
Normal file
1
doc/images/posix_success.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.7 KiB |
1
doc/images/windows_exec.svg
Normal file
1
doc/images/windows_exec.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.5 KiB |
@@ -1,24 +0,0 @@
|
||||
[section:introduction Introduction]
|
||||
|
||||
Boost.Process is a library to manage system processes. It can be used to:
|
||||
|
||||
* create child processes
|
||||
* setup streams for child processes
|
||||
* communicate with child processes through streams (synchronously or asynchronously)
|
||||
* wait for processes to exit (synchronously or asynchronously)
|
||||
* terminate processes
|
||||
|
||||
Here's a simple example of how to start a program with Boost.Process:
|
||||
|
||||
[def ipstream [classref boost::process::ipstream ipstream]]
|
||||
[def system [funcref boost::process::system system]]
|
||||
[def std_out [globalref boost::process::std_out std_out]]
|
||||
[def boost/process.hpp [headerref boost/process.hpp boost/process.hpp]]
|
||||
|
||||
|
||||
[import ../example/intro.cpp]
|
||||
[intro]
|
||||
|
||||
[caution This is not yet an official Boost C++ library. It wasn't reviewed and can't be downloaded from [@http://www.boost.org/ www.boost.org]. It is however the latest version of an ongoing effort to create a process management library for Boost. For now the library can be downloaded or cloned from here [@https://github.com/klemens-morgenstern/boost-process/tree/develop https://github.com/klemens-morgenstern/boost-process/tree/develop].]
|
||||
|
||||
[endsect]
|
||||
@@ -11,9 +11,8 @@
|
||||
]
|
||||
]
|
||||
|
||||
[include introduction.qbk]
|
||||
[include tutorial.qbk]
|
||||
[include design.qbk]
|
||||
[include faq.qbk]
|
||||
[xinclude autodoc.xml]
|
||||
[note Process v1 will be deprecated in the future. Use v2 for new projects.]
|
||||
|
||||
[include v1.qbk]
|
||||
[include v2.qbk]
|
||||
[include acknowledgements.qbk]
|
||||
|
||||
431
doc/tutorial.qbk
431
doc/tutorial.qbk
@@ -1,431 +0,0 @@
|
||||
[def bp::system [funcref boost::process::system bp::system]]
|
||||
[def bp::spawn [funcref boost::process::system bp::spawn]]
|
||||
[def bp::child [classref boost::process::child bp::child]]
|
||||
[def bp::group [classref boost::process::group bp::group]]
|
||||
[def bp::ipstream [classref boost::process::ipstream bp::ipstream]]
|
||||
[def bp::opstream [classref boost::process::opstream bp::opstream]]
|
||||
[def bp::pstream [classref boost::process::pstream bp::pstream]]
|
||||
[def bp::pipe [classref boost::process::pipe bp::pipe]]
|
||||
[def boost_org [@www.boost.org "www.boost.org"]]
|
||||
[def std::system [@http://en.cppreference.com/w/cpp/utility/program/system std::system]]
|
||||
[def child_running [memberref boost::process::child::running running]]
|
||||
[def child_wait [memberref boost::process::child::wait wait]]
|
||||
[def child_exit_code [memberref boost::process::child::exit_code exit_code]]
|
||||
[def bp::on_exit [globalref boost::process::on_exit bp::on_exit]]
|
||||
[def bp::null [globalref boost::process::null bp::null]]
|
||||
[def child_terminate [memberref boost::process::child::terminate terminate]]
|
||||
[def group_terminate [memberref boost::process::group::terminate terminate]]
|
||||
[def bp::std_in [globalref boost::process::std_in bp::std_in]]
|
||||
[def bp::std_out [globalref boost::process::std_out bp::std_out]]
|
||||
[def bp::std_err [globalref boost::process::std_err bp::std_err]]
|
||||
[def io_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]]
|
||||
[def asio_buffer [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html boost::asio::buffer]]
|
||||
[def asio_async_read [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_read.html boost::asio::async_read]]
|
||||
[def bp::environment [classref boost::process::basic_environment bp::environment]]
|
||||
[def bp::native_environment [classref boost::process::basic_native_environment bp::native_environment]]
|
||||
[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]]
|
||||
|
||||
|
||||
[def __wait_for__ [memberref boost::process::child::wait_for wait_for]]
|
||||
[def __wait_until__ [memberref boost::process::child::wait_until wait_until]]
|
||||
[def __detach__ [memberref boost::process::child::detach detach]]
|
||||
|
||||
|
||||
[def __reference__ [link process.reference reference]]
|
||||
|
||||
[def boost::asio::yield_context [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/yield_context.html boost::asio::yield_context]]
|
||||
[def boost::asio::coroutine [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/coroutine.html boost::asio::coroutine]]
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
In this section we will go step by step through the different features of
|
||||
boost.process. For a full description see the __reference__.
|
||||
|
||||
[section Starting a process]
|
||||
|
||||
We want to start a process, so let's start with a simple process. We will
|
||||
invoke the gcc compiler to compile a simple program.
|
||||
|
||||
With the standard library this looks like this.
|
||||
|
||||
```
|
||||
int result = std::system("g++ main.cpp");
|
||||
```
|
||||
|
||||
Which we can write exactly like this in boost.process.
|
||||
|
||||
```
|
||||
namespace bp = boost::process; //we will assume this for all further examples
|
||||
int result = bp::system("g++ main.cpp");
|
||||
```
|
||||
|
||||
The first thing we can do, is to separate the command and the executable into
|
||||
two parts, so it is more readable and can be built by a function.
|
||||
|
||||
```
|
||||
int result = bp::system("g++", "main.cpp");
|
||||
```
|
||||
|
||||
With that sytax we still have "g++" hard-coded, so let's assume we get the string
|
||||
from an external source as `boost::filesystem::path`, we can do this too.
|
||||
|
||||
```
|
||||
boost::filesystem::path p = "g++"; //or get it from somewhere else.
|
||||
int result = bp::system(p, "main.cpp");
|
||||
```
|
||||
|
||||
Now, there is a subtle difference between the two syntaxes, i.e. passing a
|
||||
single string or passing multiple. When passing multiple string, the first string will be
|
||||
interpreted as the name of a file and the rest as arguments;
|
||||
when passing one string it will be interpreted as a command.
|
||||
|
||||
For more details please see the [link boost_process.design.arg_cmd_style design description].
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:launch_mode Launch functions]
|
||||
|
||||
Given that in our example used the [funcref boost::process::system system] function,
|
||||
our program will wait until the child process is completed. This is unwanted,
|
||||
especially since compiling can take a while.
|
||||
|
||||
In order to avoid that, boost.process provides several ways to launch a process.
|
||||
Besides the already mentioned [funcref boost::process::system system] function,
|
||||
we can also use the [funcref boost::process::spawn spawn] function or the
|
||||
[classref boost::process::child child] class.
|
||||
|
||||
The [funcref boost::process::spawn spawn] function launches a process and
|
||||
immediately detaches so, so no handle will be returned and the process will be ignored.
|
||||
This is not what we need for compiling, but maybe we want to entertain the user,
|
||||
while compiling:
|
||||
|
||||
```
|
||||
bp::spawn("chrome", boost_org);
|
||||
```
|
||||
|
||||
Now for the more sensible approach for compiling, we want a non-blocking execution.
|
||||
To implement that, we directly call the constructor of [classref boost::process::child child].
|
||||
|
||||
```
|
||||
bp::child c("g++", "main.cpp");
|
||||
|
||||
while (c.child_running())
|
||||
do_some_stuff();
|
||||
|
||||
c.child_wait(); //wait for the process to exit
|
||||
int result = c.child_exit_code();
|
||||
```
|
||||
|
||||
So we launch the process, by calling the child constructor. Then we check and do other
|
||||
things while the process is running and afterwards get the exit code. The call
|
||||
to child_wait is necessary, to obtain it and tell the operating system, that no
|
||||
one is waiting for the process anymore.
|
||||
|
||||
[note You can also wait for a time span or a until a time point with __wait_for__ and __wait_until__]
|
||||
|
||||
[warning If you don't call wait on a child object, it will be terminated on destruction.
|
||||
This can be avoided by calling __detach__ beforehand]
|
||||
|
||||
[endsect]
|
||||
[section:error_handling Error]
|
||||
|
||||
Until now, we have assumed that everything works out, but it is not impossible,
|
||||
that "g++" is not present. That will cause the launch of the process to fail.
|
||||
The default behaviour of all functions is to throw an
|
||||
[@http://en.cppreference.com/w/cpp/error/system_error std::system_error] on failure.
|
||||
As with many other functions in this library, passing an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code]
|
||||
will change the behaviour, so that instead of throwing an exception, the error will be a assigned to the error code.
|
||||
|
||||
```
|
||||
std::error_code ec;
|
||||
bp::system c("g++", "main.cpp", ec);
|
||||
```
|
||||
[endsect]
|
||||
[section:io Synchronous I/O]
|
||||
|
||||
In the examples given above, we have only started a program, but did not consider the output.
|
||||
The default depends on the system, but usually this will just write it to the same output as the launching process.
|
||||
If this shall be guaranteed, the streams can be explicitly forwarded like this.
|
||||
|
||||
```
|
||||
bp::system("g++", bp::std_out > stdout, bp::std_err > stderr, bp::std_in < stdin);
|
||||
```
|
||||
|
||||
Now for the first example, we might want to just ignore the output, which can be done by redirecting it to the null-device.
|
||||
This can be achieved this way:
|
||||
|
||||
```
|
||||
bp::system("g++", "main.cpp", bp::std_out > bp::null);
|
||||
```
|
||||
|
||||
Alternatively we can also easily redirect the output to a file:
|
||||
|
||||
```
|
||||
bp::system("g++", "main.cpp", bp::std_out > "gcc_out.log");
|
||||
```
|
||||
|
||||
Now, let's take a more visual example for reading data.
|
||||
[@http://pubs.opengroup.org/onlinepubs/009696699/utilities/nm.html nm] is a tool on posix,
|
||||
which reads the outline, i.e. a list of all entry points, of a binary.
|
||||
Every entry point will be put into a single line, and we will use a pipe to read it.
|
||||
At the end an empty line is appended, which we use as the indication to stop reading.
|
||||
Boost.process provides the pipestream ([classref boost::process::ipstream ipstream],
|
||||
[classref boost::process::opstream opstream], [classref boost::process::pstream pstream]) to
|
||||
wrap around the [classref boost::process::pipe pipe] and provide an implementation of the
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_istream std::istream],
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_ostream std::ostream] and
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_iostream std::iostream] interface.
|
||||
|
||||
```
|
||||
std::vector<std::string> read_outline(std::string & file)
|
||||
{
|
||||
bp::ipstream is; //reading pipe-stream
|
||||
bp::child c("nm", file, bp::std_out > is);
|
||||
|
||||
std::vector<std::string> data;
|
||||
std::string line;
|
||||
|
||||
while (c.child_running() && std::getline(is, line) && !line.empty())
|
||||
data.push_back(line);
|
||||
|
||||
c.child_wait();
|
||||
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
What this does is redirect the `stdout` of the process into a pipe and we read this
|
||||
synchronously.
|
||||
|
||||
[warning The pipe will cause a deadlock if you try to read after nm exited]
|
||||
[note You can do the same thing with [globalref boost::process::std_err std_err]]
|
||||
|
||||
Now we get the name from `nm` and we might want to demangle it, so we use input and output.
|
||||
`nm` has a demangle option, but for the sake of the example, we'll use
|
||||
[@https://sourceware.org/binutils/docs/binutils/c_002b_002bfilt.html c++filt] for this.
|
||||
|
||||
```
|
||||
bp::opstream in;
|
||||
bp::ipstream out;
|
||||
|
||||
bp::child c("c++filt", std_out > out, std_in < in);
|
||||
|
||||
in << "_ZN5boost7process8tutorialE" << endl;
|
||||
std::string value;
|
||||
out >> value;
|
||||
|
||||
c.child_terminate();
|
||||
```
|
||||
|
||||
Now you might want to forward output from one process to another processes input.
|
||||
|
||||
```
|
||||
std::vector<std::string> read_demangled_outline(const std::string & file)
|
||||
{
|
||||
bp::pipe p;
|
||||
bp::ipstream is;
|
||||
|
||||
std::vector<std::string> outline;
|
||||
|
||||
//we just use the same pipe, so the
|
||||
bp::child nm("nm", file, bp::std_out > p);
|
||||
bp::child filt("c++filt", bp::std_in < p, bp::std_out > is);
|
||||
|
||||
while (nm.running()) //nm finishes automatically, so then we can terminate c++filt.
|
||||
{
|
||||
std::string line;
|
||||
std::getline(is, line);
|
||||
outline.push_back(line);
|
||||
}
|
||||
nm.child_wait();
|
||||
filt.child_terminate();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Now this forwards the data from `nm` to `c++filt` without your process needing to do anything.
|
||||
|
||||
[endsect]
|
||||
[section:async_io Asynchronous I/O]
|
||||
|
||||
Boost.process allows the usage of boost.asio to implement asynchronous I/O.
|
||||
If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] (which we highly recommend),
|
||||
you can use [classref boost::process::async_pipe async_pipe] which is implemented
|
||||
as an I/O-Object and can be used like [classref boost::process::pipe pipe] as shown above.
|
||||
|
||||
Now we get back to our compiling example. `nm` we might analyze it line by line,
|
||||
but the compiler output will just be put into one large buffer.
|
||||
|
||||
With [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] this is what it looks like.
|
||||
|
||||
```
|
||||
io_service ios;
|
||||
std::vector<char> buf;
|
||||
|
||||
bp::async_pipe ap(ios);
|
||||
|
||||
child c("g++", "main.cpp", bp::std_out > ap);
|
||||
|
||||
asio_async_read(ap, asio_buffer(buf),
|
||||
[](const boost::system::error_code &ec, std::size_t size){});
|
||||
|
||||
ios.run();
|
||||
c.wait();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
To make it easier, boost.process provides simpler interface for that, so that the buffer can be passed directly,
|
||||
provided we also pass a reference to an io_service.
|
||||
|
||||
```
|
||||
io_service ios;
|
||||
std::vector<char> buf;
|
||||
|
||||
child c("g++", "main.cpp", bp::std_out > asio_buffer(buf), ios);
|
||||
|
||||
ios.run();
|
||||
c.wait();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
[note Passing an instance of io_service to the launching function automatically cause it to wait asynchronously for the exit, so no call of
|
||||
[memberref boost::process::child::wait wait] is needed]
|
||||
|
||||
To make it even easier, you can use [@http://en.cppreference.com/w/cpp/thread/future std::future] for asynchronous operations
|
||||
(you will still need to pass a reference to a io_service) to the launching function, unless you use bp::system.
|
||||
|
||||
Now we will revisit our first example and read the compiler output asynchronously:
|
||||
|
||||
```
|
||||
boost::asio::io_service ios;
|
||||
|
||||
std::future<std::string> data;
|
||||
|
||||
child c("g++", "main.cpp", //set the input
|
||||
bp::std_in.close(),
|
||||
bp::std_out > bp::null, //so it can be written without anything
|
||||
bp::std_err > data,
|
||||
ios);
|
||||
|
||||
|
||||
ios.run(); //this will actually block until the compiler is finished
|
||||
|
||||
auto err = fut.get();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
[section:group Groups]
|
||||
|
||||
When launching several processes, processes can be grouped together.
|
||||
This will also apply for a child process, that launches other processes,
|
||||
if they do not modifiy the group membership. E.g. if you call `make` which
|
||||
launches other processes and call terminate on it,
|
||||
it will not terminate all the child processes of the child unless you use a group.
|
||||
|
||||
```
|
||||
bp::group g;
|
||||
bp::child c1("foo", g);
|
||||
bp::child c2("bar", g);
|
||||
g.group_terminate();
|
||||
```
|
||||
|
||||
Please see to the [headerref boost/process/group.hpp reference] for more information.
|
||||
|
||||
[endsect]
|
||||
[section:env Environment]
|
||||
|
||||
This library provides access to the environment of the current process and allows
|
||||
setting it for the child process.
|
||||
|
||||
```
|
||||
//get a handle to the current environment
|
||||
auto env = boost::this_process::environment();
|
||||
//add a variable to the current environment
|
||||
env["VALUE_1"] = "foo";
|
||||
|
||||
//copy it into a environment seperate to the one of this process
|
||||
bp::environment env_ = env;
|
||||
//add a value only to the new env
|
||||
env_["VALUE_2"] = "bar";
|
||||
|
||||
//launch a process with `env_`
|
||||
bp::system("stuff", env_);
|
||||
```
|
||||
|
||||
A more convenient way to modify the environment for the child is the
|
||||
[globalref boost::process::env env] property.
|
||||
|
||||
Please see to the [headerref boost/process/environment.hpp reference] for more information.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:coro Coroutines]
|
||||
[section:stackless Stackless Coroutines]
|
||||
|
||||
[note This section presumes knowledge of the boost.asio
|
||||
[@http://www.boost.org/doc/libs/release/doc/html/boost_asio/overview/core/coroutine.html stackless coroutine] feature.]
|
||||
|
||||
Stackless coroutines can be implemented rather easily, so there is no need to
|
||||
implement extra functionality concerning boost.process.
|
||||
|
||||
```
|
||||
struct stackless_t : boost::asio::coroutine
|
||||
{
|
||||
bp::child c;
|
||||
|
||||
boost::asio::io_service & ios;
|
||||
|
||||
stackless_t(boost::asio::io_service & ios) : ios(ios) {}
|
||||
|
||||
void operator()(
|
||||
boost::system::error_code ec = boost::system::error_code(),
|
||||
std::size_t n = 0)
|
||||
{
|
||||
if (!ec) reenter (this)
|
||||
{
|
||||
c = bp::child("my_program", ios,
|
||||
bp::on_exit=
|
||||
[this](int, const std::error_code&)
|
||||
{
|
||||
(*this)(); //this is the reentry for the coroutine
|
||||
});
|
||||
yield; //yield the thing.
|
||||
}
|
||||
}
|
||||
};
|
||||
///post the coroutine to a io-service and run it
|
||||
int main()
|
||||
{
|
||||
boost::asio::io_service ios;
|
||||
ios.post(stackless_t(ios));
|
||||
ios.run();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:stackful Stackful Coroutines]
|
||||
|
||||
[note This section presumes knowledge of the boost.asio
|
||||
[@http://www.boost.org/doc/libs/release/doc/html/boost_asio/overview/core/spawn.html stackful coroutine] feature.]
|
||||
|
||||
For stackful coroutines this is not as simple, because the members of
|
||||
`boost::asio::yield_context` are not documented. Therefore, boost.process
|
||||
provides a simple way to use stackful coroutines, which looks as follows:
|
||||
|
||||
```
|
||||
void cr(boost::asio::yield_context yield_)
|
||||
{
|
||||
bp::system("my-program", yield_);
|
||||
}
|
||||
```
|
||||
|
||||
This will automatically suspend the coroutine until the child process is finished.
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
11
doc/v1.qbk
Normal file
11
doc/v1.qbk
Normal file
@@ -0,0 +1,11 @@
|
||||
[section:v1 Process V1]
|
||||
|
||||
[include v1/introduction.qbk]
|
||||
[include v1/concepts.qbk]
|
||||
[include v1/tutorial.qbk]
|
||||
[include v1/design.qbk]
|
||||
[include v1/extend.qbk]
|
||||
[include v1/faq.qbk]
|
||||
[xinclude reference_v2.xml]
|
||||
|
||||
[endsect]
|
||||
82
doc/v1/concepts.qbk
Normal file
82
doc/v1/concepts.qbk
Normal file
@@ -0,0 +1,82 @@
|
||||
[section:concepts Concepts]
|
||||
In this section, some of the underlying concepts of the operating system used in this library, will be explained.
|
||||
In the following chapters we will presume knowledge of that. Though please note,
|
||||
that this is a short summary and not conclusive of everything that can be done.
|
||||
|
||||
The goal of this library is to implement a portable wrapper, so that we will explain mostly what
|
||||
windows and posix have in common.
|
||||
|
||||
[section:pipes Pipes]
|
||||
Pipes are a facility for communication between different threads, processes and in some cases machines, the operating system provides.
|
||||
|
||||
The typical feature of a pipe is, that it is one channel, to which two handles are given, one for reading (source), one for writing (sink).
|
||||
In that it is different than other facilities (like sockets) and provides another way to manage the connectivity: if one side of the pipe is closed
|
||||
(i.e. the pipe is broken), the other is notified.
|
||||
|
||||
Pipes are typically used for interprocess communication. The main reason is, that pipes can be directly assigned to the process stdio, i.e. stderr, stdin and stdout.
|
||||
Additionally, half of the pipe can be inherited to the child process and closed in the father process. This will cause the pipe to be broken when the child process exits.
|
||||
|
||||
Though please note, that if the same thread reads and writes to a pipe, it will only talk to itself.
|
||||
|
||||
[section:anonymous Anonymous Pipes]
|
||||
|
||||
The most common pipes are anonymous. Since they have no name,
|
||||
a handle to them can only be obtained from duplicating either handle.
|
||||
|
||||
In this library the following functions are used for the creation of unnamed pipes:
|
||||
|
||||
* [@http://pubs.opengroup.org/onlinepubs/7908799/xsh/pipe.html posix]
|
||||
* [@https://msdn.microsoft.com/de-de/library/windows/desktop/aa365152.aspx windows]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:named Named Pipes]
|
||||
|
||||
As the name suggests, named pipes have a string identifier. This means that a
|
||||
handle to them can be obtained with the identifier, too.
|
||||
|
||||
The implementation on posix uses [@http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html fifos],
|
||||
which means, that the named pipe behaves like a file.
|
||||
|
||||
Windows does provide a facility called [@https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx named pipes],
|
||||
which also have file-like names, but are in a different scope than the actual file system.
|
||||
|
||||
[note The main reason named pipes are part of this library, is because they need to be internally used for asynchronous communication on windows.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:process Processes]
|
||||
|
||||
A process is an independently executable entity, which is different from a thread, in that it has its own resources.
|
||||
Those include memory and hardware resources.
|
||||
|
||||
Every process is identified by a unique number[footnote it is unique as long as the process is active], called the process identification digit, `pid`.
|
||||
|
||||
[section:exit_code Exit code]
|
||||
A process will return an integer value indicating whether it was successful. On posix
|
||||
there are more codes associated with that, but not so on windows. Therefore there is no such encoding currently in the library.
|
||||
However an exit code of zero means the process was successful, while one different than zero indicates an error.
|
||||
[endsect]
|
||||
|
||||
[section:termination Termination]
|
||||
Processes can also be forced to exit. There are two ways to do this, signal the process to do so and wait, and just terminate the process without conditions.
|
||||
|
||||
Usually the first approach is to signal an exit request, but windows - unlike posix - does not provide a consistent way to do this. Hence this is not part of the
|
||||
library and only the hard terminate is.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:env Environment]
|
||||
|
||||
The environment is a map of variables local to every process. The most significant one for this library
|
||||
is the `PATH` variable, which contains a list of paths, that ought to be searched for executables. A shell will do this automatically,
|
||||
while this library provides a function for that.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
@@ -1,12 +1,12 @@
|
||||
[section:design Design Rationale]
|
||||
[section Scope]
|
||||
This library is meant to give an wrapper around the different OS-specific methods
|
||||
This library is meant to give a wrapper around the different OS-specific methods
|
||||
to launch processes. Its aim is to provide all functionality that is available on
|
||||
those systems and allow the user to do all related things, which require using the OS APIs.
|
||||
|
||||
[*This library does not try to provide a full library for everything process related]
|
||||
[*This library does not try to provide a full library for everything process related.]
|
||||
In many discussions the proposal was made to build boost.process into a DSEL [footnote Domain Specific Embedded Language] of some sort.
|
||||
This is not the goal, it rather provides the facilities to build such a DSEL-Library on top of it.
|
||||
This is not the goal, it rather provides the facilities to build such a DSEL-library on top of it.
|
||||
Therefore the library also does [*not] force any particular use (such as only asynchronous communication) on its user.
|
||||
It rather could be integrated with such a library.
|
||||
|
||||
@@ -33,7 +33,7 @@ Both styles can also be mixed in some cases.
|
||||
system("gcc", "-c", args+={"main.cpp"});
|
||||
```
|
||||
|
||||
In the following section the avaible styles will be described. Note that the
|
||||
In the following section the available styles will be described. Note that the
|
||||
overload style is implemented via type traits, so the types will be listed.
|
||||
|
||||
[caution There is no guarantee in which order the arguments will be applied!
|
||||
@@ -54,7 +54,7 @@ interpret each string as an argument.
|
||||
]
|
||||
|
||||
When using the overloading variant, a single string will result in a cmd interpretation,
|
||||
several strings will yield a exe-args interpretation. Both version can be set explicitly:
|
||||
several strings will yield a exe-args interpretation. Both versions can be set explicitly:
|
||||
|
||||
```
|
||||
system("grep -c false /etc/passwd"); //cmd style
|
||||
@@ -65,8 +65,9 @@ system(exe="grep", args={"-c", "false", "/etc/passwd"}); //exe-/args-
|
||||
```
|
||||
|
||||
[note If a '"' sign is used in the argument style, it will be passed as part of the argument.
|
||||
If the same effect it wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
|
||||
[note On windows the path will only be searched for the executable in the command style.]
|
||||
If the same effect is wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
|
||||
[note The `PATH` variable will automatically be searched in the command style,
|
||||
but the one of the launching process, not the one passed to the child process.]
|
||||
[endsect]
|
||||
|
||||
[section:plat_ext Extensions]
|
||||
@@ -74,15 +75,15 @@ If the same effect it wanted with the cmd syntax, it ought to be escaped, i.e. '
|
||||
The simplest form to extend functionality is to provide another handler, which
|
||||
will be called on the respective events on process launching. The names are:
|
||||
|
||||
*`boost::process::on_setup`
|
||||
*`boost::process::on_error`
|
||||
*`boost::process::on_success`
|
||||
*`boost::process::v1::on_setup`
|
||||
*`boost::process::v1::on_error`
|
||||
*`boost::process::v1::on_success`
|
||||
|
||||
|
||||
As an example:
|
||||
|
||||
```
|
||||
child c("ls", on_setup([](){cout << "On Setup" << endl;});
|
||||
child c("ls", on_setup([](){cout << "On Setup" << endl;}));
|
||||
```
|
||||
|
||||
|
||||
212
doc/v1/extend.qbk
Normal file
212
doc/v1/extend.qbk
Normal file
@@ -0,0 +1,212 @@
|
||||
[def __on_exit__ [globalref boost::process::v1::on_exit on_exit]]
|
||||
[def __on_success__ [globalref boost::process::v1::extend::on_success ex::on_success]]
|
||||
[def __child__ [classref boost::process::v1::child child]]
|
||||
[def __handler__ [classref boost::process::v1::extend::handler handler]]
|
||||
[def __on_success__ [memberref boost::process::v1::extend::handler::on_success on_success]]
|
||||
[def __posix_executor__ [classref boost::process::v1::extend::posix_executor ex::posix_executor]]
|
||||
[def __windows_executor__ [classref boost::process::v1::extend::windows_executor ex::windows_executor]]
|
||||
[def __io_context__ [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_context.html boost::asio::io_context]]
|
||||
[def __require_io_context__ [classref boost::process::v1::extend::require_io_context ex::require_io_context]]
|
||||
[def __async_handler__ [classref boost::process::v1::extend::async_handler ex::async_handler]]
|
||||
[def __get_io_context__ [funcref boost::process::v1::extend::get_io_context ex::get_io_context]]
|
||||
|
||||
[section:extend Extensions]
|
||||
To extend the library, the header [headerref boost/process/extend.hpp extend] is provided.
|
||||
|
||||
It only provides the explicit style for custom properties, but no implicit style.
|
||||
|
||||
What this means is, that a custom initializer can be implemented, a reference which can be passed to one of the launching functions.
|
||||
If a class inherits [classref boost::process::v1::extend::handler] it will be regarded as an initializer and thus directly put into the sequence
|
||||
the executor gets passed.
|
||||
|
||||
[section:structure Structure]
|
||||
|
||||
The executor calls different handlers of the initializers during the process launch.
|
||||
The basic structure consists of three functions, as given below:
|
||||
|
||||
* [globalref boost::process::v1::extend::on_setup on_setup]
|
||||
* [globalref boost::process::v1::extend::on_error on_error]
|
||||
* [globalref boost::process::v1::extend::on_success on_success]
|
||||
|
||||
'''
|
||||
<imagedata fileref="boost_process/windows_exec.svg"/>
|
||||
'''
|
||||
|
||||
Additionally posix provides three more handlers, listed below:
|
||||
|
||||
* [globalref boost::process::v1::extend::on_fork_error on_fork_error]
|
||||
* [globalref boost::process::v1::extend::on_exec_setup on_exec_setup]
|
||||
* [globalref boost::process::v1::extend::on_exec_error on_exec_error]
|
||||
|
||||
For more information see the reference of [classref boost::process::v1::extend::posix_executor posix_executor].
|
||||
|
||||
[endsect]
|
||||
[section:simple Simple extensions]
|
||||
|
||||
The simplest extension just takes a single handler, which can be done in a functional style.
|
||||
So let's start with a simple hello-world example, while we use a C++14 generic lambda.
|
||||
|
||||
```
|
||||
using namespace boost::process;
|
||||
namespace ex = bp::extend;
|
||||
|
||||
__child__ c("foo", __on_success__=[](auto & exec) {std::cout << "hello world" << std::endl;});
|
||||
```
|
||||
|
||||
Considering that lambdas can also capture values, data can easily be shared between handlers.
|
||||
|
||||
To see which members the executor has, refer to [classref boost::process::v1::extend::windows_executor windows_executor]
|
||||
and [classref boost::process::v1::extend::posix_executor posix_executor].
|
||||
|
||||
[note Combined with __on_exit__ this can also handle the process exit.]
|
||||
|
||||
[caution The posix handler symbols are not defined on windows.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:handler Handler Types]
|
||||
|
||||
Since the previous example is in a functional style, it is not very reusable.
|
||||
To solve that problem, the [classref boost::process::v1::extend::handler handler] has an alias in the `boost::process::v1::extend` namespace, to be inherited.
|
||||
So let's implement the hello world example in a class.
|
||||
|
||||
```
|
||||
struct hello_world : __handler__
|
||||
{
|
||||
template<typename Executor>
|
||||
void __on_success__(Executor & exec) const
|
||||
{
|
||||
std::cout << "hello world" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
//in our function
|
||||
__child__ c("foo", hello_world());
|
||||
```
|
||||
|
||||
[note The implementation is done via overloading, not overriding.]
|
||||
|
||||
Every handler not implemented defaults to [classref boost::process::v1::extend::handler handler], where an empty handler is defined for each event.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:async Asynchronous Functionality]
|
||||
|
||||
Since `boost.process` provides an interface for [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio],
|
||||
this functionality is also available for extensions. If the class needs the __io_context__ for some reason, the following code will do that.
|
||||
|
||||
```
|
||||
struct async_foo : __handler__, __require_io_context__
|
||||
{
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
__io_context__ & ios = __get_io_context__(exec.seq); //gives us a reference and a compiler error if not present.
|
||||
//do something with ios
|
||||
}
|
||||
};
|
||||
```
|
||||
[note Inheriting [globalref boost::process::v1::extend::require_io_context require_io_context] is necessary, so [funcref boost::process::v1::system system] provides one.]
|
||||
|
||||
Additionally the handler can provide a function that is invoked when the child process exits. This is done through __async_handler__.
|
||||
|
||||
[note [globalref boost::process::v1::extend::async_handler async_handler] implies [globalref boost::process::v1::extend::require_io_context require_io_context] .]
|
||||
|
||||
```
|
||||
struct async_bar : __handler, __async_handler__
|
||||
{
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
|
||||
{
|
||||
auto handler_ = this->handler;
|
||||
return [handler_](int exit_code, const std::error_code & ec)
|
||||
{
|
||||
std::cout << "hello world, I exited with " << exit_code << std::endl;
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
[caution `on_exit_handler` does not default and is always required when [classref boost::process::v1::extend::async_handler async_handler] is inherited. ]
|
||||
|
||||
[caution `on_exit_handler` uses `boost::asio::signal_set` to listen for SIGCHLD on posix. The application must not also register a signal handler for SIGCHLD using functions such as `signal()` or `sigaction()` (but using `boost::asio::signal_set` is fine). ]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:error Error handling]
|
||||
|
||||
If an error occurs in the initializers it shall be told to the executor and not handled directly. This is because
|
||||
the behaviour can be changed through arguments passed to the launching function. Hence the executor
|
||||
has the function `set_error`, which takes an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code] and a string.
|
||||
Depending on the configuration of the executor, this may either throw, set an internal `error_code`, or do nothing.
|
||||
|
||||
So let's take a simple example, where we set a randomly chosen `error_code`.
|
||||
|
||||
```
|
||||
auto set_error = [](auto & exec)
|
||||
{
|
||||
std::error_code ec{42, std::system_category()};
|
||||
exec.set_error(ec, "a fake error");
|
||||
|
||||
};
|
||||
__child__ c("foo", on_setup=set_error);
|
||||
```
|
||||
|
||||
Since we do not specify the error-handling mode in this example, this will throw [classref boost::process::v1::process_error process_error].
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:exec_over Executor Overloading]
|
||||
|
||||
Now that we have a custom initializer, let's consider how we can handle differences between different executors.
|
||||
The distinction is between posix and windows and `char` and `wchar_t` on windows.
|
||||
One solution is to use the [@http://www.boost.org/doc/libs/master/boost/system/api_config.hpp BOOST_WINDOWS_API and BOOST_POSIX_API] macros,
|
||||
which are automatically available as soon as any process-header is included.
|
||||
|
||||
Another variant are the type aliases __posix_executor__ and __windows_executor__, where the executor, not on the current system is a forward-declaration.
|
||||
This works fine, because the function will never get invoked. So let's implement another example, which prints the executable name __on_success__.
|
||||
|
||||
```
|
||||
struct hello_exe : __handler__
|
||||
{
|
||||
template<typename Sequence>
|
||||
void __on_success__(__posix_executor__<Sequence> & exec)
|
||||
{
|
||||
std::cout << "posix-exe: " << exec.exe << std::endl;
|
||||
}
|
||||
|
||||
template<typename Sequence>
|
||||
void __on_success__(__windows_executor__<char, Sequence> & exec)
|
||||
{
|
||||
//note: exe might be a nullptr on windows.
|
||||
if (exec.exe != nullptr)
|
||||
std::cout << "windows-exe: " << exec.exe << std::endl;
|
||||
else
|
||||
std::cout << "windows didn't use exe" << std::endl;
|
||||
}
|
||||
|
||||
template<typename Sequence>
|
||||
void __on_success__(__windows_executor__<wchar_t, Sequence> & exec)
|
||||
{
|
||||
//note: exe might be a nullptr on windows.
|
||||
if (exec.exe != nullptr)
|
||||
std::wcout << L"windows-exe: " << exec.exe << std::endl;
|
||||
else
|
||||
std::cout << "windows didn't use exe" << std::endl;
|
||||
}
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
So given our example, the definitions with the non-native executor are still a template so that they will not be evaluated if not used. Hence this provides a
|
||||
way to implement system-specific code without using the preprocessor.
|
||||
|
||||
[note If you only write a partial implementation, e.g. only for __posix_executor__, the other variants will default to __handler__].
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
@@ -1,87 +1,87 @@
|
||||
[section:faq Frequently Asked Questions]
|
||||
|
||||
[section:dead_lock Why does this produce a deadlock?]
|
||||
|
||||
Now let's revisit our c++filt example and we will put in an obvious mistake.
|
||||
This might however be not as obvious for more complex applications.
|
||||
|
||||
```
|
||||
vector<string> demangle(vector<string> in)
|
||||
{
|
||||
|
||||
ipstream is;
|
||||
opstream os;
|
||||
child c("c++filt", std_out > is, std_in < os);
|
||||
|
||||
vector<string> data;
|
||||
for (auto & elem : data)
|
||||
{
|
||||
string line;
|
||||
getline(is, line);
|
||||
os << elem;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
We switched the read and write operation up, so that's causing a dead-lock.
|
||||
This locks immediately. This is because `c++filt` expects input, before
|
||||
outputting any data. The launching process on the other hand wait's for it's output.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:closep Why does the pipe not close?]
|
||||
|
||||
Now for another example, which might look correct, let's consider you want
|
||||
to use `ls` to read the current directory.
|
||||
|
||||
```
|
||||
ipstream is;
|
||||
child c("ls", std_out > is);
|
||||
|
||||
std::string file;
|
||||
while (is >> file)
|
||||
cout << "File: " << file << endl;
|
||||
|
||||
```
|
||||
|
||||
This will also deadlock, because the pipe does not close when the subprocess exits.
|
||||
So the `ipstream` will still look for data even though the process has ended.
|
||||
|
||||
[note It is not possible to use automatically pipe-closing in this library, because
|
||||
a pipe might be a file-handle (as for async pipes on windows).]
|
||||
|
||||
But, since pipes are buffered, you might get incomplete data if you do this:
|
||||
|
||||
```
|
||||
ipstream is;
|
||||
child c("ls", std_out > is);
|
||||
|
||||
std::string file;
|
||||
while (c.running())
|
||||
{
|
||||
is >> file;
|
||||
cout << "File: " << file << endl;
|
||||
}
|
||||
```
|
||||
|
||||
It is therefore highly recommended that you use the asynchronous api if you are
|
||||
not absolutely sure how the output will look.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wchar_t When will the codecvt be used?]
|
||||
|
||||
Since windows does not use UTF-8 it is sometimes unavoidable to use the `wchar_t` version of the WinApi.
|
||||
To keep this library consistent it provides `wchar_t` support on posix also.
|
||||
|
||||
Since the posix api is purely `char` every `wchar_t` based type will be converted into `char`.
|
||||
|
||||
Windows on the other hand is more selective; the default is to use `char`,
|
||||
but if any parameter requires `wchar_t`, everything will be converted to `wchar_t`.
|
||||
This also includes `boost::filesystem::path`. Additionally, if the system does not provide
|
||||
the `char` api (as is the case with Windows CE) everything will also be converted.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:faq Frequently Asked Questions]
|
||||
|
||||
[section:dead_lock Why does this produce a deadlock?]
|
||||
|
||||
Now let's revisit our c++filt example and we will put in an obvious mistake.
|
||||
This might however be not as obvious for more complex applications.
|
||||
|
||||
```
|
||||
vector<string> demangle(vector<string> in)
|
||||
{
|
||||
|
||||
ipstream is;
|
||||
opstream os;
|
||||
child c("c++filt", std_out > is, std_in < os);
|
||||
|
||||
vector<string> data;
|
||||
for (auto & elem : data)
|
||||
{
|
||||
string line;
|
||||
getline(is, line);
|
||||
os << elem;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
We switched the read and write operation up, so that's causing a dead-lock.
|
||||
This locks immediately. This is because `c++filt` expects input, before
|
||||
outputting any data. The launching process on the other hand waits for its output.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:closep Why does the pipe not close?]
|
||||
|
||||
Now for another example, which might look correct, let's consider you want
|
||||
to use `ls` to read the current directory.
|
||||
|
||||
```
|
||||
ipstream is;
|
||||
child c("ls", std_out > is);
|
||||
|
||||
std::string file;
|
||||
while (is >> file)
|
||||
cout << "File: " << file << endl;
|
||||
|
||||
```
|
||||
|
||||
This will also deadlock, because the pipe does not close when the subprocess exits.
|
||||
So the `ipstream` will still look for data even though the process has ended.
|
||||
|
||||
[note It is not possible to use automatic pipe-closing in this library, because
|
||||
a pipe might be a file-handle (as for async pipes on windows).]
|
||||
|
||||
But, since pipes are buffered, you might get incomplete data if you do this:
|
||||
|
||||
```
|
||||
ipstream is;
|
||||
child c("ls", std_out > is);
|
||||
|
||||
std::string file;
|
||||
while (c.running())
|
||||
{
|
||||
is >> file;
|
||||
cout << "File: " << file << endl;
|
||||
}
|
||||
```
|
||||
|
||||
It is therefore highly recommended that you use the asynchronous API if you are
|
||||
not absolutely sure how the output will look.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wchar_t When will the codecvt be used?]
|
||||
|
||||
Since windows does not use UTF-8 it is sometimes unavoidable to use the `wchar_t` version of the WinApi.
|
||||
To keep this library consistent it provides `wchar_t` support on posix also.
|
||||
|
||||
Since the posix api is purely `char` every `wchar_t` based type will be converted into `char`.
|
||||
|
||||
Windows on the other hand is more selective; the default is to use `char`,
|
||||
but if any parameter requires `wchar_t`, everything will be converted to `wchar_t`.
|
||||
This also includes `boost::filesystem::path`. Additionally, if the system does not provide
|
||||
the `char` api (as is the case with Windows CE) everything will also be converted.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
24
doc/v1/introduction.qbk
Normal file
24
doc/v1/introduction.qbk
Normal file
@@ -0,0 +1,24 @@
|
||||
[section:introduction Introduction]
|
||||
|
||||
Boost.Process is a library to manage system processes. It can be used to:
|
||||
|
||||
* create child processes
|
||||
* setup streams for child processes
|
||||
* communicate with child processes through streams (synchronously or asynchronously)
|
||||
* wait for processes to exit (synchronously or asynchronously)
|
||||
* terminate processes
|
||||
|
||||
Here's a simple example of how to start a program with Boost.Process:
|
||||
|
||||
[def ipstream [classref boost::process::v1::ipstream ipstream]]
|
||||
[def system [funcref boost::process::v1::system system]]
|
||||
[def std_out [globalref boost::process::v1::std_out std_out]]
|
||||
[def child [globalref boost::process::v1::child child]]
|
||||
[def boost/process.hpp [headerref boost/process.hpp boost/process.hpp]]
|
||||
[def std::string [@http://en.cppreference.com/w/cpp/string/basic_string std::string]]
|
||||
[def std::getline [@http://en.cppreference.com/w/cpp/string/basic_string/getline std::getline]]
|
||||
|
||||
[import ../../example/intro.cpp]
|
||||
[intro]
|
||||
|
||||
[endsect]
|
||||
60
doc/v1/posix_pseudocode.xml
Normal file
60
doc/v1/posix_pseudocode.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<programlisting>
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (<methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::v1::child">child</classname>();
|
||||
}
|
||||
|
||||
pid = <ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html">fork()</ulink>
|
||||
<methodname alt="boost::process::v1::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (pid == -1) //fork error
|
||||
{
|
||||
<methodname alt="boost::process::v1::extend::posix_executor::set_error">set_error</methodname>(<functionname alt="boost::process::v1::extend::get_last_error">get_last_error</functionname>());
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_fork_error">on_fork_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::v1::child">child</classname>()
|
||||
}
|
||||
else if (pid == 0) //child process
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_exec_setup">on_exec_setup</methodname>(*this);
|
||||
<ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html">execve</ulink>(exe, cmd_line, env);
|
||||
auto ec = <functionname alt="boost::process::v1::extend::get_last_error">get_last_error</functionname>();
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_exec_error">on_exec_error</methodname>(*this);
|
||||
|
||||
<emphasis>unspecified();</emphasis>//here the error is sent to the father process internally
|
||||
|
||||
<ulink url="http://en.cppreference.com/w/cpp/utility/program/exit">std::exit</ulink>(<ulink url="http://en.cppreference.com/w/c/program/EXIT_status">EXIT_FAILURE</ulink>);
|
||||
return <classname alt="boost::process::v1::child">child</classname>(); //for C++ compliance
|
||||
}
|
||||
|
||||
<classname alt="boost::process::v1::child">child</classname> c(pid, exit_code);
|
||||
|
||||
<emphasis>unspecified();</emphasis>//here, we read the error from the child process
|
||||
|
||||
if (<methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>())
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
|
||||
else
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_success</methodname>(*this);
|
||||
|
||||
//now we check again, because an on_success handler might've errored.
|
||||
if (<methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::v1::child">child</classname>();
|
||||
}
|
||||
else
|
||||
return c;
|
||||
</programlisting>
|
||||
425
doc/v1/tutorial.qbk
Normal file
425
doc/v1/tutorial.qbk
Normal file
@@ -0,0 +1,425 @@
|
||||
[def bp::system [funcref boost::process::v1::system bp::system]]
|
||||
[def bp::async_system [funcref boost::process::v1::async_system bp::async_system]]
|
||||
[def bp::spawn [funcref boost::process::v1::spawn bp::spawn]]
|
||||
[def bp::child [classref boost::process::v1::child bp::child]]
|
||||
[def bp::cmd [classref boost::process::v1::cmd bp::cmd]]
|
||||
[def bp::group [classref boost::process::v1::group bp::group]]
|
||||
[def bp::ipstream [classref boost::process::v1::ipstream bp::ipstream]]
|
||||
[def bp::opstream [classref boost::process::v1::opstream bp::opstream]]
|
||||
[def bp::pstream [classref boost::process::v1::pstream bp::pstream]]
|
||||
[def bp::pipe [classref boost::process::v1::pipe bp::pipe]]
|
||||
[def bp::async_pipe [classref boost::process::v1::async_pipe bp::async_pipe]]
|
||||
[def bp::search_path [funcref boost::process::v1::search_path bp::search_path]]
|
||||
[def boost_org [@www.boost.org "www.boost.org"]]
|
||||
[def std::system [@http://en.cppreference.com/w/cpp/utility/program/system std::system]]
|
||||
[def child_running [memberref boost::process::v1::child::running running]]
|
||||
[def child_wait [memberref boost::process::v1::child::wait wait]]
|
||||
[def child_wait_for [memberref boost::process::v1::child::wait_for wait_for]]
|
||||
[def child_exit_code [memberref boost::process::v1::child::exit_code exit_code]]
|
||||
[def group_wait_for [memberref boost::process::v1::group::wait_for wait_for]]
|
||||
[def bp::on_exit [globalref boost::process::v1::on_exit bp::on_exit]]
|
||||
[def bp::null [globalref boost::process::v1::null bp::null]]
|
||||
[def child_terminate [memberref boost::process::v1::child::terminate terminate]]
|
||||
[def group_terminate [memberref boost::process::v1::group::terminate terminate]]
|
||||
[def group_wait [memberref boost::process::v1::group::wait wait]]
|
||||
[def bp::std_in [globalref boost::process::v1::std_in bp::std_in]]
|
||||
[def bp::std_out [globalref boost::process::v1::std_out bp::std_out]]
|
||||
[def bp::std_err [globalref boost::process::v1::std_err bp::std_err]]
|
||||
[def io_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]]
|
||||
[def asio_buffer [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html boost::asio::buffer]]
|
||||
[def asio_async_read [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_read.html boost::asio::async_read]]
|
||||
[def bp::environment [classref boost::process::v1::basic_environment bp::environment]]
|
||||
[def bp::native_environment [classref boost::process::v1::basic_native_environment bp::native_environment]]
|
||||
[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]]
|
||||
[def std::chrono::seconds [@http://en.cppreference.com/w/cpp/chrono/duration std::chrono::seconds]]
|
||||
[def std::vector [@http://en.cppreference.com/w/cpp/container/vector std::vector]]
|
||||
|
||||
[def __wait_for__ [memberref boost::process::v1::child::wait_for wait_for]]
|
||||
[def __wait_until__ [memberref boost::process::v1::child::wait_until wait_until]]
|
||||
[def __detach__ [memberref boost::process::v1::child::detach detach]]
|
||||
|
||||
[def __reference__ [link process.reference reference]]
|
||||
[def __concepts__ [link boost_process.concepts concepts]]
|
||||
|
||||
[def boost::asio::yield_context [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/yield_context.html boost::asio::yield_context]]
|
||||
[def boost::asio::coroutine [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/coroutine.html boost::asio::coroutine]]
|
||||
[def bp::env [globalref boost::process::v1::env bp::env]]
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
In this section we will go step by step through the different features of
|
||||
boost.process. For a full description see the __reference__ and the __concepts__ sections.
|
||||
|
||||
[section Starting a process]
|
||||
|
||||
We want to start a process, so let's start with a simple process. We will
|
||||
invoke the gcc compiler to compile a simple program.
|
||||
|
||||
With the standard library this looks like this.
|
||||
|
||||
```
|
||||
int result = std::system("g++ main.cpp");
|
||||
```
|
||||
|
||||
Which we can write exactly like this in boost.process.
|
||||
|
||||
```
|
||||
namespace bp = boost::process; //we will assume this for all further examples
|
||||
int result = bp::system("g++ main.cpp");
|
||||
```
|
||||
|
||||
If a single string is given (or the explicit form bp::cmd), it will be interpreted as a command line.
|
||||
That will cause the execution function to search the `PATH` variable to find the executable.
|
||||
The alternative is the `exe-args` style, where the first string will be interpreted as a filename (including the path),
|
||||
and the rest as arguments passed to said function.
|
||||
|
||||
[note For more details on the `cmd`/`exe-args` style look [link boost_process.design.arg_cmd_style here].]
|
||||
|
||||
So as a first step, we'll use the `exe-args` style.
|
||||
|
||||
```
|
||||
int result = bp::system("/usr/bin/g++", "main.cpp");
|
||||
```
|
||||
|
||||
With that syntax we still have "g++" hard-coded, so let's assume we get the string
|
||||
from an external source as `boost::process::v1::filesystem::path`, we can do this too.
|
||||
|
||||
```
|
||||
boost::process::v1::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
|
||||
int result = bp::system(p, "main.cpp");
|
||||
```
|
||||
|
||||
Now we might want to find the `g++` executable in the `PATH`-variable, as the `cmd` syntax would do.
|
||||
`Boost.process` provides a function to this end: bp::search_path.
|
||||
|
||||
```
|
||||
boost::process::v1::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else.
|
||||
int result = bp::system(p, "main.cpp");
|
||||
```
|
||||
|
||||
[note [funcref boost::process::v1::search_path search_path] will search for any executable with that name.
|
||||
This also includes to add a file suffix on windows, such as `.exe` or `.bat`.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:launch_mode Launch functions]
|
||||
|
||||
Given that our example used the [funcref boost::process::v1::system system] function,
|
||||
our program will wait until the child process is completed. This may be unwanted,
|
||||
especially since compiling can take a while.
|
||||
|
||||
In order to avoid that, boost.process provides several ways to launch a process.
|
||||
Besides the already mentioned [funcref boost::process::v1::system system] function and its
|
||||
asynchronous version [funcref boost::process::v1::async_system async_system],
|
||||
we can also use the [funcref boost::process::v1::spawn spawn] function or the
|
||||
[classref boost::process::v1::child child] class.
|
||||
|
||||
The [funcref boost::process::v1::spawn spawn] function launches a process and
|
||||
immediately detaches it, so no handle will be returned and the process will be ignored.
|
||||
This is not what we need for compiling, but maybe we want to entertain the user,
|
||||
while compiling:
|
||||
|
||||
```
|
||||
bp::spawn(bp::search_path("chrome"), boost_org);
|
||||
```
|
||||
|
||||
Now for the more sensible approach for compiling: a non-blocking execution.
|
||||
To implement that, we directly call the constructor of [classref boost::process::v1::child child].
|
||||
|
||||
```
|
||||
bp::child c(bp::search_path("g++"), "main.cpp");
|
||||
|
||||
while (c.child_running())
|
||||
do_some_stuff();
|
||||
|
||||
c.child_wait(); //wait for the process to exit
|
||||
int result = c.child_exit_code();
|
||||
```
|
||||
|
||||
So we launch the process, by calling the child constructor. Then we check and do other
|
||||
things while the process is running and afterwards get the exit code. The call
|
||||
to child_wait is necessary, to obtain it and tell the operating system, that no
|
||||
one is waiting for the process anymore.
|
||||
|
||||
[note You can also wait for a time span or until a time point with __wait_for__ and __wait_until__.]
|
||||
|
||||
[warning If you don't call wait on a child object, it will be terminated on destruction.
|
||||
This can be avoided by calling __detach__ beforehand]
|
||||
|
||||
[endsect]
|
||||
[section:error_handling Error]
|
||||
|
||||
Until now, we have assumed that everything works out, but it is not impossible,
|
||||
that "g++" is not present. That will cause the launch of the process to fail.
|
||||
The default behaviour of all functions is to throw a
|
||||
[@http://en.cppreference.com/w/cpp/error/system_error std::system_error] on failure.
|
||||
As with many other functions in this library, passing an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code]
|
||||
will change the behaviour, so that instead of throwing an exception, the error will be assigned to the error code.
|
||||
|
||||
```
|
||||
std::error_code ec;
|
||||
bp::system("g++ main.cpp", ec);
|
||||
```
|
||||
[endsect]
|
||||
[section:io Synchronous I/O]
|
||||
|
||||
In the examples given above, we have only started a program, but did not consider the output.
|
||||
The default depends on the system, but usually this will just write it to the same output as the launching process.
|
||||
If this shall be guaranteed, the streams can be explicitly forwarded like this.
|
||||
|
||||
```
|
||||
bp::system("g++ main.cpp", bp::std_out > stdout, bp::std_err > stderr, bp::std_in < stdin);
|
||||
```
|
||||
|
||||
Now for the first example, we might want to just ignore the output, which can be done by redirecting it to the null-device.
|
||||
This can be achieved this way:
|
||||
|
||||
```
|
||||
bp::system("g++ main.cpp", bp::std_out > bp::null);
|
||||
```
|
||||
|
||||
Alternatively we can also easily redirect the output to a file:
|
||||
|
||||
```
|
||||
bp::system("g++ main.cpp", bp::std_out > "gcc_out.log");
|
||||
```
|
||||
|
||||
Now, let's take a more visual example for reading data.
|
||||
[@http://pubs.opengroup.org/onlinepubs/009696699/utilities/nm.html nm] is a tool on posix,
|
||||
which reads the outline, i.e. a list of all entry points, of a binary.
|
||||
Every entry point will be put into a single line, and we will use a pipe to read it.
|
||||
At the end an empty line is appended, which we use as the indication to stop reading.
|
||||
Boost.process provides the pipestream ([classref boost::process::v1::ipstream ipstream],
|
||||
[classref boost::process::v1::opstream opstream], [classref boost::process::v1::pstream pstream]) to
|
||||
wrap around the [classref boost::process::v1::pipe pipe] and provide an implementation of the
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_istream std::istream],
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_ostream std::ostream] and
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_iostream std::iostream] interface.
|
||||
|
||||
```
|
||||
std::vector<std::string> read_outline(std::string & file)
|
||||
{
|
||||
bp::ipstream is; //reading pipe-stream
|
||||
bp::child c(bp::search_path("nm"), file, bp::std_out > is);
|
||||
|
||||
std::vector<std::string> data;
|
||||
std::string line;
|
||||
|
||||
while (c.child_running() && std::getline(is, line) && !line.empty())
|
||||
data.push_back(line);
|
||||
|
||||
c.child_wait();
|
||||
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
What this does is redirect the `stdout` of the process into a pipe and we read this
|
||||
synchronously.
|
||||
|
||||
[note You can do the same thing with [globalref boost::process::v1::std_err std_err].]
|
||||
|
||||
Now we get the name from `nm` and we might want to demangle it, so we use input and output.
|
||||
`nm` has a demangle option, but for the sake of the example, we'll use
|
||||
[@https://sourceware.org/binutils/docs/binutils/c_002b_002bfilt.html c++filt] for this.
|
||||
|
||||
```
|
||||
bp::opstream in;
|
||||
bp::ipstream out;
|
||||
|
||||
bp::child c("c++filt", std_out > out, std_in < in);
|
||||
|
||||
in << "_ZN5boost7process8tutorialE" << endl;
|
||||
std::string value;
|
||||
out >> value;
|
||||
|
||||
c.child_terminate();
|
||||
```
|
||||
|
||||
Now you might want to forward output from one process to another processes input.
|
||||
|
||||
```
|
||||
std::vector<std::string> read_demangled_outline(const std::string & file)
|
||||
{
|
||||
bp::pipe p;
|
||||
bp::ipstream is;
|
||||
|
||||
std::vector<std::string> outline;
|
||||
|
||||
//we just use the same pipe, so the output of nm is directly passed as input to c++filt
|
||||
bp::child nm(bp::search_path("nm"), file, bp::std_out > p);
|
||||
bp::child filt(bp::search_path("c++filt"), bp::std_in < p, bp::std_out > is);
|
||||
|
||||
std::string line;
|
||||
while (filt.running() && std::getline(is, line)) //when nm finished the pipe closes and c++filt exits
|
||||
outline.push_back(line);
|
||||
|
||||
nm.child_wait();
|
||||
filt.wait();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
This forwards the data from `nm` to `c++filt` without your process needing to do anything.
|
||||
|
||||
[endsect]
|
||||
[section:async_io Asynchronous I/O]
|
||||
|
||||
Boost.process allows the usage of boost.asio to implement asynchronous I/O.
|
||||
If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] (which we highly recommend),
|
||||
you can use [classref boost::process::v1::async_pipe async_pipe] which is implemented
|
||||
as an I/O-Object and can be used like [classref boost::process::v1::pipe pipe] as shown above.
|
||||
|
||||
Now we get back to our compiling example. For `nm` we might analyze the output line by line,
|
||||
but the compiler output will just be put into one large buffer.
|
||||
|
||||
With [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] this is what it looks like.
|
||||
|
||||
```
|
||||
io_service ios;
|
||||
std::vector<char> buf(4096);
|
||||
|
||||
bp::async_pipe ap(ios);
|
||||
|
||||
bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > ap);
|
||||
|
||||
asio_async_read(ap, asio_buffer(buf),
|
||||
[](const boost::system::error_code &ec, std::size_t size){});
|
||||
|
||||
ios.run();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
To make it easier, boost.process provides a simpler interface for that, so that the buffer can be passed directly,
|
||||
provided we also pass a reference to an io_service.
|
||||
|
||||
```
|
||||
io_service ios;
|
||||
std::vector<char> buf(4096);
|
||||
|
||||
bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > asio_buffer(buf), ios);
|
||||
|
||||
ios.run();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
[note Passing an instance of io_service to the launching function automatically cause it to wait asynchronously for the exit, so no call of
|
||||
[memberref boost::process::v1::child::wait wait] is needed.]
|
||||
|
||||
To make it even easier, you can use [@http://en.cppreference.com/w/cpp/thread/future std::future] for asynchronous operations
|
||||
(you will still need to pass a reference to a io_service) to the launching function, unless you use bp::system or bp::async_system.
|
||||
|
||||
Now we will revisit our first example and read the compiler output asynchronously:
|
||||
|
||||
```
|
||||
boost::asio::io_service ios;
|
||||
|
||||
std::future<std::string> data;
|
||||
|
||||
child c("g++", "main.cpp", //set the input
|
||||
bp::std_in.close(),
|
||||
bp::std_out > bp::null, //so it can be written without anything
|
||||
bp::std_err > data,
|
||||
ios);
|
||||
|
||||
|
||||
ios.run(); //this will actually block until the compiler is finished
|
||||
|
||||
auto err = data.get();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
[section:group Groups]
|
||||
|
||||
When launching several processes, they can be grouped together.
|
||||
This will also apply for a child process, that launches other processes,
|
||||
if they do not modify the group membership. E.g. if you call `make` which
|
||||
launches other processes and call terminate on it,
|
||||
it will not terminate all the child processes of the child unless you use a group.
|
||||
|
||||
The two main reasons to use groups are:
|
||||
|
||||
# Being able to terminate child processes of the child process
|
||||
# Grouping several processes into one, just so they can be terminated at once
|
||||
|
||||
If we have a program like `make`, which does launch its own child processes,
|
||||
a call of child_terminate might not suffice. I.e. if we have a makefile launching `gcc`
|
||||
and use the following code, the `gcc` process will still run afterwards:
|
||||
|
||||
```
|
||||
bp::child c("make");
|
||||
if (!c.child_wait_for(std::chrono::seconds(10))) //give it 10 seconds
|
||||
c.child_terminate(); //then terminate
|
||||
```
|
||||
|
||||
So in order to also terminate `gcc` we can use a group.
|
||||
|
||||
```
|
||||
bp::group g;
|
||||
bp::child c("make", g);
|
||||
if (!g.group_wait_for(std::chrono::seconds(10)))
|
||||
g.group_terminate();
|
||||
|
||||
c.child_wait(); //to avoid a zombie process & get the exit code
|
||||
```
|
||||
|
||||
Now given the example, we still call child_wait to avoid a zombie process.
|
||||
An easier solution for that might be to use [funcref boost::process::v1::spawn spawn].
|
||||
|
||||
|
||||
To put two processes into one group, the following code suffices. Spawn already
|
||||
launches a detached process (i.e. without a child-handle), but they can be grouped,
|
||||
to that in the case of a problem, RAII is still a given.
|
||||
|
||||
```
|
||||
void f()
|
||||
{
|
||||
bp::group g;
|
||||
bp::spawn("foo", g);
|
||||
bp::spawn("bar", g);
|
||||
|
||||
do_something();
|
||||
|
||||
g.group_wait();
|
||||
};
|
||||
```
|
||||
|
||||
In the example, it will wait for both processes at the end of the function unless
|
||||
an exception occurs. I.e. if an exception is thrown, the group will be terminated.
|
||||
|
||||
|
||||
Please see the [headerref boost/process/group.hpp reference] for more information.
|
||||
|
||||
[endsect]
|
||||
[section:env Environment]
|
||||
|
||||
This library provides access to the environment of the current process and allows
|
||||
setting it for the child process.
|
||||
|
||||
```
|
||||
//get a handle to the current environment
|
||||
auto env = boost::this_process::environment();
|
||||
//add a variable to the current environment
|
||||
env["VALUE_1"] = "foo";
|
||||
|
||||
//copy it into an environment separate to the one of this process
|
||||
bp::environment env_ = env;
|
||||
//append two values to a variable in the new env
|
||||
env_["VALUE_2"] += {"bar1", "bar2"};
|
||||
|
||||
//launch a process with `env_`
|
||||
bp::system("stuff", env_);
|
||||
```
|
||||
|
||||
A more convenient way to modify the environment for the child is the
|
||||
[globalref boost::process::v1::env env] property, which can be used in the example as following:
|
||||
|
||||
```
|
||||
bp::system("stuff", bp::env["VALUE_1"]="foo", bp::env["VALUE_2"]+={"bar1", "bar2"});
|
||||
|
||||
```
|
||||
|
||||
Please see the [headerref boost/process/environment.hpp reference] for more information.
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
42
doc/v1/windows_pseudocode.xml
Normal file
42
doc/v1/windows_pseudocode.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<programlisting>
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (<methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::v1::child">child</classname>();
|
||||
}
|
||||
int err_code = <ulink url="https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425.aspx">CreateProcess</ulink>(
|
||||
exe,
|
||||
cmd_line,
|
||||
proc_attrs,
|
||||
thread_attrs,
|
||||
creation_flags,
|
||||
env,
|
||||
work_dir,
|
||||
startup_info,
|
||||
proc_info);
|
||||
|
||||
<classname alt="boost::process::v1::child">child</classname> c(proc_info, exit_code);
|
||||
|
||||
if (<methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>())
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>());
|
||||
else
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_success</methodname>(*this);
|
||||
|
||||
//now we check again, because an on_success handler might've errored.
|
||||
if (<methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::v1::child">child</classname>();
|
||||
}
|
||||
else
|
||||
return c;
|
||||
|
||||
</programlisting>
|
||||
11
doc/v2.qbk
Normal file
11
doc/v2.qbk
Normal file
@@ -0,0 +1,11 @@
|
||||
[section:v2 Process V2]
|
||||
|
||||
[include v2/introduction.qbk]
|
||||
[include v2/quickstart.qbk]
|
||||
[include v2/launcher.qbk]
|
||||
[include v2/start_dir.qbk]
|
||||
[include v2/stdio.qbk]
|
||||
[include v2/env.qbk]
|
||||
[xinclude reference_v2.xml]
|
||||
|
||||
[endsect]
|
||||
48
doc/v2/env.qbk
Normal file
48
doc/v2/env.qbk
Normal file
@@ -0,0 +1,48 @@
|
||||
[section:env Environment]
|
||||
|
||||
The `environment` namespace provides all sorts of facilities to query and manipulate the environment of the current process.
|
||||
|
||||
The api should be straight forward, but one oddity that needs to be pointed out is, that environment names
|
||||
are not case sensitive on windows. The key_traits class implements the proper traits depending on the current system.
|
||||
|
||||
Additionally, environment can be lists separated by `:` or `;`; `environment::value` and
|
||||
`environment::value_view` can be used to iterate those.
|
||||
|
||||
Beyond that, the requirements on an environment are a low as possible;
|
||||
an environment is either a list of strings or a list of string-pairs. It is however recommended to use the environment types,
|
||||
as to have the right value comparisons.
|
||||
|
||||
To note is the `find_executable` functions, which searches in an environment for an executable.
|
||||
|
||||
```
|
||||
// search in the current environment
|
||||
auto exe = environment::find_executable("g++");
|
||||
|
||||
std::unordered_map<environment::key, environment::value> my_env =
|
||||
{
|
||||
{"SECRET", "THIS_IS_A_TEST"},
|
||||
{"PATH", {"/bin", "/usr/bin"}}
|
||||
};
|
||||
|
||||
auto other_exe = environment::find_executable("g++", my_env);
|
||||
```
|
||||
|
||||
[section:process_env Subprocess environment]
|
||||
|
||||
The subprocess environment assignment follows the same constraints:
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
std::unordered_map<environment::key, environment::value> my_env =
|
||||
{
|
||||
{"SECRET", "THIS_IS_A_TEST"},
|
||||
{"PATH", {"/bin", "/usr/bin"}}
|
||||
};
|
||||
auto exe = find_executable("g++");
|
||||
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
|
||||
process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env));
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
86
doc/v2/introduction.qbk
Normal file
86
doc/v2/introduction.qbk
Normal file
@@ -0,0 +1,86 @@
|
||||
[section:introduction Introduction]
|
||||
|
||||
Boost.process V2 is an redesign of boost.process, based on previous
|
||||
design mistakes & improved system APIs.
|
||||
|
||||
The major changes are
|
||||
|
||||
* Simplified interface
|
||||
* Reliance on pidfd_open on linux
|
||||
* Full asio integration
|
||||
* Removed unreliable functionality
|
||||
* UTF8 Support
|
||||
* separate compilation
|
||||
* fd safe by default
|
||||
|
||||
[section:simplified Simplified Interface]
|
||||
|
||||
In process v1 one can define partial settings in the constructor of the process,
|
||||
which has lead to a small DSL.
|
||||
|
||||
child c{exe="test", args+="--help", std_in < null(), env["FOO"] += "BAR"};
|
||||
|
||||
While this looks fancy at first, it really does not scale well with more parameters.
|
||||
For process v2, the interfaces is simple:
|
||||
|
||||
extern std::unordered_map<std::string, std::string> my_env;
|
||||
extern asio::io_context ctx;
|
||||
process proc(ctx, "./test", {"--help"}, process_io{nullptr, {}, {}}, process_environment(my_env));
|
||||
|
||||
Every initializer addresses one logical component (e.g. stdio) instead of multiple ones accumulating.
|
||||
Furthermore, every process has a path and arguments, instead of a confusing mixture of cmd-style and
|
||||
exe-args that can be randomly spread out.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:pidfd_open pidfd_open]
|
||||
|
||||
Since process v1 came out, linux has moved along and added pidfd_open which allows users to get a
|
||||
file descriptor for a process. This is much more reliable since it is not as easy to miss as a `SIGCHLD`.
|
||||
FreeBSD has a similar feature with `pdfork` which is also supported, while windows has provided `HANDLE`s
|
||||
for processes all along.
|
||||
Unless the OS doesn't support it, process v2 will use file descriptors and handles to implement waiting
|
||||
for processes.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:asio Full asio integration]
|
||||
|
||||
Process v1 aimed to make asio optional, but synchronous IO with subprocesses usually means one is begging
|
||||
for deadlocks.
|
||||
Since asio added pipes in boost 1.78, boost process V2 is fully asio based and uses it's pipes and
|
||||
file-handles for the subprocess.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:unreliable Unreliable functionality]
|
||||
|
||||
Certain parts of boost.process were not as reliable as they should've been.
|
||||
|
||||
This concerns especially the `wait_for` and `wait_until` functions on the process.
|
||||
The latter are easy to do on windows, but posix does not provide an API for this.
|
||||
Thus the wait_for used signals or fork, which was all but safe.
|
||||
Since process v2 is based on asio and thus supports cancellation,
|
||||
a wait_for can not safely be implemented with an async_wait + timeout.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:utf8 UTF-8]
|
||||
|
||||
["UTF-8 or GTFO]--Vinnie Falco
|
||||
|
||||
Instead of using ascii-APIs on windows, process V2 just assumes UTF-8 everywhere.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:limit_fd Fd safe by default]
|
||||
|
||||
While not a problem on windows (since HANDLEs get manually enabled for inheritance),
|
||||
posix systems create a problem with inheriting file handles by default.
|
||||
|
||||
Process V2 will automatically close all non-whitelisted descriptors,
|
||||
without needing any option to enable it.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
128
doc/v2/launcher.qbk
Normal file
128
doc/v2/launcher.qbk
Normal file
@@ -0,0 +1,128 @@
|
||||
[section:launchers Launcher]
|
||||
|
||||
The process creation is done by a process_launcher.
|
||||
The constructor of `process` will use the default_launcher, which varies by system.
|
||||
There are additional launcher available on most systems.
|
||||
|
||||
[table:launchers Launcher overview
|
||||
[[Name] [Summary] [Default on] [Available on]]
|
||||
[[`windows::default_launcher`] [Launcher using `CreateProcessW`] [windows] [windows]]
|
||||
[[`windows::as_user_launcher`] [Launcher using `CreateProcessAsUserW`] [] [windows]]
|
||||
[[`windows::with_logon_launcher`] [Launcher using `CreateProcessWithLogonW`] [] [windows]]
|
||||
[[`windows::with_token_launcher`] [Launcher using `CreateProcessWithTokenW`] [] [windows]]
|
||||
[[`posix::default_launcher`] [Launcher using fork & an error pipe] [most of posix] [posix]]
|
||||
[[`posix::fork_and_forget`] [Launcher using fork without error pipe] [] [posix]]
|
||||
[[`posix::pdfork_launcher`] [Launcher using pdfork with an error pipe] [FreeBSD] [FreeBSD]]
|
||||
[[`posix::vfork_launcher`] [Launcher using vfork] [] [posix]]
|
||||
]
|
||||
|
||||
A launcher is invoked through the call operator.
|
||||
|
||||
```
|
||||
auto l = windows::as_user_launcher((HANDLE)0xDEADBEEF);
|
||||
asio::io_context ctx;
|
||||
boost::system::error_code ec;
|
||||
auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {});
|
||||
```
|
||||
|
||||
The launcher will call certain functions on the initializer if they're present, as documented below.
|
||||
The initializer are used to modify the process behaviour.
|
||||
|
||||
[section:linux Linux Launchers]
|
||||
|
||||
The default and pdfork launchers on linux open an internal pipe to communicate errors that occur after forking back to the parent process.
|
||||
|
||||
This can be prevented by using the `fork_and_forget_launcher`.
|
||||
Alternatively, the `vfork_launcher` can report errors directly back to the parent process.
|
||||
|
||||
Thus some calls to the initializers occur after forking from the child process.
|
||||
|
||||
```
|
||||
struct custom_initializer
|
||||
{
|
||||
// functions called from the parent process:
|
||||
|
||||
|
||||
// called before a call to fork. A returned error will cancel the launch.
|
||||
template<typename Launcher>
|
||||
error_code on_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
// called for every initializer if an error occurred during setup or process creation
|
||||
template<typename Launcher>
|
||||
void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
|
||||
const error_code & ec);
|
||||
|
||||
// called after successful process creation
|
||||
template<typename Launcher>
|
||||
void on_success(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
// called for every initializer if an error occurred when forking, in addition to on_error.
|
||||
template<typename Launcher>
|
||||
void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
|
||||
const error_code & ec);
|
||||
|
||||
|
||||
// called before a call to execve. A returned error will cancel the launch. Called from the child process.
|
||||
template<typename Launcher>
|
||||
error_code on_exec_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
|
||||
// called after a failed call to execve from the child process.
|
||||
template<typename Launcher>
|
||||
void on_exec_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
};
|
||||
```
|
||||
|
||||
The call sequence on success:
|
||||
'''
|
||||
<imagedata fileref="boost_process/posix_success.svg"/>
|
||||
'''
|
||||
|
||||
The call sequence when fork fails:
|
||||
'''
|
||||
<imagedata fileref="boost_process/posix_fork_err.svg"/>
|
||||
'''
|
||||
|
||||
The call sequence when exec fails:
|
||||
'''
|
||||
<imagedata fileref="boost_process/posix_exec_err.svg"/>
|
||||
'''
|
||||
|
||||
The launcher will close all non-whitelisted file descriptors after `on_exec_setup`.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:windows Windows Launchers]
|
||||
|
||||
Windows launchers are pretty straight forward, they will call the following functions on the initializer if present.
|
||||
|
||||
```
|
||||
struct custom_initializer
|
||||
{
|
||||
// called before a call to CreateProcess. A returned error will cancel the launch.
|
||||
template<typename Launcher>
|
||||
error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
|
||||
|
||||
// called for every initializer if an error occurred during setup or process creation
|
||||
template<typename Launcher>
|
||||
void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
|
||||
const error_code & ec);
|
||||
|
||||
// called after successful process creation
|
||||
template<typename Launcher>
|
||||
void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
[note All the additional launchers for windows inherit `default_launcher`]
|
||||
|
||||
The call sequence is as follows:
|
||||
'''
|
||||
<imagedata fileref="boost_process/windows_exec.svg"/>
|
||||
'''
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
123
doc/v2/quickstart.qbk
Normal file
123
doc/v2/quickstart.qbk
Normal file
@@ -0,0 +1,123 @@
|
||||
[section:quickstart Quickstart]
|
||||
|
||||
A process needs four things to be launched:
|
||||
|
||||
* an asio execution_context / executor
|
||||
* a path to an executable
|
||||
* a list of arguments
|
||||
* a variadic set of initializers
|
||||
|
||||
```
|
||||
// process(asio::any_io_executor, filesystem::path, range<string> args, AdditionalInitializers...)
|
||||
asio::io_context ctx;
|
||||
process proc(ctx, "/usr/bin/cp", {"source.txt", "target.txt"});
|
||||
```
|
||||
|
||||
|
||||
The started process can then be awaited or terminated.
|
||||
|
||||
[section:lifetime Lifetime]
|
||||
|
||||
If the process handle goes out of scope, it will terminate the subprocess.
|
||||
You can prevent this, by calling `proc.detach()`; do however note that this
|
||||
can lead to zombie processes.
|
||||
|
||||
A process that completed will deliver an exit-code,
|
||||
which can be obtained by calling `.exit_code` on the exited process and which is
|
||||
also returned from `.wait()`.
|
||||
|
||||
```
|
||||
process proc("/bin/ls", {});
|
||||
assert(proc.wait() == 0);
|
||||
```
|
||||
|
||||
The normal exit-code is what the subprocess returned from `main`;
|
||||
posix will however add additional information about the process.
|
||||
This is called the `native_exit_code`.
|
||||
|
||||
|
||||
The `.running()` function can be used to detect if the process is still active.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:signal Signalling the subprocess]
|
||||
|
||||
The parent process can signal the subprocess demanding certain actions.
|
||||
|
||||
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
|
||||
This is the only reliable & portable way to end a subprocess.
|
||||
|
||||
```
|
||||
process proc("/bin/totally-not-a-virus", {});
|
||||
proc.terminate();
|
||||
```
|
||||
|
||||
`.request_exit` will ask the subprocess to shutdown (`SIGTERM` on posix),
|
||||
which the subprocess might ignore.
|
||||
|
||||
```
|
||||
process proc("/bin/bash", {});
|
||||
proc.request_exit();
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
`.interrupt` will send an SIGINT to the subprocess, which a subprocess might
|
||||
interpret as a signal to shutdown.
|
||||
|
||||
[warning interrupt requires the initializer `windows::create_new_process_group` to be set]
|
||||
|
||||
```
|
||||
process proc("/usr/bin/addr2line", {});
|
||||
proc.request_exit();
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:execute Execute functions]
|
||||
|
||||
Process v2 provides `execute` and `async_execute` functions that can be used for managed executions.
|
||||
|
||||
```
|
||||
assert(execute(process("/bin/ls", {}) == 0));
|
||||
```
|
||||
|
||||
The async version supports cancellation and will forward cancellation types as follows:
|
||||
|
||||
- asio::cancellation_type::total -> interrupt
|
||||
- asio::cancellation_type::partial -> request_exit
|
||||
- asio::cancellation_type::terminal -> terminate
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
asio::steady_timer timeout{ctx, std::chrono::seconds(10)};
|
||||
|
||||
asio::cancellation_signal sig;
|
||||
async_execute(process("/usr/bin/g++", {"hello_world.cpp"}),
|
||||
asio::bind_cancellation_slot(sig.slot(),
|
||||
[&](error_code ec, int exit_code)
|
||||
{
|
||||
timeout.cancel(); // we're done earlier
|
||||
}));
|
||||
|
||||
timeout.async_wait(
|
||||
[&](error_code ec)
|
||||
{
|
||||
if (ec) // we were cancelled, do nothing
|
||||
return ;
|
||||
sig.emit(asio::cancellation_type::partial);
|
||||
// request exit first, but terminate after another 10 sec
|
||||
timeout.expires_after(std::chrono::seconds(10));
|
||||
timeout.async_wait(
|
||||
[&](error_code ec)
|
||||
{
|
||||
if (!ec)
|
||||
sig.emit(asio::cancellation_type::terminal);
|
||||
});
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
16
doc/v2/start_dir.qbk
Normal file
16
doc/v2/start_dir.qbk
Normal file
@@ -0,0 +1,16 @@
|
||||
[section:start_dir process_start_dir]
|
||||
|
||||
The easier initializer to use is `process_start_dir`:
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
process ls(ctx, "/ls", {}, process_start_dir("/home"));
|
||||
ls.wait();
|
||||
```
|
||||
|
||||
This will run `ls` in the folder `/home` instead of the current folder.
|
||||
|
||||
[warning If your path is relative, it may fail on posix, because the directory is changed before a call to execve.]
|
||||
|
||||
|
||||
[endsect]
|
||||
89
doc/v2/stdio.qbk
Normal file
89
doc/v2/stdio.qbk
Normal file
@@ -0,0 +1,89 @@
|
||||
[section:stdio stdio]
|
||||
|
||||
When using io with a subprocess, all three standard streams (stdin, stdout, stderr) get set for the child-process.
|
||||
The default setting is to inherit the parent process.
|
||||
|
||||
This feature meant to be flexible, which is why there is little checking on the arguments assigned to one of those streams.
|
||||
|
||||
[section:pipe Pipe]
|
||||
|
||||
asio pipes can be used for io. When using in process_stdio they will get
|
||||
automatically connected and the other side will get assigned to the child process:
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
asio::readable_pipe rp{ctx};
|
||||
|
||||
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }});
|
||||
std::string output;
|
||||
|
||||
system::error_code ec;
|
||||
rp.read(asio::dynamic_buffer(output), ec);
|
||||
assert(ec == asio::eof);
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
readable pipes can be assigned to `out` an `err`, while writable_pipes can be assigned to `in`.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:file `FILE*`]
|
||||
|
||||
`FILE*` can also be used for either side; this allows the `stdin`, `stderr`, `stdout` macros to be used:
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
// forward both stderr & stdout to stdout of the parent process
|
||||
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, stdout, stdout});
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:null `nullptr`]
|
||||
|
||||
`nullptr` may be used to set a given stream to be opened on the null-device (`/dev/null` on posix, `NUL` on windows).
|
||||
This is used to ignore output or give only EOF as input.
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
// ignore stderr
|
||||
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, {}, nullptr});
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:native_handle `native_handle`]
|
||||
|
||||
A native handle can be used as well, which means an `int` on posix or a `HANDLE` on windows.
|
||||
Furthermore, any object that has a `native_handle` returning that native handle type is valid, too.
|
||||
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
// ignore stderr
|
||||
asio::ip::tcp::socket sock{ctx};
|
||||
connect_my_socket(sock);
|
||||
process proc(ctx, "~/not-a-virus", {}, process_stdio{sock, sock, nullptr});
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:popen popen]
|
||||
|
||||
Additionally, process v2 provides a `popen` class.
|
||||
It starts a process and connects pipes for stdin and stdout, so that the popen object can be used as a stream.
|
||||
|
||||
```
|
||||
popen proc(executor, "/usr/bin/addr2line, {argv[0]});
|
||||
asio::write(proc, asio::buffer("main\n"));
|
||||
std::string line;
|
||||
asio::read_until(proc, asio::dynamic_buffer(line), '\n');
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
@@ -8,7 +8,7 @@
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
project : requirements
|
||||
<include>../../..
|
||||
<library>/boost/process//boost_process
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
;
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::io_context ios;
|
||||
boost::asio::streambuf buffer;
|
||||
|
||||
|
||||
|
||||
@@ -10,12 +10,15 @@
|
||||
//[intro
|
||||
#include <boost/process.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
using namespace boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
ipstream pipe_stream;
|
||||
child c("gcc.exe", "--version", std_out > pipe_stream);
|
||||
child c("gcc --version", std_out > pipe_stream);
|
||||
|
||||
std::string line;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ int main()
|
||||
bp::std_in < bp::null //null in
|
||||
);
|
||||
|
||||
boost::filesystem::path p = "input.txt";
|
||||
boost::process::v1::filesystem::path p = "input.txt";
|
||||
|
||||
bp::system(
|
||||
"test.exe",
|
||||
@@ -44,14 +44,14 @@ int main()
|
||||
|
||||
}
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
bp::async_pipe p1(io_service);
|
||||
bp::async_pipe p2(io_service);
|
||||
boost::asio::io_context io_context;
|
||||
bp::async_pipe p1(io_context);
|
||||
bp::async_pipe p2(io_context);
|
||||
bp::system(
|
||||
"test.exe",
|
||||
bp::std_out > p2,
|
||||
bp::std_in < p1,
|
||||
io_service,
|
||||
io_context,
|
||||
bp::on_exit([&](int exit, const std::error_code& ec_in)
|
||||
{
|
||||
p1.async_close();
|
||||
@@ -64,7 +64,7 @@ int main()
|
||||
boost::asio::async_read (p2, boost::asio::buffer(in_buf), []( const boost::system::error_code&, std::size_t){});
|
||||
}
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::io_context io_context;
|
||||
std::vector<char> in_buf;
|
||||
std::string value = "my_string";
|
||||
bp::system(
|
||||
@@ -75,7 +75,7 @@ int main()
|
||||
}
|
||||
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::io_context io_context;
|
||||
std::future<std::vector<char>> in_buf;
|
||||
std::future<void> write_fut;
|
||||
std::string value = "my_string";
|
||||
|
||||
@@ -8,38 +8,39 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/process/posix.hpp>
|
||||
#include <boost/process/v1/posix.hpp>
|
||||
#include <boost/process/v1/extend.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
using namespace boost::process;
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
//duplicate our pipe descriptor into literal position 4
|
||||
pipe p;
|
||||
system("test", posix::fd.bind(4, p.native_sink()) );
|
||||
bp::pipe p;
|
||||
bp::system("test", bp::posix::fd.bind(4, p.native_sink()));
|
||||
|
||||
|
||||
//close file-descriptor from explicit integral value
|
||||
system("test", posix::fd.close(STDIN_FILENO));
|
||||
bp::system("test", bp::posix::fd.close(STDIN_FILENO));
|
||||
|
||||
//close file-descriptors from explicit integral values
|
||||
system("test", posix::fd.close({STDIN_FILENO, STDOUT_FILENO}));
|
||||
bp::system("test", bp::posix::fd.close({STDIN_FILENO, STDOUT_FILENO}));
|
||||
|
||||
//add custom handlers
|
||||
const char *env[2] = { 0 };
|
||||
env[0] = "LANG=de";
|
||||
system("test",
|
||||
on_setup([env](auto &e) { e.env = const_cast<char**>(env); }),
|
||||
posix::on_fork_error([](auto&)
|
||||
bp::system("test",
|
||||
bp::extend::on_setup([env](auto &e) { e.env = const_cast<char**>(env); }),
|
||||
bp::extend::on_fork_error([](auto&, const std::error_code & ec)
|
||||
{ std::cerr << errno << std::endl; }),
|
||||
posix::on_exec_setup([](auto&)
|
||||
bp::extend::on_exec_setup([](auto&)
|
||||
{ ::chroot("/new/root/directory/"); }),
|
||||
posix::on_exec_error([](auto&)
|
||||
bp::extend::on_exec_error([](auto&, const std::error_code & ec)
|
||||
{ std::ofstream ofs("log.txt"); if (ofs) ofs << errno; })
|
||||
);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
@@ -19,9 +19,9 @@ int main()
|
||||
bp::start_dir="../foo"
|
||||
);
|
||||
|
||||
boost::filesystem::path exe = "test.exe";
|
||||
boost::process::v1::filesystem::path exe = "test.exe";
|
||||
bp::system(
|
||||
boost::filesystem::absolute(exe),
|
||||
boost::process::v1::filesystem::absolute(exe),
|
||||
bp::start_dir="../foo"
|
||||
);
|
||||
}
|
||||
|
||||
15
example/v2/Jamfile.jam
Normal file
15
example/v2/Jamfile.jam
Normal file
@@ -0,0 +1,15 @@
|
||||
# Copyright (c) 2022 Klemens Morgenstern
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
project : requirements
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<link>static
|
||||
;
|
||||
|
||||
import testing ;
|
||||
|
||||
exe intro : intro.cpp ;
|
||||
exe intro_popen : intro_popen.cpp : <boost.process.fs>boost ;
|
||||
39
example/v2/intro.cpp
Normal file
39
example/v2/intro.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2022 Klemens Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
//[intro
|
||||
#include <boost/process/v2.hpp>
|
||||
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/readable_pipe.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace proc = boost::process::v2;
|
||||
namespace asio = boost::asio;
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
asio::io_context ctx;
|
||||
asio::readable_pipe p{ctx};
|
||||
|
||||
const auto exe = proc::environment::find_executable("gcc");
|
||||
|
||||
proc::process c{ctx, exe, {"--version"}, proc::process_stdio{nullptr, p}};
|
||||
|
||||
std::string line;
|
||||
boost::system::error_code ec;
|
||||
|
||||
auto sz = asio::read(p, asio::dynamic_buffer(line), ec);
|
||||
assert(ec == asio::error::eof);
|
||||
|
||||
std::cout << "Gcc version: '" << line << "'" << std::endl;
|
||||
|
||||
c.wait();
|
||||
}
|
||||
//]
|
||||
36
example/v2/intro_popen.cpp
Normal file
36
example/v2/intro_popen.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2022Klemens Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
//[intro
|
||||
#include <boost/process/v2.hpp>
|
||||
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/readable_pipe.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace proc = boost::process::v2;
|
||||
namespace asio = boost::asio;
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
asio::io_context ctx;
|
||||
const auto exe = proc::environment::find_executable("gcc");
|
||||
proc::popen c{ctx, exe, {"--version"}};
|
||||
|
||||
std::string line;
|
||||
boost::system::error_code ec;
|
||||
|
||||
auto sz = asio::read(c, asio::dynamic_buffer(line), ec);
|
||||
assert(ec == asio::error::eof);
|
||||
|
||||
std::cout << "Gcc version: '" << line << "'" << std::endl;
|
||||
|
||||
c.wait();
|
||||
}
|
||||
//]
|
||||
@@ -21,14 +21,14 @@ int main()
|
||||
}
|
||||
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::io_context io_context;
|
||||
|
||||
bp::child c(
|
||||
"test.exe",
|
||||
io_service,
|
||||
io_context,
|
||||
bp::on_exit([&](int exit, const std::error_code& ec_in){})
|
||||
);
|
||||
|
||||
io_service.run();
|
||||
io_context.run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/process/windows.hpp>
|
||||
#include <boost/process/v1/extend.hpp>
|
||||
#include <boost/process/v1/windows.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include <windows.h>
|
||||
@@ -22,9 +23,9 @@ int main()
|
||||
|
||||
|
||||
bp::system("test.exe",
|
||||
bp::on_setup([](auto &e)
|
||||
bp::extend::on_setup([](auto &e)
|
||||
{ e.startup_info.dwFlags = STARTF_RUNFULLSCREEN; }),
|
||||
bp::on_error([](auto&, const std::error_code & ec)
|
||||
bp::extend::on_error([](auto&, const std::error_code & ec)
|
||||
{ std::cerr << ec.message() << std::endl; })
|
||||
);
|
||||
}
|
||||
|
||||
14
filter_section_warning.py
Normal file
14
filter_section_warning.py
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
for line in sys.stdin:
|
||||
# If line is a 'noisy' warning, don't print it or the following two lines.
|
||||
if ('warning: section' in line and 'is deprecated' in line
|
||||
or 'note: change section name to' in line):
|
||||
next(sys.stdin)
|
||||
next(sys.stdin)
|
||||
else:
|
||||
sys.stdout.write(line)
|
||||
sys.stdout.flush()
|
||||
@@ -19,22 +19,16 @@
|
||||
* boost.process header files.
|
||||
*/
|
||||
|
||||
#include <boost/process/args.hpp>
|
||||
#include <boost/process/async.hpp>
|
||||
#include <boost/process/group.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/cmd.hpp>
|
||||
#include <boost/process/env.hpp>
|
||||
#include <boost/process/environment.hpp>
|
||||
#include <boost/process/error.hpp>
|
||||
#include <boost/process/exe.hpp>
|
||||
#include <boost/process/group.hpp>
|
||||
#include <boost/process/io.hpp>
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/shell.hpp>
|
||||
#include <boost/process/search_path.hpp>
|
||||
#include <boost/process/spawn.hpp>
|
||||
#include <boost/process/system.hpp>
|
||||
#include <boost/process/start_dir.hpp>
|
||||
#if !defined(BOOST_PROCESS_VERSION)
|
||||
#define BOOST_PROCESS_VERSION 1
|
||||
#endif
|
||||
|
||||
#if BOOST_PROCESS_VERSION == 1
|
||||
#include <boost/process/v1.hpp>
|
||||
#elif BOOST_PROCESS_VERSION == 2
|
||||
#include <boost/process/v2.hpp>
|
||||
#else
|
||||
#error "Unknown boost process version"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,279 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_ARGS_HPP
|
||||
#define BOOST_PROCESS_ARGS_HPP
|
||||
|
||||
/** \file boost/process/args.hpp
|
||||
*
|
||||
* This header provides the \xmlonly <globalname alt="boost::process::args">args</globalname>\endxmlonly property. It also provides the
|
||||
* alternative name \xmlonly <globalname alt="boost::process::argv">argv</globalname>\endxmlonly .
|
||||
*
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::args">args</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::argv">argv</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
|
||||
#include <boost/process/detail/basic_cmd.hpp>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct args_
|
||||
{
|
||||
template<typename T>
|
||||
using remove_reference_t = typename std::remove_reference<T>::type;
|
||||
template<typename T>
|
||||
using value_type = typename remove_reference_t<T>::value_type;
|
||||
|
||||
template<typename T>
|
||||
using vvalue_type = value_type<value_type<T>>;
|
||||
|
||||
template <class Range>
|
||||
arg_setter_<vvalue_type<Range>, true> operator()(Range &&range) const
|
||||
{
|
||||
return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range));
|
||||
}
|
||||
template <class Range>
|
||||
arg_setter_<vvalue_type<Range>, true> operator+=(Range &&range) const
|
||||
{
|
||||
return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range));
|
||||
}
|
||||
template <class Range>
|
||||
arg_setter_<vvalue_type<Range>, false> operator= (Range &&range) const
|
||||
{
|
||||
return arg_setter_<vvalue_type<Range>, false>(std::forward<Range>(range));
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(std::basic_string<Char> && str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(std::basic_string<Char> && str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (std::basic_string<Char> && str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(const std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(const std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (const std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(const Char* str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(const Char* str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (const Char* str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
// template<typename Char, std::size_t Size>
|
||||
// arg_setter_<Char, true> operator()(const Char (&str) [Size]) const
|
||||
// {
|
||||
// return arg_setter_<Char, true> (str);
|
||||
// }
|
||||
// template<typename Char, std::size_t Size>
|
||||
// arg_setter_<Char, true> operator+=(const Char (&str) [Size]) const
|
||||
// {
|
||||
// return arg_setter_<Char, true> (str);
|
||||
// }
|
||||
// template<typename Char, std::size_t Size>
|
||||
// arg_setter_<Char, false> operator= (const Char (&str) [Size]) const
|
||||
// {
|
||||
// return arg_setter_<Char, false>(str);
|
||||
// }
|
||||
|
||||
arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator+=(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator()(std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator+=(std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
|
||||
arg_setter_<wchar_t, true> operator()(std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator+=(std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator()(std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator+=(std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
|
||||
The `args` property allows to explicitly set arguments for the execution. The
|
||||
name of the executable will always be the first element in the arg-vector.
|
||||
|
||||
\section args_details Details
|
||||
|
||||
\subsection args_operations Operations
|
||||
|
||||
\subsubsection args_set_var Setting values
|
||||
|
||||
To set a the argument vector the following syntax can be used.
|
||||
|
||||
\code{.cpp}
|
||||
args = value;
|
||||
args(value);
|
||||
\endcode
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
\code{.cpp}
|
||||
args = {value1, value2};
|
||||
args({value1, value2});
|
||||
\endcode
|
||||
|
||||
Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`.
|
||||
|
||||
\paragraph args_set_var_value value
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type * `
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
Additionally any range of `std::basic_string<char_type>` can be passed.
|
||||
|
||||
\subsubsection args_append_var Appending values
|
||||
|
||||
To append a the argument vector the following syntax can be used.
|
||||
|
||||
\code{.cpp}
|
||||
args += value;
|
||||
\endcode
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
\code{.cpp}
|
||||
args += {value1, value2};
|
||||
\endcode
|
||||
|
||||
Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`.
|
||||
|
||||
\paragraph args_append_var_value value
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type * `
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
Additionally any range of `std::basic_string<char_type>` can be passed.
|
||||
|
||||
|
||||
\subsection args_example Example
|
||||
|
||||
The overload form is used when more than one string is passed, from the second one forward.
|
||||
I.e. the following expressions have the same results:
|
||||
|
||||
\code{.cpp}
|
||||
spawn("gcc", "--version");
|
||||
spawn("gcc", args ="--version");
|
||||
spawn("gcc", args+="--version");
|
||||
spawn("gcc", args ={"--version"});
|
||||
spawn("gcc", args+={"--version"});
|
||||
\endcode
|
||||
|
||||
\note A string will be parsed and set in quotes if it has none and contains spaces.
|
||||
|
||||
|
||||
*/
|
||||
constexpr boost::process::detail::args_ args{};
|
||||
|
||||
///Alias for \xmlonly <globalname alt="boost::process::args">args</globalname> \endxmlonly .
|
||||
constexpr boost::process::detail::args_ argv{};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/args.hpp>")
|
||||
#include <boost/process/v1/args.hpp>
|
||||
|
||||
@@ -1,121 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/** \file boost/process/async.hpp
|
||||
|
||||
The header which provides the basic asynchrounous features.
|
||||
It provides the on_exit property, which allows callbacks when the process exits.
|
||||
It also implements the necessary traits for passing an boost::asio::io_service,
|
||||
which is needed for asynchronous communication.
|
||||
|
||||
It also pulls the [boost::asio::buffer](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html)
|
||||
into the boost::process namespace for convenience.
|
||||
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <ulink url="http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/buffer.html">buffer</ulink>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::on_exit">on_exit</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_HPP_
|
||||
#define BOOST_PROCESS_ASYNC_HPP_
|
||||
|
||||
#include <boost/process/detail/traits.hpp>
|
||||
#include <boost/process/detail/on_exit.hpp>
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <type_traits>
|
||||
#include <boost/fusion/iterator/deref.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/io_service_ref.hpp>
|
||||
#include <boost/process/detail/posix/async_in.hpp>
|
||||
#include <boost/process/detail/posix/async_out.hpp>
|
||||
#include <boost/process/detail/posix/on_exit.hpp>
|
||||
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/io_service_ref.hpp>
|
||||
#include <boost/process/detail/windows/async_in.hpp>
|
||||
#include <boost/process/detail/windows/async_out.hpp>
|
||||
#include <boost/process/detail/windows/on_exit.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct async_tag;
|
||||
|
||||
template<typename T>
|
||||
struct is_io_service : std::false_type {};
|
||||
template<>
|
||||
struct is_io_service<api::io_service_ref> : std::true_type {};
|
||||
|
||||
template<typename Tuple>
|
||||
inline asio::io_service& get_io_service(const Tuple & tup)
|
||||
{
|
||||
auto& ref = *boost::fusion::find_if<is_io_service<boost::mpl::_>>(tup);
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
struct async_builder
|
||||
{
|
||||
boost::asio::io_service * ios;
|
||||
|
||||
void operator()(boost::asio::io_service & ios_) {this->ios = &ios_;};
|
||||
|
||||
typedef api::io_service_ref result_type;
|
||||
api::io_service_ref get_initializer() {return api::io_service_ref (*ios);};
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<async_tag>
|
||||
{
|
||||
typedef async_builder type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using ::boost::asio::buffer;
|
||||
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/** When an io_service is passed, the on_exit property can be used, to be notified
|
||||
when the child process exits.
|
||||
|
||||
|
||||
The following syntax is valid
|
||||
|
||||
\code{.cpp}
|
||||
on_exit=function;
|
||||
on_exit(function);
|
||||
\endcode
|
||||
|
||||
with `function` being a callable object with the signature `(int, const std::error_code&)`.
|
||||
|
||||
\par Example
|
||||
|
||||
\code{.cpp}
|
||||
io_service ios;
|
||||
spawn("ls", on_exit=[](int exit, const std::error_code& ec_in){});
|
||||
\endcode
|
||||
|
||||
*/
|
||||
constexpr static ::boost::process::detail::on_exit_ on_exit{};
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ASYNC_HPP_ */
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/async.hpp>")
|
||||
#include <boost/process/v1/async.hpp>
|
||||
|
||||
@@ -1,219 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_PIPE_HPP
|
||||
#define BOOST_PROCESS_ASYNC_PIPE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/async_pipe.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/async_pipe.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
|
||||
|
||||
/** Class implementing and asnychronous I/O-Object for use with boost.asio.
|
||||
* It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or
|
||||
* boost::asio::posix::stream_descriptor.
|
||||
*
|
||||
* It can be used directly with boost::asio::async_read or async_write.
|
||||
*
|
||||
* \note The object is copyable, but that does invoke a handle duplicate.
|
||||
*/
|
||||
class async_pipe
|
||||
{
|
||||
public:
|
||||
/** Typedef for the native handle representation.
|
||||
* \note This is the handle on the system, not the boost.asio class.
|
||||
*
|
||||
*/
|
||||
typedef platform_specific native_handle_type;
|
||||
/** Typedef for the handle representation of boost.asio.
|
||||
*
|
||||
*/
|
||||
typedef platform_specific handle_type;
|
||||
|
||||
/** Construct a new async_pipe, does automatically open the pipe.
|
||||
* Initializes source and sink with the same io_service.
|
||||
* @note Windows creates a named pipe here, where the name is automatically generated.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_service & ios);
|
||||
|
||||
/** Construct a new async_pipe, does automatically open the pipe.
|
||||
* @note Windows creates a named pipe here, where the name is automatically generated.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_service & ios_source,
|
||||
boost::asio::io_service & ios_sink);
|
||||
|
||||
/** Construct a new async_pipe, does automatically open.
|
||||
* Initializes source and sink with the same io_service.
|
||||
*
|
||||
* @note Windows restricts possible names.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_service & ios, const std::string & name);
|
||||
|
||||
|
||||
/** Construct a new async_pipe, does automatically open.
|
||||
*
|
||||
* @note Windows restricts possible names.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_service & ios_source,
|
||||
boost::asio::io_service & ios_sink, const std::string & name);
|
||||
|
||||
/** Copy-Constructor of the async pipe.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
async_pipe(const async_pipe& lhs);
|
||||
|
||||
/** Move-Constructor of the async pipe.
|
||||
*/
|
||||
async_pipe(async_pipe&& lhs);
|
||||
|
||||
/** Construct the async-pipe from a pipe.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p);
|
||||
|
||||
/** Construct the async-pipe from a pipe, with two different io_service objects.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(boost::asio::io_service & ios_source,
|
||||
boost::asio::io_service & ios_sink,
|
||||
const basic_pipe<CharT, Traits> & p);
|
||||
|
||||
|
||||
/** Assign a basic_pipe.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
|
||||
|
||||
/** Copy Assign a pipe.
|
||||
* @note Duplicates the handles.
|
||||
*/
|
||||
async_pipe& operator=(const async_pipe& lhs);
|
||||
/** Move assign a pipe */
|
||||
async_pipe& operator=(async_pipe&& lhs);
|
||||
|
||||
/** Destructor. Closes the pipe handles. */
|
||||
~async_pipe();
|
||||
|
||||
/** Explicit cast to basic_pipe. */
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline explicit operator basic_pipe<CharT, Traits>() const;
|
||||
|
||||
/** Cancel the current asynchronous operations. */
|
||||
void cancel();
|
||||
/** Close the pipe handles. */
|
||||
void close();
|
||||
/** Close the pipe handles. While passing an error_code
|
||||
*
|
||||
*/
|
||||
void close(std::error_code & ec);
|
||||
|
||||
/** Check if the pipes are open. */
|
||||
bool is_open() const;
|
||||
|
||||
/** Async close, i.e. close after current operation is completed.
|
||||
*
|
||||
* \note There is no guarantee that this will indeed read the entire pipe-buffer
|
||||
*/
|
||||
void async_close();
|
||||
|
||||
/** Read some data from the handle.
|
||||
|
||||
* See the boost.asio documentation for more details.
|
||||
*/
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence & buffers);
|
||||
|
||||
/** Write some data to the handle.
|
||||
|
||||
* See the boost.asio documentation for more details.
|
||||
*/
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t write_some(const MutableBufferSequence & buffers);
|
||||
|
||||
/** Get the native handle of the source. */
|
||||
native_handle native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();}
|
||||
/** Get the native handle of the sink. */
|
||||
native_handle native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();}
|
||||
|
||||
/** Start an asynchronous read.
|
||||
|
||||
* See the boost.asio documentation for more details.
|
||||
*/
|
||||
template<typename MutableBufferSequence,
|
||||
typename ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
ReadHandler, void(boost::system::error_code, std::size_t))
|
||||
async_read_some(
|
||||
const MutableBufferSequence & buffers,
|
||||
ReadHandler &&handler);
|
||||
|
||||
/** Start an asynchronous write.
|
||||
|
||||
* See the boost.asio documentation for more details.
|
||||
*/
|
||||
template<typename ConstBufferSequence,
|
||||
typename WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
WriteHandler, void(boost::system::error_code, std::size_t))
|
||||
async_write_some(
|
||||
const ConstBufferSequence & buffers,
|
||||
WriteHandler && handler);
|
||||
|
||||
///Get the asio handle of the pipe sink.
|
||||
const handle_type & sink () const &;
|
||||
///Get the asio handle of the pipe source.
|
||||
const handle_type & source() const &;
|
||||
|
||||
///Get the asio handle of the pipe sink. Qualified as rvalue
|
||||
handle_type && sink () &&;
|
||||
///Get the asio handle of the pipe source. Qualified as rvalue
|
||||
handle_type && source() &&;
|
||||
|
||||
/// Move the source out of this class and change the io_service. Qualified as rvalue. \attention Will always move.
|
||||
handle_type source(::boost::asio::io_service& ios) &&;
|
||||
/// Move the sink out of this class and change the io_service. Qualified as rvalue. \attention Will always move
|
||||
handle_type sink (::boost::asio::io_service& ios) &&;
|
||||
|
||||
/// Copy the source out of this class and change the io_service. \attention Will always copy.
|
||||
handle_type source(::boost::asio::io_service& ios) const &;
|
||||
/// Copy the sink out of this class and change the io_service. \attention Will always copy
|
||||
handle_type sink (::boost::asio::io_service& ios) const &;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#else
|
||||
using ::boost::process::detail::api::async_pipe;
|
||||
#endif
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/async_pipe.hpp>")
|
||||
#include <boost/process/v1/async_pipe.hpp>
|
||||
|
||||
9
include/boost/process/async_system.hpp
Normal file
9
include/boost/process/async_system.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/async_system.hpp>")
|
||||
#include <boost/process/v1/async_system.hpp>
|
||||
@@ -1,144 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/child.hpp
|
||||
*
|
||||
* Defines a child process class.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_CHILD_HPP
|
||||
#define BOOST_PROCESS_CHILD_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/child_decl.hpp>
|
||||
#include <boost/process/detail/execute_impl.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/posix.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
///The main namespace of boost.process.
|
||||
namespace process {
|
||||
|
||||
template<typename ...Args>
|
||||
child::child(Args&&...args)
|
||||
: child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {}
|
||||
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread),
|
||||
* in that it has a join and detach function.
|
||||
*
|
||||
* @attention The destructor will call terminate on the process if not joined or detached without any warning.
|
||||
*
|
||||
*/
|
||||
|
||||
class child
|
||||
{
|
||||
/** Type definition for the native process handle. */
|
||||
typedef platform_specific native_handle_t;
|
||||
|
||||
/** Construct the child from a pid.
|
||||
*
|
||||
* @attention There is no guarantee that this will work. The process need the right access rights, which are very platform specific.
|
||||
*/
|
||||
explicit child(pid_t & pid) : _child_handle(pid) {};
|
||||
|
||||
/** Move-Constructor.*/
|
||||
child(child && lhs);
|
||||
|
||||
/** Construct a child from a property list and launch it
|
||||
* The standard version is to create a subprocess, which will spawn the process.
|
||||
*/
|
||||
template<typename ...Args>
|
||||
explicit child(Args&&...args);
|
||||
|
||||
/** Construct an empty child. */
|
||||
child() = default;
|
||||
|
||||
/** Move assign. */
|
||||
child& operator=(child && lhs);
|
||||
|
||||
/** Detach the child, i.e. let it run after this handle dies. */
|
||||
void detach();
|
||||
/** Join the child. This just calls wait, but that way the naming is similar to std::thread */
|
||||
void join();
|
||||
/** Check if the child is joinable. */
|
||||
bool joinable();
|
||||
|
||||
/** Destructor.
|
||||
* @attention Will call terminate (without warning) when the child was neither joined nor detached.
|
||||
*/
|
||||
~child();
|
||||
|
||||
/** Get the native handle for the child process. */
|
||||
native_handle_t native_handle() const;
|
||||
|
||||
/** Get the exit_code. The return value is without any meaning if the child wasn't waited for or if it was terminated. */
|
||||
int exit_code() const;
|
||||
/** Get the Process Identifier. */
|
||||
pid_t id() const;
|
||||
|
||||
/** Check if the child process is running. */
|
||||
bool running();
|
||||
/** \overload void running() */
|
||||
bool running(std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit. */
|
||||
void wait();
|
||||
/** \overload void wait() */
|
||||
void wait(std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit for a period of time. */
|
||||
template< class Rep, class Period >
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time);
|
||||
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) */
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit until a point in time. */
|
||||
template< class Clock, class Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time );
|
||||
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )*/
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept;
|
||||
|
||||
/** Check if this handle holds a child process.
|
||||
* @note That does not mean, that the process is still running. It only means, that the handle does or did exist.
|
||||
*/
|
||||
bool valid() const;
|
||||
/** Same as valid, for convenience. */
|
||||
explicit operator bool() const;
|
||||
|
||||
/** Check if the the chlid process is in any process group. */
|
||||
bool in_group() const;
|
||||
|
||||
/** \overload bool in_group() const */
|
||||
bool in_group(std::error_code & ec) const noexcept;
|
||||
|
||||
/** Terminate the child process.
|
||||
*
|
||||
* This function will cause the child process to unconditionally and immediately exit.
|
||||
* It is implement with [SIGKILL](http://pubs.opengroup.org/onlinepubs/009695399/functions/kill.html) on posix
|
||||
* and [TerminateProcess](https://technet.microsoft.com/en-us/library/ms686714.aspx) on windows.
|
||||
*
|
||||
*/
|
||||
void terminate();
|
||||
|
||||
/** \overload void terminate() */
|
||||
void terminate(std::error_code & ec) noexcept;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
#endif
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/child.hpp>")
|
||||
#include <boost/process/v1/child.hpp>
|
||||
|
||||
@@ -1,122 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_CMD_LINE_HPP
|
||||
#define BOOST_PROCESS_DETAIL_CMD_LINE_HPP
|
||||
|
||||
#include <boost/detail/winapi/config.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/cmd.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/cmd.hpp>
|
||||
#endif
|
||||
|
||||
/** \file boost/process/cmd.hpp
|
||||
*
|
||||
* This header provides the \xmlonly <globalname alt="boost::process::cmd">cmd</globalname>\endxmlonly property.
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::cmd">cmd</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
struct cmd_
|
||||
{
|
||||
constexpr cmd_() {}
|
||||
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator()(const Char *s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator= (const Char *s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator()(const std::basic_string<Char> &s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator= (const std::basic_string<Char> &s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct is_wchar_t<api::cmd_setter_<wchar_t>> : std::true_type {};
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, api::cmd_setter_<wchar_t>>
|
||||
{
|
||||
static api::cmd_setter_<char> conv(const api::cmd_setter_<wchar_t> & in)
|
||||
{
|
||||
return { ::boost::process::detail::convert(in.str()) };
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, api::cmd_setter_<char>>
|
||||
{
|
||||
static api::cmd_setter_<wchar_t> conv(const api::cmd_setter_<char> & in)
|
||||
{
|
||||
return { ::boost::process::detail::convert(in.str()) };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** The cmd property allows to explicitly set commands for the execution.
|
||||
|
||||
The overload form applies when only one string is passed to a launching function.
|
||||
The string will be internally parsed and split at spaces.
|
||||
|
||||
The following expressions are valid, with `value` being either a C-String or
|
||||
a `std::basic_string` with `char` or `wchar_t`.
|
||||
|
||||
\code{.cpp}
|
||||
cmd="value";
|
||||
cmd(value);
|
||||
\endcode
|
||||
|
||||
The property can only be used for assignments.
|
||||
|
||||
|
||||
*/
|
||||
constexpr static ::boost::process::detail::cmd_ cmd;
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/cmd.hpp>")
|
||||
#include <boost/process/v1/cmd.hpp>
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* async_handler.hpp
|
||||
*
|
||||
* Created on: 12.06.2016
|
||||
* Author: Klemens
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/posix.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/process/detail/posix/asio_fwd.hpp>
|
||||
#else
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace process {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
using ::boost::process::detail::posix::is_async_handler;
|
||||
using ::boost::process::detail::posix::does_require_io_service;
|
||||
#else
|
||||
using ::boost::process::detail::windows::is_async_handler;
|
||||
using ::boost::process::detail::windows::does_require_io_service;
|
||||
#endif
|
||||
|
||||
template<typename ...Args>
|
||||
struct has_io_service;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct has_io_service<T, Args...>
|
||||
{
|
||||
typedef typename has_io_service<Args...>::type next;
|
||||
typedef typename std::is_same<
|
||||
typename std::remove_reference<T>::type,
|
||||
boost::asio::io_service>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_io_service<T>
|
||||
{
|
||||
typedef typename std::is_same<
|
||||
typename std::remove_reference<T>::type,
|
||||
boost::asio::io_service>::type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
using has_io_service_t = typename has_io_service<Args...>::type;
|
||||
|
||||
template<typename ...Args>
|
||||
struct has_async_handler;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct has_async_handler<T, Args...>
|
||||
{
|
||||
typedef typename has_async_handler<Args...>::type next;
|
||||
typedef typename is_async_handler<T>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_async_handler<T>
|
||||
{
|
||||
typedef typename is_async_handler<T>::type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
struct needs_io_service;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct needs_io_service<T, Args...>
|
||||
{
|
||||
typedef typename needs_io_service<Args...>::type next;
|
||||
typedef typename does_require_io_service<T>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct needs_io_service<T>
|
||||
{
|
||||
typedef typename does_require_io_service<T>::type type;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_yield_context
|
||||
{
|
||||
typedef std::false_type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_yield_context<::boost::asio::basic_yield_context<T>>
|
||||
{
|
||||
typedef std::true_type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
struct has_yield_context;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct has_yield_context<T, Args...>
|
||||
{
|
||||
typedef typename has_yield_context<Args...>::type next;
|
||||
typedef typename is_yield_context<
|
||||
typename std::remove_reference<T>::type>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_yield_context<T>
|
||||
{
|
||||
typedef typename is_yield_context<
|
||||
typename std::remove_reference<T>::type>::type type;
|
||||
};
|
||||
|
||||
|
||||
template<typename ...Args>
|
||||
boost::asio::io_service &get_io_service_var(boost::asio::io_service & f, Args&...args)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
template<typename First, typename ...Args>
|
||||
boost::asio::io_service &get_io_service_var(First & f, Args&...args)
|
||||
{
|
||||
return get_io_service_var(args...);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_ */
|
||||
@@ -1,95 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/config.hpp
|
||||
*
|
||||
* Defines various macros.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_CONFIG_HPP
|
||||
#define BOOST_PROCESS_DETAIL_CONFIG_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/system/api_config.hpp>
|
||||
|
||||
#include <boost/process/exception.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <errno.h>
|
||||
#include <features.h>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/detail/winapi/get_last_error.hpp>
|
||||
#else
|
||||
#error "System API not supported by boost.process"
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { namespace detail
|
||||
{
|
||||
|
||||
#if !defined(BOOST_PROCESS_PIPE_SIZE)
|
||||
#define BOOST_PROCESS_PIPE_SIZE 1024
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
namespace posix {namespace extensions {}}
|
||||
namespace api = posix;
|
||||
|
||||
inline std::error_code get_last_error() noexcept
|
||||
{
|
||||
return std::error_code(errno, std::system_category());
|
||||
}
|
||||
|
||||
//copied from linux spec.
|
||||
#if defined (__USE_XOPEN_EXTENDED) && !defined (__USE_XOPEN2K8) || defined( __USE_BSD)
|
||||
#define BOOST_POSIX_HAS_VFORK 1
|
||||
#endif
|
||||
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
namespace windows {namespace extensions {}}
|
||||
namespace api = windows;
|
||||
|
||||
inline std::error_code get_last_error() noexcept
|
||||
{
|
||||
return std::error_code(::boost::detail::winapi::GetLastError(), std::system_category());
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void throw_last_error(const std::string & msg)
|
||||
{
|
||||
throw process_error(get_last_error(), msg);
|
||||
}
|
||||
|
||||
inline void throw_last_error()
|
||||
{
|
||||
throw process_error(get_last_error());
|
||||
}
|
||||
|
||||
|
||||
template<typename Char> constexpr static Char null_char();
|
||||
template<> constexpr char null_char<char> (){return '\0';}
|
||||
template<> constexpr wchar_t null_char<wchar_t> (){return L'\0';}
|
||||
|
||||
template<typename Char> constexpr static Char equal_sign();
|
||||
template<> constexpr char equal_sign<char> () {return '='; }
|
||||
template<> constexpr wchar_t equal_sign<wchar_t> () {return L'='; }
|
||||
|
||||
template<typename Char> constexpr static Char quote_sign();
|
||||
template<> constexpr char quote_sign<char> () {return '"'; }
|
||||
template<> constexpr wchar_t quote_sign<wchar_t> () {return L'"'; }
|
||||
|
||||
template<typename Char> constexpr static Char space_sign();
|
||||
template<> constexpr char space_sign<char> () {return ' '; }
|
||||
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }
|
||||
|
||||
|
||||
}}}
|
||||
#endif
|
||||
@@ -1,94 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
|
||||
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_service
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<std::promise<void>> promise;
|
||||
async_in_buffer operator>(std::future<void> & fut)
|
||||
{
|
||||
promise = std::make_shared<std::promise<void>>();
|
||||
fut = promise->get_future(); return std::move(*this);
|
||||
}
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
async_in_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &exec)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
if (this->promise)
|
||||
{
|
||||
auto promise = this->promise;
|
||||
|
||||
boost::asio::async_write(*pipe, buf,
|
||||
[pipe, promise](const boost::system::error_code & ec, std::size_t)
|
||||
{
|
||||
if (ec && (ec.value() != EBADF) && (ec.value() != EPERM) && (ec.value() != ENOENT))
|
||||
{
|
||||
std::error_code e(ec.value(), std::system_category());
|
||||
promise->set_exception(std::make_exception_ptr(process_error(e)));
|
||||
}
|
||||
else
|
||||
promise->set_value();
|
||||
});
|
||||
}
|
||||
else
|
||||
boost::asio::async_write(*pipe, buf,
|
||||
[pipe](const boost::system::error_code&ec, std::size_t size){});
|
||||
|
||||
::close(pipe->native_source());
|
||||
this->pipe = nullptr;
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::close(pipe->native_source());
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &exec)
|
||||
{
|
||||
if (::dup2(pipe->native_source(), STDIN_FILENO) == -1)
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
::close(pipe->native_source());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,162 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_IO_SERVICE_REF_HPP_
|
||||
#define BOOST_PROCESS_POSIX_IO_SERVICE_REF_HPP_
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/transform.hpp>
|
||||
#include <boost/fusion/view/transform_view.hpp>
|
||||
#include <boost/fusion/container/vector/convert.hpp>
|
||||
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<typename Executor>
|
||||
struct on_exit_handler_transformer
|
||||
{
|
||||
Executor & exec;
|
||||
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
|
||||
template<typename Sig>
|
||||
struct result;
|
||||
|
||||
template<typename T>
|
||||
struct result<on_exit_handler_transformer<Executor>(T&)>
|
||||
{
|
||||
typedef typename T::on_exit_handler_t type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
auto operator()(T& t) const -> typename T::on_exit_handler_t
|
||||
{
|
||||
return t.on_exit_handler(exec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct async_handler_collector
|
||||
{
|
||||
Executor & exec;
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
|
||||
|
||||
|
||||
async_handler_collector(Executor & exec,
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
|
||||
: exec(exec), handlers(handlers) {}
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
handlers.push_back(t.on_exit_handler(exec));
|
||||
};
|
||||
};
|
||||
|
||||
//Also set's up waiting for the exit, so it can close async stuff.
|
||||
struct io_service_ref : handler_base_ext
|
||||
{
|
||||
io_service_ref(boost::asio::io_service & ios) : ios(ios)
|
||||
{
|
||||
|
||||
}
|
||||
boost::asio::io_service &get() {return ios;};
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec) const
|
||||
{
|
||||
//must be on the heap so I can move it into the lambda.
|
||||
auto asyncs = boost::fusion::filter_if<
|
||||
is_async_handler<
|
||||
typename std::remove_reference< boost::mpl::_ > ::type
|
||||
>>(exec.seq);
|
||||
|
||||
//ok, check if there are actually any.
|
||||
if (boost::fusion::empty(asyncs))
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
|
||||
funcs.reserve(boost::fusion::size(asyncs));
|
||||
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
|
||||
|
||||
|
||||
|
||||
wait_handler wh(std::move(funcs), ios, exec.exit_status);
|
||||
|
||||
auto signal_p = wh.signal_.get();
|
||||
signal_p->async_wait(std::move(wh));
|
||||
}
|
||||
struct wait_handler
|
||||
{
|
||||
std::shared_ptr<boost::asio::signal_set> signal_;
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
|
||||
std::shared_ptr<std::atomic<int>> exit_status;
|
||||
|
||||
wait_handler(const wait_handler & ) = default;
|
||||
wait_handler(wait_handler && ) = default;
|
||||
wait_handler(
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
|
||||
boost::asio::io_service & ios,
|
||||
const std::shared_ptr<std::atomic<int>> &exit_status)
|
||||
: signal_(new boost::asio::signal_set(ios, SIGCHLD)),
|
||||
funcs(std::move(funcs)),
|
||||
exit_status(exit_status)
|
||||
|
||||
|
||||
{
|
||||
|
||||
}
|
||||
void operator()(const boost::system::error_code & ec_in, int /*signal*/)
|
||||
{
|
||||
int status;
|
||||
::wait(&status);
|
||||
|
||||
std::error_code ec(ec_in.value(), std::system_category());
|
||||
int val = WEXITSTATUS(status);
|
||||
exit_status->store(val);
|
||||
|
||||
for (auto & func : funcs)
|
||||
func(val, ec);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Posix specific notifies
|
||||
template <class PosixExecutor>
|
||||
void on_fork_setup(PosixExecutor&) const
|
||||
{
|
||||
ios.notify_fork(boost::asio::io_service::fork_prepare);
|
||||
}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_fork_success(PosixExecutor&) const
|
||||
{
|
||||
ios.notify_fork(boost::asio::io_service::fork_parent);
|
||||
}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_exec_setup(PosixExecutor&) const
|
||||
{
|
||||
ios.notify_fork(boost::asio::io_service::fork_child);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::io_service &ios;
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright (c) 2106 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_IS_RUNNING_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_IS_RUNNING_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <sys/wait.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
constexpr static int still_active = 0x7F;
|
||||
static_assert(!WIFEXITED(still_active), "Internal Error");
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code)
|
||||
{
|
||||
int status;
|
||||
auto ret = ::waitpid(p.pid, &status, WNOHANG|WUNTRACED);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
|
||||
::boost::process::detail::throw_last_error("is_running error");
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (ret == 0)
|
||||
return true;
|
||||
else //exited
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
exit_code = status;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
int status;
|
||||
auto ret = ::waitpid(p.pid, &status, WNOHANG|WUNTRACED);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
return false;
|
||||
}
|
||||
else if (ret == 0)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
if (WIFEXITED(status))
|
||||
exit_code = status;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_running(int code)
|
||||
{
|
||||
return !WIFEXITED(code);
|
||||
}
|
||||
|
||||
inline int eval_exit_status(int code)
|
||||
{
|
||||
return WEXITSTATUS(code);
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <system_error>
|
||||
#include <functional>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct on_exit_ : boost::process::detail::posix::async_handler
|
||||
{
|
||||
std::function<void(int, const std::error_code&)> handler;
|
||||
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
|
||||
{
|
||||
return handler;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_PIPE_IN_HPP
|
||||
#define BOOST_PROCESS_POSIX_PIPE_IN_HPP
|
||||
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct pipe_in : handler_base_ext
|
||||
{
|
||||
int descr_;
|
||||
|
||||
template<typename T>
|
||||
pipe_in(const T & p) : descr_(p.native_source()) {}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::close(descr_);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &) const
|
||||
{
|
||||
::close(descr_);
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(descr_, STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
::close(descr_);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,76 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
|
||||
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct pipe_out : handler_base_ext
|
||||
{
|
||||
int descr_;
|
||||
|
||||
template<typename T>
|
||||
pipe_out(const T & p) : descr_(p.native_sink()) {}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::close(descr_);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &) const
|
||||
{
|
||||
::close(descr_);
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void pipe_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(descr_, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup3() failed");
|
||||
::close(descr_);
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void pipe_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(descr_, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
::close(descr_);
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void pipe_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(descr_, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
if (::dup2(descr_, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
::close(descr_);
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_SEARCH_PATH_HPP
|
||||
#define BOOST_PROCESS_POSIX_SEARCH_PATH_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
inline boost::filesystem::path search_path(
|
||||
const boost::filesystem::path &filename,
|
||||
const std::vector<boost::filesystem::path> &path)
|
||||
{
|
||||
std::string result;
|
||||
for (const boost::filesystem::path & pp : path)
|
||||
{
|
||||
auto p = pp / filename;
|
||||
if (!::access(p.c_str(), X_OK))
|
||||
return p;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,209 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_WAIT_FOR_EXIT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_WAIT_FOR_EXIT_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
inline void wait(const child_handle &p, int & exit_code)
|
||||
{
|
||||
pid_t ret;
|
||||
int status;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, 0);
|
||||
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
exit_code = status;
|
||||
}
|
||||
|
||||
inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, 0);
|
||||
}
|
||||
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
exit_code = status;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto time_out = start + rel_time;
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
|
||||
exit_code = status;
|
||||
|
||||
return !time_out_occured;
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto time_out = start + rel_time;
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
exit_code = status;
|
||||
}
|
||||
|
||||
return !time_out_occured;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_until(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& time_out)
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
|
||||
exit_code = status;
|
||||
|
||||
return !time_out_occured;
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_until(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& time_out,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
exit_code = status;
|
||||
}
|
||||
|
||||
return !time_out_occured;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,191 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_WAIT_GROUP_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_WAIT_GROUP_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/group_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
inline void wait(const group_handle &p)
|
||||
{
|
||||
pid_t ret;
|
||||
int status;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, 0);
|
||||
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
}
|
||||
|
||||
inline void wait(const group_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, 0);
|
||||
}
|
||||
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto time_out = start + rel_time;
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
|
||||
|
||||
return !time_out_occured;
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto time_out = start + rel_time;
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
return !time_out_occured;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& time_out)
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
|
||||
|
||||
return !time_out_occured;
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& time_out,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
return !time_out_occured;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_TRAITS_HPP_
|
||||
#define BOOST_PROCESS_TRAITS_HPP_
|
||||
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
#include <boost/process/detail/traits/async.hpp>
|
||||
#include <boost/process/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/detail/traits/env.hpp>
|
||||
#include <boost/process/detail/traits/error.hpp>
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
|
||||
#endif /* BOOST_PROCESS_TRAITS_HPP_ */
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct error_tag {};
|
||||
|
||||
template<>
|
||||
struct make_initializer_t<error_tag>;
|
||||
|
||||
|
||||
template<> struct initializer_tag_t<std::error_code> { typedef error_tag type;};
|
||||
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
@@ -1,105 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/handle_info.hpp>
|
||||
#include <boost/detail/winapi/error_codes.hpp>
|
||||
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
|
||||
::boost::process::detail::windows::require_io_service
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<std::promise<void>> promise;
|
||||
async_in_buffer operator>(std::future<void> & fut)
|
||||
{
|
||||
promise = std::make_shared<std::promise<void>>();
|
||||
fut = promise->get_future(); return std::move(*this);
|
||||
}
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
async_in_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &exec)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
|
||||
if (this->promise)
|
||||
{
|
||||
auto promise = this->promise;
|
||||
|
||||
boost::asio::async_write(*pipe, buf,
|
||||
[promise](const boost::system::error_code & ec, std::size_t)
|
||||
{
|
||||
if (ec && (ec.value() != ::boost::detail::winapi::ERROR_BROKEN_PIPE_))
|
||||
{
|
||||
std::error_code e(ec.value(), std::system_category());
|
||||
promise->set_exception(std::make_exception_ptr(process_error(e)));
|
||||
}
|
||||
promise->set_value();
|
||||
});
|
||||
}
|
||||
else
|
||||
boost::asio::async_write(*pipe, buf,
|
||||
[pipe](const boost::system::error_code&ec, std::size_t size){});
|
||||
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_source());
|
||||
|
||||
|
||||
this->pipe = nullptr;
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_source());
|
||||
}
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
|
||||
|
||||
::boost::detail::winapi::HANDLE_ source_handle = std::move(*pipe).source().native_handle();
|
||||
|
||||
boost::detail::winapi::SetHandleInformation(source_handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
exec.startup_info.hStdInput = source_handle;
|
||||
exec.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
exec.inherit_handles = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,176 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/handle_info.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#include <boost/detail/winapi/error_codes.hpp>
|
||||
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template<int p1, int p2, typename Buffer>
|
||||
struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
|
||||
::boost::process::detail::windows::require_io_service
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
|
||||
async_out_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &exec)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
boost::asio::async_read(*pipe, buf,
|
||||
[pipe](const boost::system::error_code&, std::size_t size){});
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_sink());
|
||||
this->pipe = nullptr;
|
||||
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_sink());
|
||||
}
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
|
||||
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<int p1, int p2, typename Type>
|
||||
struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
|
||||
::boost::process::detail::windows::require_io_service
|
||||
{
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
|
||||
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
|
||||
|
||||
|
||||
async_out_future(std::future<Type> & fut)
|
||||
{
|
||||
fut = promise->get_future();
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &exec)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
auto buffer = this->buffer;
|
||||
auto promise = this->promise;
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_sink());
|
||||
boost::asio::async_read(*pipe, *buffer,
|
||||
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t size)
|
||||
{
|
||||
if (ec && (ec.value() != ::boost::detail::winapi::ERROR_BROKEN_PIPE_))
|
||||
{
|
||||
std::error_code e(ec.value(), std::system_category());
|
||||
promise->set_exception(std::make_exception_ptr(process_error(e)));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::istream is (buffer.get());
|
||||
Type arg;
|
||||
arg.resize(buffer->size());
|
||||
is.read(&*arg.begin(), buffer->size());
|
||||
|
||||
promise->set_value(std::move(arg));
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
this->pipe = nullptr;
|
||||
this->buffer = nullptr;
|
||||
this->promise = nullptr;
|
||||
|
||||
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_sink());
|
||||
}
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
|
||||
|
||||
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,409 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
|
||||
|
||||
#include <boost/detail/winapi/basic_types.hpp>
|
||||
#include <boost/detail/winapi/pipes.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/file_management.hpp>
|
||||
#include <boost/detail/winapi/get_last_error.hpp>
|
||||
#include <boost/detail/winapi/access_rights.hpp>
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/process/detail/windows/basic_pipe.hpp>
|
||||
#include <boost/asio/windows/stream_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
inline std::string make_pipe_name()
|
||||
{
|
||||
std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_";
|
||||
|
||||
auto pid = ::boost::detail::winapi::GetCurrentProcessId();
|
||||
|
||||
static unsigned long long cnt = 0;
|
||||
name += std::to_string(pid);
|
||||
name += "_";
|
||||
name += std::to_string(cnt++);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
class async_pipe
|
||||
{
|
||||
::boost::asio::windows::stream_handle _source;
|
||||
::boost::asio::windows::stream_handle _sink ;
|
||||
public:
|
||||
typedef ::boost::detail::winapi::HANDLE_ native_handle_type;
|
||||
typedef ::boost::asio::windows::stream_handle handle_type;
|
||||
|
||||
inline async_pipe(boost::asio::io_service & ios,
|
||||
const std::string & name = make_pipe_name())
|
||||
: async_pipe(ios, ios, name) {}
|
||||
|
||||
inline async_pipe(boost::asio::io_service & ios_source,
|
||||
boost::asio::io_service & ios_sink,
|
||||
const std::string & name = make_pipe_name());
|
||||
|
||||
inline async_pipe(const async_pipe& rhs);
|
||||
async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
|
||||
{
|
||||
rhs._source.assign (::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
rhs._sink .assign (::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(::boost::asio::io_service & ios_source,
|
||||
::boost::asio::io_service & ios_sink,
|
||||
const basic_pipe<CharT, Traits> & p)
|
||||
: _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
|
||||
{
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p)
|
||||
: async_pipe(ios, ios, p)
|
||||
{
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
|
||||
inline async_pipe& operator=(const async_pipe& rhs);
|
||||
|
||||
inline async_pipe& operator=(async_pipe&& rhs);
|
||||
|
||||
~async_pipe()
|
||||
{
|
||||
if (_sink .native() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::detail::winapi::CloseHandle(_sink.native());
|
||||
if (_source.native() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::detail::winapi::CloseHandle(_source.native());
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline explicit operator basic_pipe<CharT, Traits>() const;
|
||||
|
||||
void cancel()
|
||||
{
|
||||
if (_sink.is_open())
|
||||
_sink.cancel();
|
||||
if (_source.is_open())
|
||||
_source.cancel();
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (_sink.is_open())
|
||||
{
|
||||
_sink.close();
|
||||
_sink.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
if (_source.is_open())
|
||||
{
|
||||
_source.close();
|
||||
_source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
}
|
||||
void close(boost::system::error_code & ec)
|
||||
{
|
||||
if (_sink.is_open())
|
||||
_sink.close(ec);
|
||||
if (_source.is_open())
|
||||
_source.close(ec);
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
{
|
||||
return _sink.is_open() || _source.is_open();
|
||||
}
|
||||
void async_close()
|
||||
{
|
||||
if (_sink.is_open())
|
||||
_sink.get_io_service(). post([this]{_sink.close();});
|
||||
if (_source.is_open())
|
||||
_source.get_io_service().post([this]{_source.close();});
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence & buffers)
|
||||
{
|
||||
return _source.read_some(buffers);
|
||||
}
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t write_some(const MutableBufferSequence & buffers)
|
||||
{
|
||||
return _sink.write_some(buffers);
|
||||
}
|
||||
|
||||
native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();}
|
||||
native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();}
|
||||
|
||||
template<typename MutableBufferSequence,
|
||||
typename ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
ReadHandler, void(boost::system::error_code, std::size_t))
|
||||
async_read_some(
|
||||
const MutableBufferSequence & buffers,
|
||||
ReadHandler &&handler)
|
||||
{
|
||||
_source.async_read_some(buffers, std::forward<ReadHandler>(handler));
|
||||
}
|
||||
|
||||
template<typename ConstBufferSequence,
|
||||
typename WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
WriteHandler, void(boost::system::error_code, std::size_t))
|
||||
async_write_some(
|
||||
const ConstBufferSequence & buffers,
|
||||
WriteHandler && handler)
|
||||
{
|
||||
_sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
|
||||
}
|
||||
|
||||
const handle_type & sink () const & {return _sink;}
|
||||
const handle_type & source() const & {return _source;}
|
||||
|
||||
handle_type && source() && { return std::move(_source); }
|
||||
handle_type && sink() && { return std::move(_sink); }
|
||||
|
||||
handle_type source(::boost::asio::io_service& ios) &&
|
||||
{
|
||||
::boost::asio::windows::stream_handle stolen(ios, _source.native_handle());
|
||||
_source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
return stolen;
|
||||
}
|
||||
handle_type sink (::boost::asio::io_service& ios) &&
|
||||
{
|
||||
::boost::asio::windows::stream_handle stolen(ios, _sink.native_handle());
|
||||
_sink.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
return stolen;
|
||||
}
|
||||
|
||||
handle_type source(::boost::asio::io_service& ios) const &
|
||||
{
|
||||
auto proc = ::boost::detail::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::detail::winapi::HANDLE_ source;
|
||||
auto source_in = const_cast<handle_type&>(_source).native();
|
||||
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, source_in, proc, &source, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
return ::boost::asio::windows::stream_handle(ios, source);
|
||||
}
|
||||
handle_type sink (::boost::asio::io_service& ios) const &
|
||||
{
|
||||
auto proc = ::boost::detail::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::detail::winapi::HANDLE_ sink;
|
||||
auto sink_in = const_cast<handle_type&>(_sink).native();
|
||||
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, sink_in, proc, &sink, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
return ::boost::asio::windows::stream_handle(ios, sink);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
async_pipe::async_pipe(const async_pipe& p) :
|
||||
_source(const_cast<handle_type&>(p._source).get_io_service()),
|
||||
_sink (const_cast<handle_type&>(p._sink).get_io_service())
|
||||
{
|
||||
auto proc = ::boost::detail::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::detail::winapi::HANDLE_ source;
|
||||
::boost::detail::winapi::HANDLE_ sink;
|
||||
|
||||
//cannot get the handle from a const object.
|
||||
auto source_in = const_cast<handle_type&>(p._source).native();
|
||||
auto sink_in = const_cast<handle_type&>(p._sink).native();
|
||||
|
||||
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, source_in, proc, &source, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, sink_in, proc, &sink, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
_source.assign(source);
|
||||
_sink. assign(sink);
|
||||
}
|
||||
|
||||
|
||||
async_pipe::async_pipe(boost::asio::io_service & ios_source,
|
||||
boost::asio::io_service & ios_sink,
|
||||
const std::string & name) : _source(ios_source), _sink(ios_sink)
|
||||
{
|
||||
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
|
||||
|
||||
::boost::detail::winapi::HANDLE_ source = ::boost::detail::winapi::create_named_pipe(
|
||||
name.c_str(),
|
||||
::boost::detail::winapi::PIPE_ACCESS_INBOUND_
|
||||
| FILE_FLAG_OVERLAPPED_, //write flag
|
||||
0, 1, 8192, 8192, 0, nullptr);
|
||||
|
||||
|
||||
if (source == boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::process::detail::throw_last_error("create_named_pipe(" + name + ") failed");
|
||||
|
||||
_source.assign(source);
|
||||
|
||||
::boost::detail::winapi::HANDLE_ sink = boost::detail::winapi::create_file(
|
||||
name.c_str(),
|
||||
::boost::detail::winapi::GENERIC_WRITE_, 0, nullptr,
|
||||
::boost::detail::winapi::OPEN_EXISTING_,
|
||||
FILE_FLAG_OVERLAPPED_, //to allow read
|
||||
nullptr);
|
||||
|
||||
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::process::detail::throw_last_error("create_file() failed");
|
||||
|
||||
_sink.assign(sink);
|
||||
}
|
||||
|
||||
async_pipe& async_pipe::operator=(const async_pipe & p)
|
||||
{
|
||||
auto proc = ::boost::detail::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::detail::winapi::HANDLE_ source;
|
||||
::boost::detail::winapi::HANDLE_ sink;
|
||||
|
||||
//cannot get the handle from a const object.
|
||||
auto &source_in = const_cast<::boost::asio::windows::stream_handle &>(p._source);
|
||||
auto &sink_in = const_cast<::boost::asio::windows::stream_handle &>(p._sink);
|
||||
|
||||
if (source_in.native() == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, source_in.native(), proc, &source, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (sink_in.native() == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, sink_in.native(), proc, &sink, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
//so we also assign the io_service
|
||||
_source = ::boost::asio::windows::stream_handle(source_in.get_io_service(), source);
|
||||
_sink = ::boost::asio::windows::stream_handle(source_in.get_io_service(), sink);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
async_pipe& async_pipe::operator=(async_pipe && rhs)
|
||||
{
|
||||
if (_source.native_handle() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::detail::winapi::CloseHandle(_source.native());
|
||||
|
||||
if (_sink.native_handle() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::detail::winapi::CloseHandle(_sink.native());
|
||||
|
||||
_source.assign(rhs._source.native_handle());
|
||||
_sink .assign(rhs._sink .native_handle());
|
||||
rhs._source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
rhs._sink .assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class CharT, class Traits>
|
||||
async_pipe::operator basic_pipe<CharT, Traits>() const
|
||||
{
|
||||
auto proc = ::boost::detail::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::detail::winapi::HANDLE_ source;
|
||||
::boost::detail::winapi::HANDLE_ sink;
|
||||
|
||||
//cannot get the handle from a const object.
|
||||
auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native();
|
||||
auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native();
|
||||
|
||||
if (source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, source_in, proc, &source, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, sink_in, proc, &sink, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
return {source, sink};
|
||||
}
|
||||
|
||||
inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */
|
||||
@@ -1,222 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_PIPE_HPP
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_PIPE_HPP
|
||||
|
||||
#include <boost/detail/winapi/basic_types.hpp>
|
||||
#include <boost/detail/winapi/error_codes.hpp>
|
||||
#include <boost/detail/winapi/pipes.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/file_management.hpp>
|
||||
#include <boost/detail/winapi/get_last_error.hpp>
|
||||
#include <boost/detail/winapi/access_rights.hpp>
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/process/detail/windows/compare_handles.hpp>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
class basic_pipe
|
||||
{
|
||||
::boost::detail::winapi::HANDLE_ _source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
::boost::detail::winapi::HANDLE_ _sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
public:
|
||||
typedef CharT char_type ;
|
||||
typedef Traits traits_type;
|
||||
typedef typename Traits::int_type int_type ;
|
||||
typedef typename Traits::pos_type pos_type ;
|
||||
typedef typename Traits::off_type off_type ;
|
||||
typedef ::boost::detail::winapi::HANDLE_ native_handle_type;
|
||||
|
||||
explicit basic_pipe(::boost::detail::winapi::HANDLE_ source, ::boost::detail::winapi::HANDLE_ sink)
|
||||
: _source(source), _sink(sink) {}
|
||||
inline explicit basic_pipe(const std::string & name);
|
||||
inline basic_pipe(const basic_pipe& p);
|
||||
basic_pipe(basic_pipe&& lhs) : _source(lhs._source), _sink(lhs._sink)
|
||||
{
|
||||
lhs._source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
lhs._sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
}
|
||||
inline basic_pipe& operator=(const basic_pipe& p);
|
||||
inline basic_pipe& operator=(basic_pipe&& lhs);
|
||||
~basic_pipe()
|
||||
{
|
||||
if (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::detail::winapi::CloseHandle(_sink);
|
||||
if (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::detail::winapi::CloseHandle(_source);
|
||||
}
|
||||
native_handle_type native_source() const {return _source;}
|
||||
native_handle_type native_sink () const {return _sink;}
|
||||
|
||||
basic_pipe()
|
||||
{
|
||||
if (!::boost::detail::winapi::CreatePipe(&_source, &_sink, nullptr, 0))
|
||||
throw_last_error("CreatePipe() failed");
|
||||
|
||||
}
|
||||
|
||||
int_type write(const char_type * data, int_type count)
|
||||
{
|
||||
::boost::detail::winapi::DWORD_ write_len;
|
||||
if (!::boost::detail::winapi::WriteFile(
|
||||
_sink, data, count * sizeof(char_type), &write_len, nullptr
|
||||
))
|
||||
{
|
||||
auto ec = ::boost::process::detail::get_last_error();
|
||||
if ((ec.value() == ::boost::detail::winapi::ERROR_BROKEN_PIPE_) ||
|
||||
(ec.value() == ::boost::detail::winapi::ERROR_NO_DATA_))
|
||||
return 0;
|
||||
else
|
||||
throw process_error(ec, "WriteFile failed");
|
||||
}
|
||||
return static_cast<int_type>(write_len);
|
||||
}
|
||||
int_type read(char_type * data, int_type count)
|
||||
{
|
||||
::boost::detail::winapi::DWORD_ read_len;
|
||||
if (!::boost::detail::winapi::ReadFile(
|
||||
_source, data, count * sizeof(char_type), &read_len, nullptr
|
||||
))
|
||||
{
|
||||
auto ec = ::boost::process::detail::get_last_error();
|
||||
if ((ec.value() == ::boost::detail::winapi::ERROR_BROKEN_PIPE_) ||
|
||||
(ec.value() == ::boost::detail::winapi::ERROR_NO_DATA_))
|
||||
return 0;
|
||||
else
|
||||
throw process_error(ec, "ReadFile failed");
|
||||
}
|
||||
return static_cast<int_type>(read_len);
|
||||
}
|
||||
|
||||
bool is_open()
|
||||
{
|
||||
return (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) ||
|
||||
(_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(_source);
|
||||
::boost::detail::winapi::CloseHandle(_sink);
|
||||
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Char, class Traits>
|
||||
basic_pipe<Char, Traits>::basic_pipe(const basic_pipe & p)
|
||||
{
|
||||
auto proc = ::boost::detail::winapi::GetCurrentProcess();
|
||||
|
||||
if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, p._source, proc, &_source, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, p._sink, proc, &_sink, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
basic_pipe<Char, Traits>::basic_pipe(const std::string & name)
|
||||
{
|
||||
static constexpr int OPEN_EXISTING_ = 3; //temporary.
|
||||
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
|
||||
//static constexpr int FILE_ATTRIBUTE_NORMAL_ = 0x00000080; //temporary
|
||||
|
||||
::boost::detail::winapi::HANDLE_ source = ::boost::detail::winapi::create_named_pipe(
|
||||
name.c_str(),
|
||||
::boost::detail::winapi::PIPE_ACCESS_INBOUND_
|
||||
| FILE_FLAG_OVERLAPPED_, //write flag
|
||||
0, 1, 8192, 8192, 0, nullptr);
|
||||
|
||||
if (source == boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::process::detail::throw_last_error("create_named_pipe() failed");
|
||||
|
||||
::boost::detail::winapi::HANDLE_ sink = boost::detail::winapi::create_file(
|
||||
name.c_str(),
|
||||
::boost::detail::winapi::GENERIC_WRITE_, 0, nullptr,
|
||||
OPEN_EXISTING_,
|
||||
FILE_FLAG_OVERLAPPED_, //to allow read
|
||||
nullptr);
|
||||
|
||||
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::process::detail::throw_last_error("create_file() failed");
|
||||
|
||||
_source = source;
|
||||
_sink = sink;
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(const basic_pipe & p)
|
||||
{
|
||||
auto proc = ::boost::detail::winapi::GetCurrentProcess();
|
||||
|
||||
if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, p._source, proc, &_source, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, p._sink, proc, &_sink, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(basic_pipe && lhs)
|
||||
{
|
||||
if (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::detail::winapi::CloseHandle(_source);
|
||||
|
||||
if (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::detail::winapi::CloseHandle(_sink);
|
||||
|
||||
_source = lhs._source;
|
||||
_sink = lhs._sink;
|
||||
lhs._source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
lhs._sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator==(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,98 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_CHILD_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_CHILD_HPP
|
||||
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/jobs.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
typedef int pid_t;
|
||||
|
||||
struct child_handle
|
||||
{
|
||||
::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
|
||||
|
||||
explicit child_handle(const ::boost::detail::winapi::PROCESS_INFORMATION_ &pi) :
|
||||
proc_info(pi)
|
||||
{}
|
||||
|
||||
explicit child_handle(pid_t pid) :
|
||||
proc_info{nullptr, nullptr, 0,0}
|
||||
{
|
||||
auto h = ::boost::detail::winapi::OpenProcess(
|
||||
::boost::detail::winapi::PROCESS_ALL_ACCESS_,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(1),
|
||||
pid);
|
||||
|
||||
if (h == nullptr)
|
||||
throw_last_error("OpenProcess() failed");
|
||||
proc_info.hProcess = h;
|
||||
proc_info.dwProcessId = pid;
|
||||
}
|
||||
|
||||
child_handle() = default;
|
||||
~child_handle()
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(proc_info.hProcess);
|
||||
::boost::detail::winapi::CloseHandle(proc_info.hThread);
|
||||
}
|
||||
child_handle(const child_handle & c) = delete;
|
||||
child_handle(child_handle && c) : proc_info(c.proc_info)
|
||||
{
|
||||
c.proc_info.hProcess = ::boost::detail::winapi::invalid_handle_value;
|
||||
c.proc_info.hThread = ::boost::detail::winapi::invalid_handle_value;
|
||||
}
|
||||
child_handle &operator=(const child_handle & c) = delete;
|
||||
child_handle &operator=(child_handle && c)
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(proc_info.hProcess);
|
||||
::boost::detail::winapi::CloseHandle(proc_info.hThread);
|
||||
proc_info = c.proc_info;
|
||||
c.proc_info.hProcess = ::boost::detail::winapi::invalid_handle_value;
|
||||
c.proc_info.hThread = ::boost::detail::winapi::invalid_handle_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pid_t id() const
|
||||
{
|
||||
return static_cast<int>(proc_info.dwProcessId);
|
||||
}
|
||||
|
||||
typedef ::boost::detail::winapi::HANDLE_ process_handle_t;
|
||||
process_handle_t process_handle() const { return proc_info.hProcess; }
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return (proc_info.hProcess != nullptr) &&
|
||||
(proc_info.hProcess != ::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
bool in_group() const
|
||||
{
|
||||
::boost::detail::winapi::BOOL_ value;
|
||||
if (!::boost::detail::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
|
||||
throw_last_error("IsProcessinJob Failed");
|
||||
return value!=0;
|
||||
}
|
||||
bool in_group(std::error_code &ec) const noexcept
|
||||
{
|
||||
::boost::detail::winapi::BOOL_ value;
|
||||
if (!::boost::detail::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
|
||||
ec = get_last_error();
|
||||
return value!=0;
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_
|
||||
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/file_management.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
inline bool compare_handles(boost::detail::winapi::HANDLE_ lhs, boost::detail::winapi::HANDLE_ rhs)
|
||||
{
|
||||
if ( (lhs == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
|| (rhs == ::boost::detail::winapi::INVALID_HANDLE_VALUE_))
|
||||
return false;
|
||||
|
||||
if (lhs == rhs)
|
||||
return true;
|
||||
|
||||
::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ lhs_info{0,0,0,0,0,0,0,0,0,0};
|
||||
::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ rhs_info{0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
if (!::boost::detail::winapi::GetFileInformationByHandle(lhs, &lhs_info))
|
||||
::boost::process::detail::throw_last_error("GetFileInformationByHandle");
|
||||
|
||||
if (!::boost::detail::winapi::GetFileInformationByHandle(rhs, &rhs_info))
|
||||
::boost::process::detail::throw_last_error("GetFileInformationByHandle");
|
||||
|
||||
return (lhs_info.nFileIndexHigh == rhs_info.nFileIndexHigh)
|
||||
&& (lhs_info.nFileIndexLow == rhs_info.nFileIndexLow);
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_ */
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_
|
||||
|
||||
#include <boost/detail/winapi/error_codes.hpp>
|
||||
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/environment.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
template<typename Char>
|
||||
struct env_init : public ::boost::process::detail::handler_base
|
||||
{
|
||||
boost::process::basic_environment<Char> env;
|
||||
|
||||
env_init(boost::process::basic_environment<Char> && env) : env(std::move(env)) {};
|
||||
env_init(const boost::process::basic_environment<Char> & env) : env(env) {};
|
||||
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec) const
|
||||
{
|
||||
auto e = env.native_handle();
|
||||
if (*e == null_char<char>())
|
||||
{
|
||||
exec.set_error(std::error_code(::boost::detail::winapi::ERROR_BAD_ENVIRONMENT_, std::system_category()),
|
||||
"Bad Environment");
|
||||
}
|
||||
|
||||
exec.env = e;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_ */
|
||||
@@ -1,104 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
|
||||
|
||||
#include <boost/detail/winapi/basic_types.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/file_management.hpp>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct file_descriptor
|
||||
{
|
||||
enum mode_t
|
||||
{
|
||||
read = 1,
|
||||
write = 2,
|
||||
read_write = 3
|
||||
};
|
||||
static ::boost::detail::winapi::DWORD_ desired_access(mode_t mode)
|
||||
{
|
||||
switch(mode)
|
||||
{
|
||||
case read:
|
||||
return ::boost::detail::winapi::GENERIC_READ_;
|
||||
case write:
|
||||
return ::boost::detail::winapi::GENERIC_WRITE_;
|
||||
case read_write:
|
||||
return ::boost::detail::winapi::GENERIC_READ_
|
||||
| ::boost::detail::winapi::GENERIC_WRITE_;
|
||||
default:
|
||||
return 0u;
|
||||
}
|
||||
}
|
||||
|
||||
file_descriptor() = default;
|
||||
file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
|
||||
: file_descriptor(p.native(), mode)
|
||||
{
|
||||
}
|
||||
|
||||
file_descriptor(const std::string & path , mode_t mode = read_write)
|
||||
: file_descriptor(path.c_str(), mode) {}
|
||||
file_descriptor(const std::wstring & path, mode_t mode = read_write)
|
||||
: file_descriptor(path.c_str(), mode) {}
|
||||
|
||||
file_descriptor(const char* path, mode_t mode = read_write)
|
||||
: _handle(
|
||||
::boost::detail::winapi::create_file(
|
||||
path,
|
||||
desired_access(mode),
|
||||
::boost::detail::winapi::FILE_SHARE_READ_ |
|
||||
::boost::detail::winapi::FILE_SHARE_WRITE_,
|
||||
nullptr,
|
||||
::boost::detail::winapi::OPEN_ALWAYS_,
|
||||
|
||||
::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
|
||||
nullptr
|
||||
))
|
||||
{
|
||||
|
||||
}
|
||||
file_descriptor(const wchar_t * path, mode_t mode = read_write)
|
||||
: _handle(
|
||||
::boost::detail::winapi::create_file(
|
||||
path,
|
||||
desired_access(mode),
|
||||
::boost::detail::winapi::FILE_SHARE_READ_ |
|
||||
::boost::detail::winapi::FILE_SHARE_WRITE_,
|
||||
nullptr,
|
||||
::boost::detail::winapi::OPEN_ALWAYS_,
|
||||
|
||||
::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
|
||||
nullptr
|
||||
))
|
||||
{
|
||||
|
||||
}
|
||||
file_descriptor(const file_descriptor & ) = delete;
|
||||
file_descriptor(file_descriptor && ) = default;
|
||||
|
||||
file_descriptor& operator=(const file_descriptor & ) = delete;
|
||||
file_descriptor& operator=(file_descriptor && ) = default;
|
||||
|
||||
~file_descriptor()
|
||||
{
|
||||
if (_handle != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::detail::winapi::CloseHandle(_handle);
|
||||
}
|
||||
|
||||
::boost::detail::winapi::HANDLE_ handle() const { return _handle;}
|
||||
|
||||
private:
|
||||
::boost::detail::winapi::HANDLE_ _handle = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/file_descriptor.hpp>
|
||||
#include <io.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct file_in : public ::boost::process::detail::handler_base
|
||||
{
|
||||
file_descriptor file;
|
||||
::boost::detail::winapi::HANDLE_ handle = file.handle();
|
||||
|
||||
template<typename T>
|
||||
file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {}
|
||||
file_in(FILE * f) : handle(reinterpret_cast<::boost::detail::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
e.startup_info.hStdInput = handle;
|
||||
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2106 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_IS_RUNNING_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_IS_RUNNING_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <cstdlib>
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
constexpr static ::boost::detail::winapi::DWORD_ still_active = 259;
|
||||
|
||||
|
||||
struct child_handle;
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code)
|
||||
{
|
||||
::boost::detail::winapi::DWORD_ code;
|
||||
//single value, not needed in the winapi.
|
||||
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &code))
|
||||
::boost::process::detail::throw_last_error("GetExitCodeProcess() failed");
|
||||
|
||||
if (code == still_active)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
exit_code = code;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
::boost::detail::winapi::DWORD_ code;
|
||||
//single value, not needed in the winapi.
|
||||
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &code))
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
if (code == still_active)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
exit_code = code;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_running(int code)
|
||||
{
|
||||
return code == still_active;
|
||||
}
|
||||
|
||||
inline int eval_exit_status(int in ) {return in;}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,139 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_
|
||||
|
||||
#include <boost/detail/winapi/config.hpp>
|
||||
#include <boost/detail/winapi/basic_types.hpp>
|
||||
#include <boost/detail/winapi/dll.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows { namespace workaround {
|
||||
|
||||
//this import workaround is to keep it a header-only library. and enums cannot be imported from the winapi.
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
typedef enum _JOBOBJECTINFOCLASS_ {
|
||||
JobObjectBasicAccountingInformation_ = 1, JobObjectBasicLimitInformation_,
|
||||
JobObjectBasicProcessIdList_, JobObjectBasicUIRestrictions_,
|
||||
JobObjectSecurityLimitInformation_, JobObjectEndOfJobTimeInformation_,
|
||||
JobObjectAssociateCompletionPortInformation_, JobObjectBasicAndIoAccountingInformation_,
|
||||
JobObjectExtendedLimitInformation_, JobObjectJobSetInformation_,
|
||||
JobObjectGroupInformation_,
|
||||
JobObjectNotificationLimitInformation_,
|
||||
JobObjectLimitViolationInformation_,
|
||||
JobObjectGroupInformationEx_,
|
||||
JobObjectCpuRateControlInformation_,
|
||||
JobObjectCompletionFilter_,
|
||||
JobObjectCompletionCounter_,
|
||||
JobObjectReserved1Information_ = 18,
|
||||
JobObjectReserved2Information_,
|
||||
JobObjectReserved3Information_,
|
||||
JobObjectReserved4Information_,
|
||||
JobObjectReserved5Information_,
|
||||
JobObjectReserved6Information_,
|
||||
JobObjectReserved7Information_,
|
||||
JobObjectReserved8Information_,
|
||||
MaxJobObjectInfoClass_
|
||||
} JOBOBJECTINFOCLASS_;
|
||||
|
||||
typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION_ {
|
||||
::boost::detail::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit;
|
||||
::boost::detail::winapi::LARGE_INTEGER_ PerJobUserTimeLimit;
|
||||
::boost::detail::winapi::DWORD_ LimitFlags;
|
||||
::boost::detail::winapi::SIZE_T_ MinimumWorkingSetSize;
|
||||
::boost::detail::winapi::SIZE_T_ MaximumWorkingSetSize;
|
||||
::boost::detail::winapi::DWORD_ ActiveProcessLimit;
|
||||
::boost::detail::winapi::ULONG_PTR_ Affinity;
|
||||
::boost::detail::winapi::DWORD_ PriorityClass;
|
||||
::boost::detail::winapi::DWORD_ SchedulingClass;
|
||||
} JOBOBJECT_BASIC_LIMIT_INFORMATION_;
|
||||
|
||||
|
||||
typedef struct _IO_COUNTERS_ {
|
||||
::boost::detail::winapi::ULONGLONG_ ReadOperationCount;
|
||||
::boost::detail::winapi::ULONGLONG_ WriteOperationCount;
|
||||
::boost::detail::winapi::ULONGLONG_ OtherOperationCount;
|
||||
::boost::detail::winapi::ULONGLONG_ ReadTransferCount;
|
||||
::boost::detail::winapi::ULONGLONG_ WriteTransferCount;
|
||||
::boost::detail::winapi::ULONGLONG_ OtherTransferCount;
|
||||
} IO_COUNTERS_;
|
||||
|
||||
|
||||
typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ {
|
||||
JOBOBJECT_BASIC_LIMIT_INFORMATION_ BasicLimitInformation;
|
||||
IO_COUNTERS_ IoInfo;
|
||||
::boost::detail::winapi::SIZE_T_ ProcessMemoryLimit;
|
||||
::boost::detail::winapi::SIZE_T_ JobMemoryLimit;
|
||||
::boost::detail::winapi::SIZE_T_ PeakProcessMemoryUsed;
|
||||
::boost::detail::winapi::SIZE_T_ PeakJobMemoryUsed;
|
||||
} JOBOBJECT_EXTENDED_LIMIT_INFORMATION_;
|
||||
|
||||
|
||||
/*BOOL WINAPI QueryInformationJobObject(
|
||||
_In_opt_ HANDLE hJob,
|
||||
_In_ JOBOBJECTINFOCLASS JobObjectInfoClass,
|
||||
_Out_ LPVOID lpJobObjectInfo,
|
||||
_In_ DWORD cbJobObjectInfoLength,
|
||||
_Out_opt_ LPDWORD lpReturnLength
|
||||
);
|
||||
*/
|
||||
typedef ::boost::detail::winapi::BOOL_ ( WINAPI *query_information_job_object_p)(
|
||||
::boost::detail::winapi::HANDLE_,
|
||||
JOBOBJECTINFOCLASS_,
|
||||
void *,
|
||||
::boost::detail::winapi::DWORD_,
|
||||
::boost::detail::winapi::DWORD_ *);
|
||||
|
||||
|
||||
inline ::boost::detail::winapi::BOOL_ WINAPI query_information_job_object(
|
||||
::boost::detail::winapi::HANDLE_ hJob,
|
||||
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
|
||||
void * lpJobObjectInfo,
|
||||
::boost::detail::winapi::DWORD_ cbJobObjectInfoLength,
|
||||
::boost::detail::winapi::DWORD_ *lpReturnLength)
|
||||
{
|
||||
static ::boost::detail::winapi::HMODULE_ h = ::boost::detail::winapi::get_module_handle("Kernel32.dll");
|
||||
static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::detail::winapi::get_proc_address(h, "QueryInformationJobObject"));
|
||||
|
||||
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength);
|
||||
}
|
||||
|
||||
/*BOOL WINAPI SetInformationJobObject(
|
||||
_In_ HANDLE hJob,
|
||||
_In_ JOBOBJECTINFOCLASS JobObjectInfoClass,
|
||||
_In_ LPVOID lpJobObjectInfo,
|
||||
_In_ DWORD cbJobObjectInfoLength
|
||||
);*/
|
||||
|
||||
typedef ::boost::detail::winapi::BOOL_ ( WINAPI *set_information_job_object_p)(
|
||||
::boost::detail::winapi::HANDLE_,
|
||||
JOBOBJECTINFOCLASS_,
|
||||
void *,
|
||||
::boost::detail::winapi::DWORD_);
|
||||
|
||||
}
|
||||
|
||||
inline ::boost::detail::winapi::BOOL_ WINAPI set_information_job_object(
|
||||
::boost::detail::winapi::HANDLE_ hJob,
|
||||
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
|
||||
void * lpJobObjectInfo,
|
||||
::boost::detail::winapi::DWORD_ cbJobObjectInfoLength)
|
||||
{
|
||||
static ::boost::detail::winapi::HMODULE_ h = ::boost::detail::winapi::get_module_handle("Kernel32.dll");
|
||||
static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::detail::winapi::get_proc_address(h, "SetInformationJobObject"));
|
||||
|
||||
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength);
|
||||
}
|
||||
|
||||
constexpr static ::boost::detail::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800;
|
||||
|
||||
}}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/handle_info.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/file_descriptor.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct null_in : public ::boost::process::detail::handler_base
|
||||
{
|
||||
file_descriptor source{"NUL", file_descriptor::read};
|
||||
|
||||
public:
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(source.handle(),
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdInput = source.handle();
|
||||
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <system_error>
|
||||
#include <functional>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct on_exit_ : boost::process::detail::windows::async_handler
|
||||
{
|
||||
std::function<void(int, const std::error_code&)> handler;
|
||||
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
|
||||
{
|
||||
auto handler = this->handler;
|
||||
::boost::detail::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info;
|
||||
auto process_handle = proc.hProcess;
|
||||
return [handler, process_handle](int exit_code, const std::error_code & ec)
|
||||
{
|
||||
handler(static_cast<int>(exit_code), ec);
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */
|
||||
@@ -1,52 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <cstdio>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct pipe_in : public ::boost::process::detail::handler_base
|
||||
{
|
||||
::boost::detail::winapi::HANDLE_ handle;
|
||||
template<typename T>
|
||||
pipe_in(const T & p) : handle(p.native_source()) {}
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdInput = handle;
|
||||
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
template<typename WindowsExecutor>
|
||||
void on_error(WindowsExecutor &, const std::error_code &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(handle);
|
||||
}
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_success(WindowsExecutor &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,87 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct pipe_out : public ::boost::process::detail::handler_base
|
||||
{
|
||||
::boost::detail::winapi::HANDLE_ handle;
|
||||
|
||||
template<typename T>
|
||||
pipe_out(const T & p) : handle(p.native_sink()) {}
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const;
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_error(WindowsExecutor &, const std::error_code &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(handle);
|
||||
}
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_success(WindowsExecutor &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(handle);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void pipe_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void pipe_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void pipe_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_SEARCH_PATH_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_SEARCH_PATH_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <boost/detail/winapi/shell.hpp>
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
inline boost::filesystem::path search_path(
|
||||
const boost::filesystem::path &filename,
|
||||
const std::vector<boost::filesystem::path> &path)
|
||||
{
|
||||
for (const boost::filesystem::path & pp : path)
|
||||
{
|
||||
auto p = pp / filename;
|
||||
std::array<std::string, 4> extensions = { "", ".exe", ".com", ".bat" };
|
||||
for (boost::filesystem::path ext : extensions)
|
||||
{
|
||||
p += ext;
|
||||
boost::system::error_code ec;
|
||||
bool file = boost::filesystem::is_regular_file(p, ec);
|
||||
if (!ec && file &&
|
||||
::boost::detail::winapi::sh_get_file_info(p.string().c_str(), 0, 0, 0, ::boost::detail::winapi::SHGFI_EXETYPE_))
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_SHELL_PATH_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_SHELL_PATH_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/detail/winapi/basic_types.hpp>
|
||||
#include <boost/detail/winapi/get_system_directory.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
inline boost::filesystem::path shell_path()
|
||||
{
|
||||
::boost::detail::winapi::WCHAR_ sysdir[260];
|
||||
unsigned int size = ::boost::detail::winapi::get_system_directory(sysdir, sizeof(sysdir));
|
||||
if (!size)
|
||||
throw_last_error("GetSystemDirectory() failed");
|
||||
|
||||
boost::filesystem::path p = sysdir;
|
||||
return p / "cmd.exe";
|
||||
}
|
||||
|
||||
inline boost::filesystem::path shell_path(std::error_code &ec) noexcept
|
||||
{
|
||||
|
||||
::boost::detail::winapi::WCHAR_ sysdir[260];
|
||||
unsigned int size = ::boost::detail::winapi::get_system_directory(sysdir, sizeof(sysdir));
|
||||
boost::filesystem::path p;
|
||||
if (!size)
|
||||
ec = std::error_code(
|
||||
::boost::detail::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
p = sysdir;
|
||||
p /= "cmd.exe";
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/show_window.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
template<::boost::detail::winapi::WORD_ Flags>
|
||||
struct show_window : ::boost::process::detail::handler_base
|
||||
{
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESHOWWINDOW_;
|
||||
e.startup_info.wShowWindow |= Flags;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_TERMINATE_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_TERMINATE_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <cstdlib>
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/get_last_error.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct child_handle;
|
||||
|
||||
inline void terminate(child_handle &p)
|
||||
{
|
||||
if (!::boost::detail::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
|
||||
boost::process::detail::throw_last_error("TerminateProcess() failed");
|
||||
|
||||
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
}
|
||||
|
||||
inline void terminate(child_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
if (!::boost::detail::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,193 +0,0 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_WAIT_FOR_EXIT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_WAIT_FOR_EXIT_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/detail/winapi/synchronization.hpp>
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/process/detail/windows/child_handle.hpp>
|
||||
#include <chrono>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
inline void wait(child_handle &p, int & exit_code)
|
||||
{
|
||||
if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
|
||||
::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
|
||||
::boost::detail::winapi::DWORD_ _exit_code;
|
||||
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
throw_last_error("GetExitCodeProcess() failed");
|
||||
|
||||
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
}
|
||||
|
||||
inline void wait(child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
::boost::detail::winapi::DWORD_ _exit_code = 1;
|
||||
|
||||
if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
|
||||
::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed)
|
||||
ec = std::error_code(
|
||||
::boost::detail::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
ec = std::error_code(
|
||||
::boost::detail::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
|
||||
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
|
||||
|
||||
::boost::detail::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
|
||||
static_cast<::boost::detail::winapi::DWORD_>(ms.count()));
|
||||
if (wait_code == ::boost::detail::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
else if (wait_code == ::boost::detail::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
::boost::detail::winapi::DWORD_ _exit_code;
|
||||
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
throw_last_error("GetExitCodeProcess() failed");
|
||||
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code &ec) noexcept
|
||||
{
|
||||
|
||||
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
|
||||
|
||||
|
||||
::boost::detail::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
|
||||
static_cast<::boost::detail::winapi::DWORD_>(ms.count()));
|
||||
if (wait_code == ::boost::detail::winapi::wait_failed)
|
||||
ec = std::error_code(
|
||||
::boost::detail::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else if (wait_code == ::boost::detail::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
::boost::detail::winapi::DWORD_ _exit_code = 1;
|
||||
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
{
|
||||
ec = std::error_code(
|
||||
::boost::detail::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
return true;
|
||||
;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time)
|
||||
{
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - std::chrono::system_clock::now());
|
||||
|
||||
::boost::detail::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
|
||||
static_cast<::boost::detail::winapi::DWORD_>(ms.count()));
|
||||
|
||||
if (wait_code == ::boost::detail::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
else if (wait_code == ::boost::detail::winapi::wait_timeout)
|
||||
return false;
|
||||
|
||||
::boost::detail::winapi::DWORD_ _exit_code;
|
||||
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
throw_last_error("GetExitCodeProcess() failed");
|
||||
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time,
|
||||
std::error_code &ec) noexcept
|
||||
{
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - std::chrono::system_clock::now());
|
||||
|
||||
::boost::detail::winapi::DWORD_ _exit_code = 1;
|
||||
|
||||
if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
|
||||
static_cast<::boost::detail::winapi::DWORD_>(ms.count()))
|
||||
== ::boost::detail::winapi::wait_failed)
|
||||
ec = std::error_code(
|
||||
::boost::detail::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
ec = std::error_code(
|
||||
::boost::detail::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
exit_code = static_cast<int>(exit_code);
|
||||
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
return true;
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -1,121 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/detail/winapi/jobs.hpp>
|
||||
#include <boost/detail/winapi/wait.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct group_handle;
|
||||
|
||||
inline void wait(const group_handle &p)
|
||||
{
|
||||
if (::boost::detail::winapi::WaitForSingleObject(p.handle(),
|
||||
::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
|
||||
}
|
||||
|
||||
inline void wait(const group_handle &p, std::error_code &ec)
|
||||
{
|
||||
if (::boost::detail::winapi::WaitForSingleObject(p.handle(),
|
||||
::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
|
||||
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
|
||||
|
||||
::boost::detail::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count());
|
||||
if (wait_code == ::boost::detail::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
else if (wait_code == ::boost::detail::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code &ec)
|
||||
{
|
||||
|
||||
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
|
||||
|
||||
|
||||
::boost::detail::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count());
|
||||
if (wait_code == ::boost::detail::winapi::wait_failed)
|
||||
ec = get_last_error();
|
||||
|
||||
else if (wait_code == ::boost::detail::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time)
|
||||
{
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - std::chrono::system_clock::now());
|
||||
|
||||
::boost::detail::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count());
|
||||
|
||||
if (wait_code == ::boost::detail::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
|
||||
else if (wait_code == ::boost::detail::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time,
|
||||
std::error_code &ec)
|
||||
{
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - std::chrono::system_clock::now());
|
||||
|
||||
::boost::detail::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count());
|
||||
|
||||
if (wait_code == ::boost::detail::winapi::wait_failed)
|
||||
ec = get_last_error();
|
||||
|
||||
else if (wait_code == ::boost::detail::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
return true;
|
||||
;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_ */
|
||||
@@ -1,483 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_ENV_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_ENV_HPP_
|
||||
|
||||
#include <boost/process/environment.hpp>
|
||||
#include <boost/none.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/env_init.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/env_init.hpp>
|
||||
#endif
|
||||
|
||||
/** \file boost/process/env.hpp
|
||||
*
|
||||
* This header which provides the `env` property. It allows the modification of the
|
||||
* environment the child process will run in, in a functional style.
|
||||
*
|
||||
* \xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::env">env</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
* \endxmlonly
|
||||
*
|
||||
* For additional information see the platform documentations:
|
||||
*
|
||||
* - [windows](https://msdn.microsoft.com/en-US/library/windows/desktop/ms682653.aspx)
|
||||
* - [posix](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace process { namespace detail {
|
||||
|
||||
|
||||
template<typename Char>
|
||||
std::size_t make_env_string_size(const std::basic_string<Char> & ch)
|
||||
{
|
||||
return ch.size() + 1;
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
std::size_t make_env_string_size(const Char * ch)
|
||||
{
|
||||
std::size_t sz = 0;
|
||||
while (ch[sz] != null_char<Char>())
|
||||
sz++;
|
||||
|
||||
sz++;
|
||||
return sz;
|
||||
}
|
||||
|
||||
template<typename Char, typename Container>
|
||||
inline std::basic_string<Char> make_env_string(const Container & value)
|
||||
{
|
||||
std::size_t sz = 0;
|
||||
for (auto & v : value)
|
||||
sz += make_env_string_size(v);
|
||||
|
||||
std::basic_string<Char> s;
|
||||
s.reserve(sz); //+1 for ;, end doesn't have one.
|
||||
|
||||
for (auto & val : value)
|
||||
(s += val) += api::env_seperator<Char>();
|
||||
|
||||
s.resize(s.size() -1); //remove last ';'
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_set
|
||||
{
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type key;
|
||||
string_type value;
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
struct env_append
|
||||
{
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type key;
|
||||
string_type value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_reset
|
||||
{
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type key;
|
||||
};
|
||||
|
||||
|
||||
template<> struct is_wchar_t<env_set<wchar_t>> : std::true_type {};
|
||||
template<> struct is_wchar_t<env_append<wchar_t>> : std::true_type {};
|
||||
template<> struct is_wchar_t<env_reset<wchar_t>> : std::true_type {};
|
||||
template<> struct is_wchar_t<basic_environment<wchar_t>> : std::true_type {};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_set<wchar_t>>
|
||||
{
|
||||
static env_set<char> conv(const env_set<wchar_t> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key),
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_set<char>>
|
||||
{
|
||||
static env_set<wchar_t> conv(const env_set<char> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key),
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_append<wchar_t>>
|
||||
{
|
||||
static env_append<char> conv(const env_append<wchar_t> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key),
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_append<char>>
|
||||
{
|
||||
static env_append<wchar_t> conv(const env_append<char> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key),
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_reset<wchar_t>>
|
||||
{
|
||||
static env_reset<char> conv(const env_reset<wchar_t> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_reset<char>>
|
||||
{
|
||||
static env_reset<wchar_t> conv(const env_reset<char> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_init
|
||||
{
|
||||
basic_environment<Char> env;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_init<wchar_t>>
|
||||
{
|
||||
static env_init<char> conv(const env_init<wchar_t> & in)
|
||||
{
|
||||
return {basic_environment<char>(in.env)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_init<char>>
|
||||
{
|
||||
static env_init<wchar_t> conv(const env_init<char> & in)
|
||||
{
|
||||
return {basic_environment<wchar_t>(in.env)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_proxy
|
||||
{
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type key;
|
||||
|
||||
|
||||
env_set<Char> operator=(const string_type & value)
|
||||
{
|
||||
return {std::move(key), value};
|
||||
}
|
||||
env_set<Char> operator=(const std::vector<string_type> & value)
|
||||
{
|
||||
return {std::move(key), make_env_string<Char>(value)};
|
||||
}
|
||||
env_set<Char> operator=(const std::initializer_list<const Char*> & value)
|
||||
{
|
||||
return {std::move(key), make_env_string<Char>(value)};
|
||||
}
|
||||
|
||||
env_append<Char> operator+=(const string_type & value)
|
||||
{
|
||||
return {std::move(key), value};
|
||||
}
|
||||
env_append<Char> operator+=(const std::vector<string_type> & value)
|
||||
{
|
||||
return {std::move(key), make_env_string<Char>(value)};
|
||||
}
|
||||
env_append<Char> operator+=(const std::initializer_list<const Char*> & value)
|
||||
{
|
||||
return {std::move(key), make_env_string<Char>(value)};
|
||||
}
|
||||
env_reset<Char> operator=(boost::none_t)
|
||||
{
|
||||
return {std::move(key)};
|
||||
}
|
||||
};
|
||||
|
||||
struct env_
|
||||
{
|
||||
constexpr env_() {};
|
||||
|
||||
template<typename Char>
|
||||
env_set<Char> operator()(const std::basic_string<Char> & key,
|
||||
const std::basic_string<Char> & value) const
|
||||
{
|
||||
return {key, value};
|
||||
}
|
||||
template<typename Char>
|
||||
env_set<Char> operator()(const std::basic_string<Char> & key,
|
||||
const std::vector<std::basic_string<Char>> & value) const
|
||||
{
|
||||
return {key, make_env_string<Char>(value)};
|
||||
}
|
||||
template<typename Char>
|
||||
env_set<Char> operator()(const std::basic_string<Char> & key,
|
||||
const std::initializer_list<Char*> & value) const
|
||||
{
|
||||
return {key, make_env_string<Char>(value)};
|
||||
}
|
||||
template<typename Char>
|
||||
env_reset<Char> operator()(const std::basic_string<Char> & key, boost::none_t)
|
||||
{
|
||||
return {key};
|
||||
}
|
||||
template<typename Char>
|
||||
env_proxy<Char> operator[](const std::basic_string<Char> & key) const
|
||||
{
|
||||
return {key};
|
||||
}
|
||||
template<typename Char>
|
||||
env_proxy<Char> operator[](const Char* key) const
|
||||
{
|
||||
return {key};
|
||||
}
|
||||
template<typename Char>
|
||||
env_init<Char> operator()(const basic_environment<Char> & env) const
|
||||
{
|
||||
return {env};
|
||||
}
|
||||
template<typename Char>
|
||||
env_init<Char> operator= (const basic_environment<Char> & env) const
|
||||
{
|
||||
return {env};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
struct env_builder
|
||||
{
|
||||
basic_environment<Char> env;
|
||||
void operator()(const basic_environment<Char> & e)
|
||||
{
|
||||
env = e;
|
||||
}
|
||||
|
||||
void operator()(env_init<Char> & ei)
|
||||
{
|
||||
env = std::move(ei.env);
|
||||
}
|
||||
void operator()(env_set<Char> & es)
|
||||
{
|
||||
env[es.key] = es.value;
|
||||
}
|
||||
void operator()(env_reset<Char> & es)
|
||||
{
|
||||
env.erase(es.key);
|
||||
}
|
||||
template<typename T>
|
||||
void operator()(env_append<T> & es)
|
||||
{
|
||||
env[es.key] += es.value;
|
||||
}
|
||||
|
||||
typedef api::env_init<Char> result_type;
|
||||
api::env_init<Char> get_initializer()
|
||||
{
|
||||
return api::env_init<Char>(std::move(env));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_builder<env_tag<char>>
|
||||
{
|
||||
typedef env_builder<char> type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_builder<env_tag<wchar_t>>
|
||||
{
|
||||
typedef env_builder<wchar_t> type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
The `env` property provides a functional way to modify the environment used by
|
||||
the child process. If none is passed the environment is inherited from the father
|
||||
process. Appending means that the environment will be interpreted as a ';' or ':'
|
||||
seperated list as used in `PATH`.
|
||||
|
||||
On both `posix` and `windows` the environment variables can be lists of strings,
|
||||
seperated by ';'. This is typically used for the `PATH` variable.
|
||||
|
||||
By default the environment will be inherited from the launching process,
|
||||
which is also true if environment are modified with this initializer.
|
||||
|
||||
\section env_details Details
|
||||
|
||||
\subsection env_operations Operations
|
||||
|
||||
\subsubsection env_set_var Setting variables
|
||||
|
||||
To set a variable `id` the value `value` the following syntax can be used.
|
||||
|
||||
\code{.cpp}
|
||||
env[id] = value;
|
||||
env(id, value);
|
||||
\endcode
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
\code{.cpp}
|
||||
env[id] = {value1, value2};
|
||||
env(id, {value1, value2});
|
||||
\endcode
|
||||
|
||||
\note Creates the variable if it does not exist.
|
||||
|
||||
The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
|
||||
for both `id` and `value`.
|
||||
|
||||
\paragraph id id
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
\paragraph env_set_var_value value
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type * `
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
|
||||
\note Using `std::vector` or `std::initializer_list`
|
||||
|
||||
\subsubsection env_append_var Append variables
|
||||
|
||||
Appending means, that a variable will be interpreted as a
|
||||
To append a variable `id` the value `value` the following syntax can be used:
|
||||
|
||||
\code{.cpp}
|
||||
env[id] += value;
|
||||
\endcode
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
\code{.cpp}
|
||||
env[id] += {value1, value2};
|
||||
\endcode
|
||||
|
||||
\note Creates the variable if it does not exist.
|
||||
|
||||
The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
|
||||
for both `id` and `value`.
|
||||
|
||||
\paragraph env_append_var_id id
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
\paragraph env_append_var_value value
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
|
||||
\subsubsection env_reset Reset variables
|
||||
|
||||
Reseting signle variables can be done in the following way:
|
||||
|
||||
\code{.cpp}
|
||||
env[id] = boost::none;
|
||||
env(id, boost::none);
|
||||
\endcode
|
||||
|
||||
\note This does not set the value empty, but removes it from the list.
|
||||
|
||||
The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`:
|
||||
|
||||
\paragraph env_reset_var_id id
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
\subsubsection env_init Initialize the environment
|
||||
|
||||
The whole environment can be initialized from an object of type
|
||||
\xmlonly <classname>boost::process::environment</classname> \endxmlonly
|
||||
|
||||
\code{.cpp}
|
||||
env=env;
|
||||
env(env);
|
||||
\endcode
|
||||
|
||||
\note The passed `environment` can also be default-constructed to get an empty environment.
|
||||
|
||||
\paragraph env_init_var_id id
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
\paragraph env_init_var_value value
|
||||
|
||||
- `boost::process::basic_environment<char_type>`
|
||||
|
||||
\subsection env_example Example
|
||||
|
||||
\code{.cpp}
|
||||
spawn("b2", env["PATH"]+="F:/boost", env["SOME_VAR"]=boost::none, env["NEW_VAR"]="VALUE");
|
||||
\endcode
|
||||
|
||||
If the overload style should be done by passing an instance of
|
||||
\xmlonly <classname>boost::process::environment</classname> \endxmlonly
|
||||
the above example would look like this.
|
||||
|
||||
\code{.cpp}
|
||||
environment e = this_process::environment();
|
||||
e["PATH"] += "F:/boost";
|
||||
e.erase("SOME_VAR");
|
||||
e["NEW_VAR"] = "VALUE";
|
||||
spawn("b2", e);
|
||||
\endcode
|
||||
|
||||
\warning Passing an empty environment will cause undefined behaviour.
|
||||
|
||||
*/
|
||||
constexpr static boost::process::detail::env_ env{};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/env.hpp>")
|
||||
#include <boost/process/v1/env.hpp>
|
||||
|
||||
@@ -1,693 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_ENVIRONMENT_HPP_
|
||||
#define BOOST_PROCESS_ENVIRONMENT_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/environment.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/environment.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename Char, typename Environment>
|
||||
struct const_entry
|
||||
{
|
||||
using value_type = Char ;
|
||||
using pointer = const value_type * ;
|
||||
using string_type = std::basic_string<value_type> ;
|
||||
using range = boost::iterator_range<pointer> ;
|
||||
using environment_t = Environment ;
|
||||
|
||||
std::vector<string_type> to_vector() const
|
||||
{
|
||||
if (_data == nullptr)
|
||||
return std::vector<string_type>();
|
||||
std::vector<string_type> data;
|
||||
auto str = string_type(_data);
|
||||
struct splitter
|
||||
{
|
||||
bool operator()(wchar_t w) const {return w == api::env_seperator<wchar_t>();}
|
||||
bool operator()(char c) const {return c == api::env_seperator<char> ();}
|
||||
} s;
|
||||
boost::split(data, _data, s);
|
||||
return std::move(data);
|
||||
}
|
||||
string_type to_string() const
|
||||
{
|
||||
if (_data != nullptr)
|
||||
return string_type(_data);
|
||||
else
|
||||
return string_type();
|
||||
}
|
||||
string_type get_name() const {return string_type(_name.begin(), _name.end());}
|
||||
explicit const_entry(string_type&& name, pointer data, environment_t & env_) :
|
||||
_name(std::move(name)), _data(data), _env(&env_) {}
|
||||
|
||||
explicit const_entry(string_type &&name, environment_t & env) :
|
||||
_name(std::move(name)), _data(nullptr), _env(&env) {}
|
||||
const_entry(const const_entry&) = default;
|
||||
const_entry& operator=(const const_entry&) = default;
|
||||
|
||||
void reload()
|
||||
{
|
||||
auto p = _env->find(_name);
|
||||
if (p == _env->end())
|
||||
_data = nullptr;
|
||||
else
|
||||
_data = p->_data;
|
||||
this->_env->reload();
|
||||
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return _data == nullptr;
|
||||
}
|
||||
protected:
|
||||
string_type _name;
|
||||
pointer _data;
|
||||
environment_t * _env;
|
||||
};
|
||||
|
||||
template<typename Char, typename Environment>
|
||||
struct entry : const_entry<Char, Environment>
|
||||
{
|
||||
using father = const_entry<Char, Environment>;
|
||||
using value_type = typename father::value_type;
|
||||
using string_type = typename father::string_type;
|
||||
using pointer = typename father::pointer;
|
||||
using environment_t = typename father::environment_t;
|
||||
|
||||
explicit entry(string_type&& name, pointer data, environment_t & env) :
|
||||
father(std::move(name), data, env) {}
|
||||
|
||||
explicit entry(string_type &&name, environment_t & env) :
|
||||
father(std::move(name), env) {}
|
||||
|
||||
entry(const entry&) = default;
|
||||
entry& operator=(const entry&) = default;
|
||||
|
||||
void assign(const string_type &value)
|
||||
{
|
||||
this->_env->set(this->_name, value);
|
||||
this->reload();
|
||||
}
|
||||
void assign(const std::vector<string_type> &value)
|
||||
{
|
||||
string_type data;
|
||||
for (auto &v : value)
|
||||
{
|
||||
if (&v != &value.front())
|
||||
data += api::env_seperator<value_type>();
|
||||
data += v;
|
||||
}
|
||||
this->_env->set(this->_name, data);
|
||||
this->reload();
|
||||
|
||||
}
|
||||
void assign(const std::initializer_list<string_type> &value)
|
||||
{
|
||||
string_type data;
|
||||
for (auto &v : value)
|
||||
{
|
||||
if (&v != &*value.begin())
|
||||
data += api::env_seperator<value_type>();
|
||||
data += v;
|
||||
}
|
||||
this->_env->set(this->_name, data);
|
||||
this->reload();
|
||||
|
||||
}
|
||||
void append(const string_type &value)
|
||||
{
|
||||
if (this->_data == nullptr)
|
||||
this->_env->set(this->_name, value);
|
||||
else
|
||||
{
|
||||
string_type st = this->_data;
|
||||
this->_env->set(this->_name, st + api::env_seperator<value_type>() + value);
|
||||
|
||||
}
|
||||
this->reload();
|
||||
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
this->_env->reset(this->_name);
|
||||
this->_env->reload();
|
||||
this->_data = nullptr;
|
||||
}
|
||||
entry &operator=(const string_type & value)
|
||||
{
|
||||
assign(value);
|
||||
return *this;
|
||||
}
|
||||
entry &operator=(const std::vector<string_type> & value)
|
||||
{
|
||||
assign(value);
|
||||
return *this;
|
||||
}
|
||||
entry &operator=(const std::initializer_list<string_type> & value)
|
||||
{
|
||||
assign(value);
|
||||
return *this;
|
||||
}
|
||||
entry &operator+=(const string_type & value)
|
||||
{
|
||||
append(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Char, typename Environment>
|
||||
struct make_entry
|
||||
{
|
||||
|
||||
make_entry(const make_entry&) = default;
|
||||
make_entry& operator=(const make_entry&) = default;
|
||||
|
||||
Environment *env;
|
||||
make_entry(Environment & env) : env(&env) {};
|
||||
entry<Char, Environment> operator()(const Char* data) const
|
||||
{
|
||||
auto p = data;
|
||||
while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
|
||||
p++;
|
||||
auto name = std::basic_string<Char>(data, p);
|
||||
p++; //go behind equal sign
|
||||
|
||||
return entry<Char, Environment>(std::move(name), p, *env);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Char, typename Environment>
|
||||
struct make_const_entry
|
||||
{
|
||||
|
||||
make_const_entry(const make_const_entry&) = default;
|
||||
make_const_entry& operator=(const make_const_entry&) = default;
|
||||
|
||||
Environment *env;
|
||||
make_const_entry(Environment & env) : env(&env) {};
|
||||
const_entry<Char, Environment> operator()(const Char* data) const
|
||||
{
|
||||
auto p = data;
|
||||
while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
|
||||
p++;
|
||||
auto name = std::basic_string<Char>(data, p);
|
||||
p++; //go behind equal sign
|
||||
|
||||
return const_entry<Char, Environment>(std::move(name), p, *env);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#if !defined (BOOST_PROCESS_DOXYGEN)
|
||||
|
||||
template<typename Char, template <class> class Implementation = detail::api::basic_environment_impl>
|
||||
class basic_environment_impl : public Implementation<Char>
|
||||
{
|
||||
Char** _get_end() const
|
||||
{
|
||||
auto p = this->_env_impl;
|
||||
while (*p != nullptr)
|
||||
p++;
|
||||
|
||||
return p;
|
||||
}
|
||||
public:
|
||||
using string_type = std::basic_string<Char>;
|
||||
using implementation_type = Implementation<Char>;
|
||||
using base_type = basic_environment_impl<Char, Implementation>;
|
||||
using entry_maker = detail::make_entry<Char, base_type>;
|
||||
using entry_type = detail::entry <Char, base_type>;
|
||||
using const_entry_type = detail::const_entry <Char, const base_type>;
|
||||
using const_entry_maker = detail::make_const_entry<Char, const base_type>;
|
||||
|
||||
friend entry_type;
|
||||
friend const_entry_type;
|
||||
|
||||
using iterator = boost::transform_iterator< entry_maker, Char**, entry_type, entry_type>;
|
||||
using const_iterator = boost::transform_iterator<const_entry_maker, Char**, const_entry_type, const_entry_type>;
|
||||
using size_type = std::size_t;
|
||||
|
||||
iterator begin() {return iterator(this->_env_impl, entry_maker(*this));}
|
||||
const_iterator begin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
|
||||
const_iterator cbegin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
|
||||
|
||||
iterator end() {return iterator(_get_end(), entry_maker(*this));}
|
||||
const_iterator end() const {return const_iterator(_get_end(), const_entry_maker(*this));}
|
||||
const_iterator cend() const {return const_iterator(_get_end(), const_entry_maker(*this));}
|
||||
|
||||
iterator find( const string_type& key )
|
||||
{
|
||||
auto p = this->_env_impl;
|
||||
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
if (std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
return iterator(p, entry_maker(*this));
|
||||
}
|
||||
const_iterator find( const string_type& key ) const
|
||||
{
|
||||
auto p = this->_env_impl;
|
||||
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
if (std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
return const_iterator(p, const_entry_maker(*this));
|
||||
}
|
||||
|
||||
std::size_t count(const string_type & st) const
|
||||
{
|
||||
auto p = this->_env_impl;
|
||||
auto st1 = st + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
if (std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
void erase(const string_type & id)
|
||||
{
|
||||
implementation_type::reset(id);
|
||||
}
|
||||
std::pair<iterator,bool> emplace(const string_type & id, const string_type & value)
|
||||
{
|
||||
auto p = this->_env_impl;
|
||||
auto st1 = id + ::boost::process::detail::equal_sign<Char>();
|
||||
auto f = find(id);
|
||||
if (f != end())
|
||||
{
|
||||
implementation_type::set(id, value);
|
||||
return std::pair<iterator, bool>(find(id), true);
|
||||
|
||||
}
|
||||
else
|
||||
return std::pair<iterator, bool>(f, true);
|
||||
}
|
||||
using implementation_type::implementation_type;
|
||||
using implementation_type::operator=;
|
||||
using native_handle_type = typename implementation_type::native_handle_type;
|
||||
using implementation_type::native_handle;
|
||||
//copy ctor if impl is copy-constructible
|
||||
bool empty()
|
||||
{
|
||||
return *this->_env_impl == nullptr;
|
||||
}
|
||||
std::size_t size() const
|
||||
{
|
||||
return (_get_end() - this->_env_impl);
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
for (auto && i : *this)
|
||||
implementation_type::reset(i.get_name());
|
||||
this->reload();
|
||||
}
|
||||
|
||||
entry_type at( const string_type& key )
|
||||
{
|
||||
auto f = find(key);
|
||||
if (f== end())
|
||||
throw std::out_of_range(key + " not found");
|
||||
return *f;
|
||||
}
|
||||
const_entry_type at( const string_type& key ) const
|
||||
{
|
||||
auto f = find(key);
|
||||
if (f== end())
|
||||
throw std::out_of_range(key + " not found");
|
||||
return *f;
|
||||
}
|
||||
entry_type operator[](const string_type & key)
|
||||
{
|
||||
auto p = find(key);
|
||||
if (p != end())
|
||||
return *p;
|
||||
|
||||
return entry_type(string_type(key), *this);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/**Template representation of environments. It takes a character type (`char` or `wchar_t`)
|
||||
* as template parameter to implement the environment
|
||||
*/
|
||||
template<typename Char>
|
||||
class basic_environment
|
||||
{
|
||||
|
||||
public:
|
||||
typedef std::basic_string<Char> string_type;
|
||||
typedef boost::transform_iterator< entry_maker, Char**> iterator ;
|
||||
typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ;
|
||||
typedef std::size_t size_type ;
|
||||
|
||||
iterator begin() ; ///<Returns an iterator to the beginning
|
||||
const_iterator begin() const ; ///<Returns an iterator to the beginning
|
||||
const_iterator cbegin() const ; ///<Returns an iterator to the beginning
|
||||
|
||||
iterator end() ; ///<Returns an iterator to the end
|
||||
const_iterator end() const; ///<Returns an iterator to the end
|
||||
const_iterator cend() const; ///<Returns an iterator to the end
|
||||
|
||||
iterator find( const string_type& key ); ///<Find a variable by its name
|
||||
const_iterator find( const string_type& key ) const; ///<Find a variable by its name
|
||||
|
||||
std::size_t count(const string_type & st) const; ///<Number of variables
|
||||
void erase(const string_type & id); ///<Erase variable by id.
|
||||
///Emplace an environment variable.
|
||||
std::pair<iterator,bool> emplace(const string_type & id, const string_type & value);
|
||||
|
||||
///Default constructor
|
||||
basic_environment();
|
||||
///Copy constructor.
|
||||
basic_environment(const basic_environment & );
|
||||
///Move constructor.
|
||||
basic_environment(basic_environment && );
|
||||
|
||||
///Copy assignment.
|
||||
basic_environment& operator=(const basic_environment & );
|
||||
///Move assignment.
|
||||
basic_environment& operator=(basic_environment && );
|
||||
|
||||
typedef typename detail::implementation_type::native_handle_type native_handle;
|
||||
|
||||
///Check if environment has entries.
|
||||
bool empty();
|
||||
///Get the number of variables.
|
||||
std::size_t size() const;
|
||||
///Clear the environment. @attention Use with care, passed environment cannot be empty.
|
||||
void clear();
|
||||
///Get the entry with the key. Throws if it does not exist.
|
||||
entry_type at( const string_type& key );
|
||||
///Get the entry with the key. Throws if it does not exist.
|
||||
const_entry_type at( const string_type& key ) const;
|
||||
///Get the entry with the given key. It creates the entry if it doesn't exist.
|
||||
entry_type operator[](const string_type & key);
|
||||
|
||||
/**Proxy class used for read access to members by [] or .at()
|
||||
* @attention Holds a reference to the environment it was created from.
|
||||
*/
|
||||
template<typename Char, typename Environment>
|
||||
struct const_entry_type
|
||||
{
|
||||
typedef Char value_type;
|
||||
typedef const value_type * pointer;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
typedef boost::iterator_range<pointer> range;
|
||||
typedef Environment environment_t;
|
||||
|
||||
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
|
||||
std::vector<string_type> to_vector() const
|
||||
///Get the value as string.
|
||||
string_type to_string() const
|
||||
///Get the name of this entry.
|
||||
string_type get_name() const {return string_type(_name.begin(), _name.end());}
|
||||
///Copy Constructor
|
||||
const_entry(const const_entry&) = default;
|
||||
///Move Constructor
|
||||
const_entry& operator=(const const_entry&) = default;
|
||||
///Check if the entry is empty.
|
||||
bool empty() const;
|
||||
};
|
||||
|
||||
/**Proxy class used for read and write access to members by [] or .at()
|
||||
* @attention Holds a reference to the environment it was created from.
|
||||
*/
|
||||
template<typename Char, typename Environment>
|
||||
struct entry_type
|
||||
{
|
||||
|
||||
typedef Char value_type;
|
||||
typedef const value_type * pointer;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
typedef boost::iterator_range<pointer> range;
|
||||
typedef Environment environment_t;
|
||||
|
||||
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
|
||||
std::vector<string_type> to_vector() const
|
||||
///Get the value as string.
|
||||
string_type to_string() const
|
||||
///Get the name of this entry.
|
||||
string_type get_name() const {return string_type(_name.begin(), _name.end());}
|
||||
///Copy Constructor
|
||||
entry(const entry&) = default;
|
||||
///Move Constructor
|
||||
entry& operator=(const entry&) = default;
|
||||
///Check if the entry is empty.
|
||||
bool empty() const;
|
||||
|
||||
///Assign a string to the value
|
||||
void assign(const string_type &value);
|
||||
///Assign a set of strings to the entry; they will be seperated by ';' or ':'.
|
||||
void assign(const std::vector<string_type> &value);
|
||||
///Append a string to the end of the entry, it will seperated by ';' or ':'.
|
||||
void append(const string_type &value);
|
||||
///Reset the value
|
||||
void clear();
|
||||
///Assign a string to the entry.
|
||||
entry &operator=(const string_type & value);
|
||||
///Assign a set of strings to the entry; they will be seperated by ';' or ':'.
|
||||
entry &operator=(const std::vector<string_type> & value);
|
||||
///Append a string to the end of the entry, it will seperated by ';' or ':'.
|
||||
entry &operator+=(const string_type & value);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/**Template representation of the environment of this process. It takes a template
|
||||
* as template parameter to implement the environment. All instances of this class
|
||||
* refer to the same environment, but might not get updated if another one makes changes.
|
||||
*/
|
||||
template<typename Char>
|
||||
class basic_native_environment
|
||||
{
|
||||
|
||||
public:
|
||||
typedef std::basic_string<Char> string_type;
|
||||
typedef boost::transform_iterator< entry_maker, Char**> iterator ;
|
||||
typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ;
|
||||
typedef std::size_t size_type ;
|
||||
|
||||
iterator begin() ; ///<Returns an iterator to the beginning
|
||||
const_iterator begin() const ; ///<Returns an iterator to the beginning
|
||||
const_iterator cbegin() const ; ///<Returns an iterator to the beginning
|
||||
|
||||
iterator end() ; ///<Returns an iterator to the end
|
||||
const_iterator end() const; ///<Returns an iterator to the end
|
||||
const_iterator cend() const; ///<Returns an iterator to the end
|
||||
|
||||
iterator find( const string_type& key ); ///<Find a variable by its name
|
||||
const_iterator find( const string_type& key ) const; ///<Find a variable by its name
|
||||
|
||||
std::size_t count(const string_type & st) const; ///<Number of variables
|
||||
void erase(const string_type & id); ///<Erase variable by id.
|
||||
///Emplace an environment variable.
|
||||
std::pair<iterator,bool> emplace(const string_type & id, const string_type & value);
|
||||
|
||||
///Default constructor
|
||||
basic_native_environment();
|
||||
///Move constructor.
|
||||
basic_native_environment(basic_native_environment && );
|
||||
///Move assignment.
|
||||
basic_native_environment& operator=(basic_native_environment && );
|
||||
|
||||
typedef typename detail::implementation_type::native_handle_type native_handle;
|
||||
|
||||
///Check if environment has entries.
|
||||
bool empty();
|
||||
///Get the number of variables.
|
||||
std::size_t size() const;
|
||||
///Get the entry with the key. Throws if it does not exist.
|
||||
entry_type at( const string_type& key );
|
||||
///Get the entry with the key. Throws if it does not exist.
|
||||
const_entry_type at( const string_type& key ) const;
|
||||
///Get the entry with the given key. It creates the entry if it doesn't exist.
|
||||
entry_type operator[](const string_type & key);
|
||||
|
||||
/**Proxy class used for read access to members by [] or .at()
|
||||
* @attention Holds a reference to the environment it was created from.
|
||||
*/
|
||||
template<typename Char, typename Environment>
|
||||
struct const_entry_type
|
||||
{
|
||||
typedef Char value_type;
|
||||
typedef const value_type * pointer;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
typedef boost::iterator_range<pointer> range;
|
||||
typedef Environment environment_t;
|
||||
|
||||
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
|
||||
std::vector<string_type> to_vector() const
|
||||
///Get the value as string.
|
||||
string_type to_string() const
|
||||
///Get the name of this entry.
|
||||
string_type get_name() const {return string_type(_name.begin(), _name.end());}
|
||||
///Copy Constructor
|
||||
const_entry(const const_entry&) = default;
|
||||
///Move Constructor
|
||||
const_entry& operator=(const const_entry&) = default;
|
||||
///Check if the entry is empty.
|
||||
bool empty() const;
|
||||
};
|
||||
|
||||
/**Proxy class used for read and write access to members by [] or .at()
|
||||
* @attention Holds a reference to the environment it was created from.
|
||||
*/
|
||||
template<typename Char, typename Environment>
|
||||
struct entry_type
|
||||
{
|
||||
|
||||
typedef Char value_type;
|
||||
typedef const value_type * pointer;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
typedef boost::iterator_range<pointer> range;
|
||||
typedef Environment environment_t;
|
||||
|
||||
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
|
||||
std::vector<string_type> to_vector() const
|
||||
///Get the value as string.
|
||||
string_type to_string() const
|
||||
///Get the name of this entry.
|
||||
string_type get_name() const {return string_type(_name.begin(), _name.end());}
|
||||
///Copy Constructor
|
||||
entry(const entry&) = default;
|
||||
///Move Constructor
|
||||
entry& operator=(const entry&) = default;
|
||||
///Check if the entry is empty.
|
||||
bool empty() const;
|
||||
|
||||
///Assign a string to the value
|
||||
void assign(const string_type &value);
|
||||
///Assign a set of strings to the entry; they will be seperated by ';' or ':'.
|
||||
void assign(const std::vector<string_type> &value);
|
||||
///Append a string to the end of the entry, it will seperated by ';' or ':'.
|
||||
void append(const string_type &value);
|
||||
///Reset the value
|
||||
void clear();
|
||||
///Assign a string to the entry.
|
||||
entry &operator=(const string_type & value);
|
||||
///Assign a set of strings to the entry; they will be seperated by ';' or ':'.
|
||||
entry &operator=(const std::vector<string_type> & value);
|
||||
///Append a string to the end of the entry, it will seperated by ';' or ':'.
|
||||
entry &operator+=(const string_type & value);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
///Definition of the environment for the current process.
|
||||
template<typename Char>
|
||||
class basic_native_environment : public basic_environment_impl<Char, detail::api::native_environment_impl>
|
||||
{
|
||||
public:
|
||||
using base_type = basic_environment_impl<Char, detail::api::native_environment_impl>;
|
||||
using base_type::base_type;
|
||||
using base_type::operator=;
|
||||
};
|
||||
|
||||
///Type definition to hold a seperate environment.
|
||||
template<typename Char>
|
||||
class basic_environment : public basic_environment_impl<Char, detail::api::basic_environment_impl>
|
||||
{
|
||||
public:
|
||||
using base_type = basic_environment_impl<Char, detail::api::basic_environment_impl>;
|
||||
using base_type::base_type;
|
||||
using base_type::operator=;
|
||||
};
|
||||
|
||||
|
||||
|
||||
///Definition of the environment for the current process.
|
||||
typedef basic_native_environment<char> native_environment;
|
||||
///Definition of the environment for the current process.
|
||||
typedef basic_native_environment<wchar_t> wnative_environment;
|
||||
|
||||
///Type definition to hold a seperate environment.
|
||||
typedef basic_environment<char> environment;
|
||||
///Type definition to hold a seperate environment.
|
||||
typedef basic_environment<wchar_t> wenvironment;
|
||||
|
||||
}
|
||||
|
||||
///Namespace containing information of the calling process.
|
||||
namespace this_process
|
||||
{
|
||||
|
||||
///Definition of the native handle type.
|
||||
typedef ::boost::process::detail::api::native_handle_t native_handle_type;
|
||||
|
||||
///Definition of the environment for this process.
|
||||
using ::boost::process::native_environment;
|
||||
///Definition of the environment for this process.
|
||||
using ::boost::process::wnative_environment;
|
||||
|
||||
///Get the process id of the current process.
|
||||
inline int get_id() { return ::boost::process::detail::api::get_id();}
|
||||
///Get the native handle of the current process.
|
||||
inline native_handle_type native_handle() { return ::boost::process::detail::api::native_handle();}
|
||||
///Get the enviroment of the current process.
|
||||
inline native_environment environment() { return ::boost::process:: native_environment(); }
|
||||
///Get the enviroment of the current process.
|
||||
inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); }
|
||||
///Get the path environment variable of the current process runs.
|
||||
inline std::vector<boost::filesystem::path> path()
|
||||
{
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
const ::boost::process::wnative_environment ne;
|
||||
typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
|
||||
const auto id = L"PATH";
|
||||
#else
|
||||
const ::boost::process::native_environment ne;
|
||||
typedef typename ::boost::process::native_environment::const_entry_type value_type;
|
||||
const auto id = "PATH";
|
||||
#endif
|
||||
|
||||
auto itr = std::find_if(ne.cbegin(), ne.cend(),
|
||||
[&](const value_type & e)
|
||||
{return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
|
||||
|
||||
if (itr == ne.cend())
|
||||
return {};
|
||||
|
||||
auto vec = itr->to_vector();
|
||||
|
||||
std::vector<boost::filesystem::path> val;
|
||||
val.resize(vec.size());
|
||||
|
||||
std::copy(vec.begin(), vec.end(), val.begin());
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENVIRONMENT_HPP_ */
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/environment.hpp>")
|
||||
#include <boost/process/v1/environment.hpp>
|
||||
|
||||
@@ -1,193 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_ERROR_HPP
|
||||
#define BOOST_PROCESS_DETAIL_ERROR_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/traits.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
#endif
|
||||
|
||||
#include <system_error>
|
||||
|
||||
#include <type_traits>
|
||||
#include <boost/fusion/algorithm/query/find_if.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic/end.hpp>
|
||||
#include <boost/fusion/sequence/comparison/equal_to.hpp>
|
||||
#include <boost/fusion/container/set/convert.hpp>
|
||||
#include <boost/type_index.hpp>
|
||||
|
||||
/** \file boost/process/error.hpp
|
||||
*
|
||||
* Header which provides the error properties. It allows to explicitly set the error handling, the properties are:
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::ignore_error">ignore_error</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::throw_on_error">throw_on_error</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::error">error</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::error_ref">error_ref</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::error_code">error_code</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
* For error there are two aliases: error_ref and error_code
|
||||
*/
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct throw_on_error_ : ::boost::process::detail::api::handler_base_ext
|
||||
{
|
||||
constexpr throw_on_error_() {};
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code & ec) const
|
||||
{
|
||||
throw process_error(ec, "process creation failed");
|
||||
}
|
||||
|
||||
const throw_on_error_ &operator()() const {return *this;}
|
||||
};
|
||||
|
||||
struct ignore_error_ : ::boost::process::detail::api::handler_base_ext
|
||||
{
|
||||
constexpr ignore_error_() {};
|
||||
};
|
||||
|
||||
struct set_on_error : ::boost::process::detail::api::handler_base_ext
|
||||
{
|
||||
set_on_error(const set_on_error&) = default;
|
||||
explicit set_on_error(std::error_code &ec) : ec_(ec) {}
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code & ec) const
|
||||
{
|
||||
ec_ = ec;
|
||||
}
|
||||
|
||||
private:
|
||||
std::error_code &ec_;
|
||||
};
|
||||
|
||||
struct error_
|
||||
{
|
||||
constexpr error_() {}
|
||||
set_on_error operator()(std::error_code &ec) const {return set_on_error(ec);}
|
||||
set_on_error operator= (std::error_code &ec) const {return set_on_error(ec);}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_error_handler : std::false_type {};
|
||||
|
||||
template<> struct is_error_handler<set_on_error> : std::true_type {};
|
||||
template<> struct is_error_handler<throw_on_error_> : std::true_type {};
|
||||
template<> struct is_error_handler<ignore_error_> : std::true_type {};
|
||||
|
||||
|
||||
//note: is a tuple of pointers to initializers
|
||||
template<typename Sequence>
|
||||
struct has_error_handler
|
||||
{
|
||||
|
||||
typedef typename boost::fusion::result_of::as_set<Sequence>::type set_type;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, set_on_error>::type t1;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, set_on_error&>::type t2;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, const set_on_error&>::type t3;
|
||||
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, const throw_on_error_&>::type t4;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, const ignore_error_&>::type t5;
|
||||
|
||||
typedef typename boost::mpl::or_<t1,t2,t3, t4, t5>::type type;
|
||||
|
||||
};
|
||||
|
||||
template<typename Sequence>
|
||||
struct has_ignore_error
|
||||
{
|
||||
typedef typename boost::fusion::result_of::as_set<Sequence>::type set_type;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_>::type type1;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_&>::type type2;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, const ignore_error_&>::type type3;
|
||||
typedef typename boost::mpl::or_<type1,type2, type3>::type type;
|
||||
|
||||
};
|
||||
|
||||
struct error_builder
|
||||
{
|
||||
std::error_code *err;
|
||||
typedef set_on_error result_type;
|
||||
set_on_error get_initializer() {return set_on_error(*err);};
|
||||
void operator()(std::error_code & ec) {err = &ec;};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_tag<std::error_code>
|
||||
{
|
||||
typedef error_tag type;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<error_tag>
|
||||
{
|
||||
typedef error_builder type;
|
||||
};
|
||||
|
||||
}
|
||||
/**The ignore_error property will disable any error handling. This can be useful
|
||||
on linux, where error handling will require a pipe.*/
|
||||
constexpr static boost::process::detail::ignore_error_ ignore_error;
|
||||
/**The throw_on_error property will enable the exception when launching a process.
|
||||
It is unnecessary by default, but may be used, when an additional error_code is provided.*/
|
||||
constexpr static boost::process::detail::throw_on_error_ throw_on_error;
|
||||
/**
|
||||
The error property will set the executor to handle any errors by setting an
|
||||
[std::error_code](http://en.cppreference.com/w/cpp/error/error_code).
|
||||
|
||||
\code{.cpp}
|
||||
std::error_code ec;
|
||||
system("gcc", error(ec));
|
||||
\endcode
|
||||
|
||||
The following syntax is valid:
|
||||
|
||||
\code{.cpp}
|
||||
error(ec);
|
||||
error=ec;
|
||||
\endcode
|
||||
|
||||
The overload version is achieved by just passing an object of
|
||||
[std::error_code](http://en.cppreference.com/w/cpp/error/error_code) to the function.
|
||||
|
||||
|
||||
*/
|
||||
constexpr static boost::process::detail::error_ error;
|
||||
///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly .
|
||||
constexpr static boost::process::detail::error_ error_ref;
|
||||
///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly .
|
||||
constexpr static boost::process::detail::error_ error_code;
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/error.hpp>")
|
||||
#include <boost/process/v1/error.hpp>
|
||||
|
||||
@@ -1,30 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_EXCEPTION_HPP_
|
||||
#define BOOST_PROCESS_EXCEPTION_HPP_
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
///The exception usually thrown by boost.process.
|
||||
/** It merely inherits [std::system_error](http://en.cppreference.com/w/cpp/error/system_error)
|
||||
* but can then be distinguished in the catch-block from other system errors.
|
||||
*
|
||||
*/
|
||||
struct process_error : std::system_error
|
||||
{
|
||||
using std::system_error::system_error;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_EXCEPTION_HPP_ */
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/exception.hpp>")
|
||||
#include <boost/process/v1/exception.hpp>
|
||||
|
||||
@@ -1,79 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_EXE_HPP
|
||||
#define BOOST_PROCESS_EXE_HPP
|
||||
|
||||
#include <boost/process/detail/basic_cmd.hpp>
|
||||
|
||||
/** \file boost/process/exe.hpp
|
||||
*
|
||||
* Header which provides the exe property.
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::exe">exe</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
*/
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct exe_
|
||||
{
|
||||
template<typename Char>
|
||||
inline exe_setter_<Char> operator()(const Char *s) const
|
||||
{
|
||||
return exe_setter_<Char>(s);
|
||||
}
|
||||
template<typename Char>
|
||||
inline exe_setter_<Char> operator= (const Char *s) const
|
||||
{
|
||||
return exe_setter_<Char>(s);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline exe_setter_<Char> operator()(const std::basic_string<Char> &s) const
|
||||
{
|
||||
return exe_setter_<Char>(s);
|
||||
}
|
||||
template<typename Char>
|
||||
inline exe_setter_<Char> operator= (const std::basic_string<Char> &s) const
|
||||
{
|
||||
return exe_setter_<Char>(s);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** The exe property allows to explicitly set the executable.
|
||||
|
||||
The overload form applies when to the first, when several strings are passed to a launching
|
||||
function.
|
||||
|
||||
The following expressions are valid, with `value` being either a C-String or
|
||||
a `std::basic_string` with `char` or `wchar_t` or a `boost::filesystem::path`.
|
||||
|
||||
\code{.cpp}
|
||||
exe="value";
|
||||
exe(value);
|
||||
\endcode
|
||||
|
||||
The property can only be used for assignments.
|
||||
|
||||
|
||||
*/
|
||||
constexpr boost::process::detail::exe_ exe{};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/exe.hpp>")
|
||||
#include <boost/process/v1/exe.hpp>
|
||||
|
||||
9
include/boost/process/extend.hpp
Normal file
9
include/boost/process/extend.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/extend.hpp>")
|
||||
#include <boost/process/v1/extend.hpp>
|
||||
9
include/boost/process/filesystem.hpp
Normal file
9
include/boost/process/filesystem.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/filesystem.hpp>")
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
@@ -1,224 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/group.hpp
|
||||
*
|
||||
* Defines a group process class.
|
||||
* For additional information see the platform specific implementations:
|
||||
*
|
||||
* - [windows - job object](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684161.aspx)
|
||||
* - [posix - process group](http://pubs.opengroup.org/onlinepubs/009695399/functions/setpgid.html)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_GROUP_HPP
|
||||
#define BOOST_PROCESS_GROUP_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/none.hpp>
|
||||
#include <atomic>
|
||||
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/group_handle.hpp>
|
||||
#include <boost/process/detail/posix/group_ref.hpp>
|
||||
#include <boost/process/detail/posix/wait_group.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/group_handle.hpp>
|
||||
#include <boost/process/detail/windows/group_ref.hpp>
|
||||
#include <boost/process/detail/windows/wait_group.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace process {
|
||||
|
||||
namespace detail {
|
||||
struct group_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a process group.
|
||||
*
|
||||
* Groups are movable but non-copyable. The destructor
|
||||
* automatically closes handles to the group process.
|
||||
*
|
||||
* The group will have the same interface as std::thread.
|
||||
*
|
||||
* \note If the destructor is called without a previous detach or wait, the group will be terminated.
|
||||
*
|
||||
* \attention If a default-constructed group is used before being used in a process launch, the behaviour is undefined.
|
||||
*/
|
||||
class group
|
||||
{
|
||||
::boost::process::detail::api::group_handle _group_handle;
|
||||
bool _attached = true;
|
||||
public:
|
||||
typedef ::boost::process::detail::api::group_handle group_handle;
|
||||
///Native representation of the handle.
|
||||
typedef group_handle::handle_t native_handle_t;
|
||||
explicit group(group_handle &&ch) : _group_handle(std::move(ch)) {}
|
||||
///Construct the group from a native_handle
|
||||
explicit group(native_handle_t & handle) : _group_handle(handle) {};
|
||||
group(const group&) = delete;
|
||||
///Move constructor
|
||||
group(group && lhs)
|
||||
: _group_handle(std::move(lhs._group_handle)),
|
||||
_attached (lhs._attached)
|
||||
{
|
||||
lhs._attached = false;
|
||||
}
|
||||
///Default constructor
|
||||
group() = default;
|
||||
group& operator=(const group&) = delete;
|
||||
///Move assign
|
||||
group& operator=(group && lhs)
|
||||
{
|
||||
_group_handle= std::move(lhs._group_handle);
|
||||
_attached = lhs._attached;
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
///Detach the group
|
||||
void detach() {_attached = false; }
|
||||
|
||||
/** Join the child. This just calls wait, but that way the naming is similar to std::thread */
|
||||
void join() {wait();}
|
||||
/** Check if the child is joinable. */
|
||||
bool joinable() {return _attached;}
|
||||
|
||||
/** Destructor
|
||||
*
|
||||
* \note If the destructor is called without a previous detach or wait, the group will be terminated.
|
||||
*
|
||||
*/
|
||||
~group()
|
||||
{
|
||||
std::error_code ec;
|
||||
if ( _attached && valid())
|
||||
terminate(ec);
|
||||
}
|
||||
|
||||
///Obtain the native handle of the group.
|
||||
native_handle_t native_handle() const { return _group_handle.handle(); }
|
||||
|
||||
///Wait for the process group to exit.
|
||||
void wait()
|
||||
{
|
||||
boost::process::detail::api::wait(_group_handle);
|
||||
}
|
||||
///\overload void wait()
|
||||
void wait(std::error_code & ec) noexcept
|
||||
{
|
||||
boost::process::detail::api::wait(_group_handle, ec);
|
||||
}
|
||||
/** Wait for the process group to exit for period of time. */
|
||||
template< class Rep, class Period >
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time);
|
||||
}
|
||||
|
||||
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */
|
||||
template< class Rep, class Period >
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time, ec);
|
||||
}
|
||||
|
||||
/** Wait for the process group to exit until a point in time. */
|
||||
template< class Clock, class Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
return boost::process::detail::api::wait_until(_group_handle, timeout_time);
|
||||
}
|
||||
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */
|
||||
template< class Clock, class Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec);
|
||||
}
|
||||
|
||||
///Check if the group has a valid handle.
|
||||
bool valid() const
|
||||
{
|
||||
return _group_handle.valid();
|
||||
}
|
||||
///Convenience to call valid.
|
||||
explicit operator bool() const {return valid();}
|
||||
|
||||
///Terminate the process group, i.e. all processes in the group
|
||||
void terminate()
|
||||
{
|
||||
::boost::process::detail::api::terminate(_group_handle);
|
||||
}
|
||||
///\overload void terminate()
|
||||
void terminate(std::error_code & ec) noexcept
|
||||
{
|
||||
::boost::process::detail::api::terminate(_group_handle, ec);
|
||||
}
|
||||
|
||||
///Assign a child process to the group
|
||||
void add(const child &c)
|
||||
{
|
||||
_group_handle.add(c.native_handle());
|
||||
}
|
||||
///\overload void assign(const child & c)
|
||||
void add(const child &c, std::error_code & ec) noexcept
|
||||
{
|
||||
_group_handle.add(c.native_handle(), ec);
|
||||
}
|
||||
|
||||
///Check if the child process is in the group
|
||||
bool has(const child &c)
|
||||
{
|
||||
return _group_handle.has(c.native_handle());
|
||||
}
|
||||
///\overload bool has(const child &)
|
||||
bool has(const child &c, std::error_code & ec) noexcept
|
||||
{
|
||||
return _group_handle.has(c.native_handle(), ec);
|
||||
|
||||
}
|
||||
|
||||
friend struct detail::group_builder;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct group_tag;
|
||||
struct group_builder
|
||||
{
|
||||
group * group_p;
|
||||
|
||||
void operator()(group & grp) {this->group_p = &grp;};
|
||||
|
||||
typedef api::group_ref result_type;
|
||||
api::group_ref get_initializer() {return api::group_ref (group_p->_group_handle);};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_tag<group>
|
||||
{
|
||||
typedef group_tag type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_builder<group_tag>
|
||||
{
|
||||
typedef group_builder type;
|
||||
};
|
||||
|
||||
}
|
||||
}}
|
||||
#endif
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/group.hpp>")
|
||||
#include <boost/process/v1/group.hpp>
|
||||
|
||||
9
include/boost/process/handles.hpp
Normal file
9
include/boost/process/handles.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/handles.hpp>")
|
||||
#include <boost/process/v1/handles.hpp>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user