1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
|
---
search: en
---
## Specification
#### Naming conventions
The interface is named according to some of the predefined specifications, which is more convenient to understand and easy to use.
It's according to the following rules:
| Interfaces | Description |
| --------------------- | ----------------------------------------------------------------- |
| `is_` + xxx | Condition interfaces |
| `set_` + xxx | Set and override the previous settings |
| `add_` + xxx | Set and append settings |
| `s` + xxx | Support multi-parameters, .e.g:`add_files("*.c", "test.cpp")` |
| `on_` + xxx | Set and override builtin script |
| `before_` + xxx | Set and run this script before running builtin-script |
| `after_` + xxx | Set and run this script after running builtin-script |
| `scope("name")` | Define a description scope, .e.g `target("xxx")`, `option("xxx")` |
| scope/settings | Indentation with spaces |
## Documentation
#### Conditions
Conditions are generally used to handle some special compilation platforms.
| 接口 | 描述 | 支持版本 |
| ------------------------- | ---------------------------------------- | -------- |
| [is_os](#is_os) | Is the current compilation system? | >= 2.0.1 |
| [is_arch](#is_arch) | Is the current compilation architecture? | >= 2.0.1 |
| [is_plat](#is_plat) | Is the current compilation platform? | >= 2.0.1 |
| [is_mode](#is_mode) | Is the current compilation mode? | >= 2.0.1 |
| [is_kind](#is_kind) | Is the current target kind? | >= 2.0.1 |
| [is_option](#is_option) | Is the given options enabled? | >= 2.0.1 |
##### is_os
###### Is the current compilation system
```lua
if is_os("ios") then
add_files("src/xxx/*.m")
end
```
Support operation systems:
* windows
* linux
* android
* macosx
* ios
##### is_arch
###### Is the current compilation architecture
You can this api to check the configuration command: `xmake f -a armv7`
```lua
-- if the current architecture is x86_64 or i386
if is_arch("x86_64", "i386") then
add_files("src/xxx/*.c")
end
-- if the current architecture is armv7 or arm64 or armv7s or armv7-a
if is_arch("armv7", "arm64", "armv7s", "armv7-a") then
-- ...
end
```
And you can also use the wildchard: `*` to check all matched architectures.
```lua
-- if the current architecture is arm which contains armv7, arm64, armv7s and armv7-a ...
if is_arch("arm*") then
-- ...
end
```
##### is_plat
###### Is the current compilation platform
You can this api to check the configuration command: `xmake f -p iphoneos`
```lua
-- if the current platform is android
if is_plat("android") then
add_files("src/xxx/*.c")
end
-- if the current platform is macosx or iphoneos
if is_plat("macosx", "iphoneos") then
add_mxflags("-framework Foundation")
add_ldflags("-framework Foundation")
end
```
Support platforms:
* windows
* linux
* macosx
* android
* iphoneos
* watchos
##### is_mode
###### Is the current compilation mode
You can this api to check the configuration command: `xmake f -m debug`
The compilation mode is not builtin mode for xmake, so you can set the mode value by yourself.
We often use these configuration values: `debug`, `release`, `profile`, etc.
```lua
-- if the current compilation mode is debug?
if is_mode("debug") then
-- add macro: DEBUG
add_defines("DEBUG")
-- enable debug symbols
set_symbols("debug")
-- 禁用优化
set_optimize("none")
end
-- if the current compilation mode is release or profile?
if is_mode("release", "profile") then
if is_mode("release") then
-- mark symbols visibility as hidden
set_symbols("hidden")
-- strip all symbols
set_strip("all")
-- fomit frame pointer
add_cxflags("-fomit-frame-pointer")
add_mxflags("-fomit-frame-pointer")
else
-- enable debug symbols
set_symbols("debug")
end
-- add vectorexts
add_vectorexts("sse2", "sse3", "ssse3", "mmx")
end
```
##### is_kind
###### Is the current target kind
You can this api to check the configuration command: `xmake f -k [static|shared]`
```lua
target("test")
-- set target kind from the configuration command
set_kind("$(kind)")
add_files("src/*c")
-- compile target for static?
if is_kind("static") then
add_files("src/xxx.c")
end
```
You can switch the target kind by configuration command.
```bash
# compile the static library
$ xmake f -k static
$ xmake
```
```bash
# compile the shared library
$ xmake f -k shared
$ xmake
```
##### is_option
###### Is the given options enabled
You can this api to check the custom option configuration command:`xmake f --xxxx=y`
For example, We want to enable the custom option: `xmake f --demo=y` and check it from `xmake.lua`.
```lua
if is_option("demo") then
add_subdirs("src/demo")
end
```
#### Global Interfaces
The global interface affects the whole project description scope and all sub-project files.
| Interfaces | Description | Version |
| ------------------------------------- | ----------------------------- | -------- |
| [set_modes](#set_modes) | Set project compilation modes | >= 2.1.2 |
| [set_project](#set_project) | Set project name | >= 2.0.1 |
| [set_version](#set_version) | Set project version | >= 2.0.1 |
| [set_xmakever](#set_xmakever) | Set minimal xmake version | >= 2.1.1 |
| [add_subdirs](#add_subdirs) | Add sub-project directories | >= 1.0.1 |
| [add_subfiles](#add_subfiles) | Add sub-project files | >= 1.0.1 |
| [add_plugindirs](#add_plugindirs) | Add plugin directories | >= 2.0.1 |
| [add_packagedirs](#add_packagedirs) | Add package directories | >= 2.0.1 |
##### set_modes
###### Set project compilation modes
This is an optional api, just to make it easy for the plugin to get mode configuration information now.
```lua
set_modes("debug", "release")
```
If you set this configuration, you need not set them manually when generating vs201x project.
```bash
$ xmake project -k vs2017
```
Otherwise, you need to run:
```bash
$ xmake project -k vs2017 -m "debug,release"
```
<p class="tip">
If you do not set this configuration, [is_mode](#is_mode) can also be used normally.
</p>
##### set_project
###### Set project name
Set the whole project name, we can set it at the beginning of `xmake.lua`.
```lua
-- set project name
set_project("tbox")
-- set project version
set_version("1.5.1")
```
##### set_version
###### Set project version
Set the whole project version, we can set it at the beginning of `xmake.lua`.
```lua
set_version("1.5.1")
```
It will add project version info to this file automatically if we call [set_config_h](#targetset_config_h) to set `config.h`.`
For example:
```c
// version
#define TB_CONFIG_VERSION "1.5.1"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 5
#define TB_CONFIG_VERSION_ALTER 1
#define TB_CONFIG_VERSION_BUILD 201510220917
```
##### set_xmakever
<p class="warning">
Translating ..., help me please! [Edit this page](https://github.com/tboox/xmake/blob/master/docs/manual.md)
</p>
###### 设置最小xmake版本
用于处理xmake版本兼容性问题,如果项目的`xmake.lua`,通过这个接口设置了最小xmake版本支持,那么用户环境装的xmake低于要求的版本,就会提示错误。
一般情况下,建议默认对其进行设置,这样对用户比较友好,如果`xmake.lua`中用到了高版本的api接口,用户那边至少可以知道是否因为版本不对导致的构建失败。
设置如下:
```lua
-- 设置最小版本为:2.1.0,低于此版本的xmake编译此工程将会提示版本错误信息
set_xmakever("2.1.0")
```
##### add_subdirs
###### 添加子工程目录
每个子工程对应一个`xmake.lua`的工程描述文件。
虽然一个`xmake.lua`也可以描述多个子工程模块,但是如果工程越来越大,越来越复杂,适当的模块化是很有必要的。。
这就需要`add_subdirs`了,将每个子模块放到不同目录中,并为其建立一个新的`xmake.lua`独立去维护它,例如:
```
./tbox
├── src
│ ├── demo
│ │ └── xmake.lua (用来描述测试模块)
│ └── tbox
│ └── xmake.lua(用来描述libtbox库模块)
└── xmake.lua(用该描述通用配置信息,以及对子模块的维护)
````
在`tbox/xmake.lua`中通过`add_subdirs`将拥有`xmale.lua`的子模块的目录,添加进来,就可以了,例如:
```lua
-- 添加libtbox库模块目录
add_subdirs("src/tbox")
-- 如果xmake f --demo=y,启用了demo模块,那么包含demo目录
if is_option("demo") then
add_subdirs("src/demo")
end
```
默认情况下,xmake会去编译在所有xmake.lua中描述的所有target目标,如果只想编译指定目标,可以执行:
```bash
# 仅仅编译tbox库模块
$ xmake tbox
# 仅仅重新编译demo模块
$ xmake -r demo
```
需要注意的是,每个子`xmake.lua`中所有的路径设置都是相对于当前这个子`xmake.lua`所在的目录的,都是相对路径,这样方便维护
##### add_subfiles
###### 添加子工程文件
`add_subfiles`的作用与[add_subdirs](#add_subdirs)类似,唯一的区别就是:这个接口直接指定`xmake.lua`文件所在的路径,而不是目录,例如:
```lua
add_subfiles("src/tbox/xmake.lua")
```
##### add_plugindirs
###### 添加插件目录
xmake内置的插件都是放在`xmake/plugins`目录下,但是对于用户自定义的一些特定工程的插件,如果不想放置在xmake安装目录下,那么可以在`xmake.lua`中进行配置指定的其他插件路径。
```lua
-- 将当前工程下的plugins目录设置为自定义插件目录
add_plugindirs("$(projectdir)/plugins")
```
这样,xmake在编译此工程的时候,也就加载这些插件。
##### add_packagedirs
###### 添加包目录
通过设置依赖包目录,可以方便的集成一些第三方的依赖库,以tbox工程为例,其包目录如下:
```
tbox.pkg
- base.pkg
- zlib.pkg
- polarssl.pkg
- openssl.pkg
- mysql.pkg
- pcre.pkg
- ...
```
如果要让当前工程识别加载这些包,首先要指定包目录路径,例如:
```lua
add_packagedirs("pkg")
```
指定好后,就可以在target作用域中,通过[add_packages](#add_packages)接口,来添加集成包依赖了,例如:
```lua
target("tbox")
add_packages("zlib", "polarssl", "pcre", "mysql")
```
#### Project Target
定义和设置子工程模块,每个`target`对应一个子工程,最后会生成一个目标程序,有可能是可执行程序,也有可能是库模块。
<p class="tip">
target的接口,都是可以放置在target外面的全局作用域中的,如果在全局中设置,那么会影响所有子工程target。
</p>
例如:
```lua
-- 会同时影响test和test2目标
add_defines("DEBUG")
target("test")
add_files("*.c")
target("test2")
add_files("*.c")
```
<p class="tip">
`target`域是可以重复进入来实现分离设置的。
</p>
| 接口 | 描述 | 支持版本 |
| ------------------------------------------- | ------------------------------------ | -------- |
| [target](#target) | 定义工程目标 | >= 1.0.1 |
| [target_end](#target_end) | 结束定义工程目标 | >= 2.1.1 |
| [set_kind](#targetset_kind) | 设置目标编译类型 | >= 1.0.1 |
| [set_strip](#targetset_strip) | 设置是否strip信息 | >= 1.0.1 |
| [set_options](#targetset_options) | 设置关联选项 | >= 1.0.1 |
| [set_symbols](#targetset_symbols) | 设置符号信息 | >= 1.0.1 |
| [set_basename](#targetset_basename) | 设置目标文件名 | >= 2.1.2 |
| [set_warnings](#targetset_warnings) | 设置警告级别 | >= 1.0.1 |
| [set_optimize](#targetset_optimize) | 设置优化级别 | >= 1.0.1 |
| [set_languages](#targetset_languages) | 设置代码语言标准 | >= 1.0.1 |
| [set_headerdir](#targetset_headerdir) | 设置头文件安装目录 | >= 1.0.1 |
| [set_targetdir](#targetset_targetdir) | 设置生成目标文件目录 | >= 1.0.1 |
| [set_objectdir](#targetset_objectdir) | 设置对象文件生成目录 | >= 1.0.1 |
| [on_build](#targeton_build) | 自定义编译脚本 | >= 2.0.1 |
| [on_clean](#targeton_clean) | 自定义清理脚本 | >= 2.0.1 |
| [on_package](#targeton_package) | 自定义打包脚本 | >= 2.0.1 |
| [on_install](#targeton_install) | 自定义安装脚本 | >= 2.0.1 |
| [on_uninstall](#targeton_uninstall) | 自定义卸载脚本 | >= 2.0.1 |
| [on_run](#targeton_run) | 自定义运行脚本 | >= 2.0.1 |
| [before_build](#targetbefore_build) | 在构建之前执行一些自定义脚本 | >= 2.0.1 |
| [before_clean](#targetbefore_clean) | 在清除之前执行一些自定义脚本 | >= 2.0.1 |
| [before_package](#targetbefore_package) | 在打包之前执行一些自定义脚本 | >= 2.0.1 |
| [before_install](#targetbefore_install) | 在安装之前执行一些自定义脚本 | >= 2.0.1 |
| [before_uninstall](#targetbefore_uninstall) | 在卸载之前执行一些自定义脚本 | >= 2.0.1 |
| [before_run](#targetbefore_run) | 在运行之前执行一些自定义脚本 | >= 2.0.1 |
| [after_build](#targetafter_build) | 在构建之后执行一些自定义脚本 | >= 2.0.1 |
| [after_clean](#targetafter_clean) | 在清除之后执行一些自定义脚本 | >= 2.0.1 |
| [after_package](#targetafter_package) | 在打包之后执行一些自定义脚本 | >= 2.0.1 |
| [after_install](#targetafter_install) | 在安装之后执行一些自定义脚本 | >= 2.0.1 |
| [after_uninstall](#targetafter_uninstall) | 在卸载之后执行一些自定义脚本 | >= 2.0.1 |
| [after_run](#targetafter_run) | 在运行之后执行一些自定义脚本 | >= 2.0.1 |
| [set_config_h](#targetset_config_h) | 设置自动生成的配置头文件路径 | >= 1.0.1 |
| [set_config_h_prefix](#targetset_config_h) | 设置自动生成的头文件中宏定义命名前缀 | >= 1.0.1 |
| [add_deps](#targetadd_deps) | 添加子工程目标依赖 | >= 1.0.1 |
| [add_links](#targetadd_links) | 添加链接库名 | >= 1.0.1 |
| [add_files](#targetadd_files) | 添加源代码文件 | >= 1.0.1 |
| [add_headers](#targetadd_headers) | 添加安装的头文件 | >= 1.0.1 |
| [add_linkdirs](#targetadd_linkdirs) | 添加链接库搜索目录 | >= 1.0.1 |
| [add_includedirs](#targetadd_includedirs) | 添加头文件搜索目录 | >= 1.0.1 |
| [add_defines](#targetadd_defines) | 添加宏定义 | >= 1.0.1 |
| [add_undefines](#targetadd_undefines) | 取消宏定义 | >= 1.0.1 |
| [add_defines_h](#targetadd_defines_h) | 添加宏定义到头文件 | >= 1.0.1 |
| [add_undefines_h](#targetadd_undefines_h) | 取消宏定义到头文件 | >= 1.0.1 |
| [add_cflags](#targetadd_cflags) | 添加c编译选项 | >= 1.0.1 |
| [add_cxflags](#targetadd_cxflags) | 添加c/c++编译选项 | >= 1.0.1 |
| [add_cxxflags](#targetadd_cxxflags) | 添加c++编译选项 | >= 1.0.1 |
| [add_mflags](#targetadd_mflags) | 添加objc编译选项 | >= 1.0.1 |
| [add_mxflags](#targetadd_mxflags) | 添加objc/objc++编译选项 | >= 1.0.1 |
| [add_mxxflags](#targetadd_mxxflags) | 添加objc++编译选项 | >= 1.0.1 |
| [add_scflags](#targetadd_scflags) | 添加swift编译选项 | >= 2.0.1 |
| [add_asflags](#targetadd_asflags) | 添加汇编编译选项 | >= 2.0.1 |
| [add_gcflags](#targetadd_gcflags) | 添加go编译选项 | >= 2.1.1 |
| [add_ldflags](#targetadd_ldflags) | 添加链接选项 | >= 1.0.1 |
| [add_arflags](#targetadd_arflags) | 添加静态库归档选项 | >= 1.0.1 |
| [add_shflags](#targetadd_shflags) | 添加动态库链接选项 | >= 1.0.1 |
| [add_cfunc](#targetadd_cfunc) | 添加单个c库函数检测 | >= 2.0.1 |
| [add_cxxfunc](#targetadd_cxxfunc) | 添加单个c++库函数检测 | >= 2.0.1 |
| [add_cfuncs](#targetadd_cfuncs) | 添加c库函数检测 | >= 2.0.1 |
| [add_cxxfuncs](#targetadd_cxxfuncs) | 添加c++库函数接口 | >= 2.0.1 |
| [add_packages](#targetadd_packages) | 添加包依赖 | >= 2.0.1 |
| [add_options](#targetadd_options) | 添加关联选项 | >= 2.0.1 |
| [add_languages](#targetadd_languages) | 添加语言标准 | >= 1.0.1 |
| [add_vectorexts](#targetadd_vectorexts) | 添加向量扩展指令 | >= 1.0.1 |
| [add_frameworks](#targetadd_frameworks) | 添加链接框架 | >= 2.1.1 |
##### target
###### 定义工程目标
定义一个新的控制台工程目标,工程名为`test`,最后生成的目标名也是`test`。
```lua
target("test")
set_kind("binary")
add_files("src/*.c")
```
可以重复调用这个api,进入target域修改设置
```lua
-- 定义目标demo,并进入demo设置模式
target("demo")
set_kind("binary")
add_files("src/demo.c")
-- 定义和设置其他目标
target("other")
...
-- 重新进入demo目标域,添加test.c文件
target("demo")
add_files("src/test.c")
```
<p class="tip">
所有根域的设置,会全局影响所有target目标,但是不会影响option的定义。
</p>
```lua
-- 在根域对所有target添加-DDEBUG的宏定义,影响所有target(demo和test都会加上此宏定义)
add_defines("DEBUG")
target("demo")
set_kind("binary")
add_files("src/demo.c")
target("test")
set_kind("binary")
add_files("src/test.c")
```
##### target_end
###### 结束定义工程目标
这是一个可选的api,如果不调用,那么`target("xxx")`之后的所有设置都是针对这个target进行的,除非进入其他`target`, `option`, `task`域。
如果想设置完当前`target`后,显示离开`target`域,进入根域设置,那么可以通过这个api才操作,例如:
```lua
target("test")
set_kind("static")
add_files("src/*.c")
target_end()
-- 此处已在根域
-- ...
```
如果不调用这个api的话:
```lua
target("test")
set_kind("static")
add_files("src/*.c")
-- 此处还在上面target域中,之后的设置还是针对test进行的设置
-- ...
-- 这个时候才离开test,进入另外一个target域中
target("test2")
...
```
##### target:set_kind
###### 设置目标编译类型
设置目标类型,目前支持的类型有:
| 值 | 描述 |
| ------ | -----------|
| binary | 二进制程序 |
| static | 静态库程序 |
| shared | 动态库程序 |
```lua
target("demo")
set_kind("binary")
```
##### target:set_strip
###### 设置是否strip信息
设置当前目标的strip模式,目前支持一下模式:
| 值 | 描述 |
| ------ | ----------------------------------------- |
| debug | 链接的时候,strip掉调试符号 |
| all | 链接的时候,strip掉所有符号,包括调试符号 |
这个api一般在release模式下使用,可以生成更小的二进制程序。。
```lua
target("xxxx")
set_strip("all")
```
<p class="tip">
这个api不一定非得在target之后使用,如果没有target指定,那么将会设置到全局模式。。
</p>
##### target:set_options
###### 设置关联选项
添加选项依赖,如果通过[option](#option)接口自定义了一些选项,那么只有在指定`target`目标域下,添加此选项,才能进行关联生效。
```lua
-- 定义一个hello选项
option("hello")
set_default(false)
set_showmenu(true)
add_defines_if_ok("HELLO_ENABLE")
target("test")
-- 如果hello选项被启用了,这个时候就会将-DHELLO_ENABLE宏应用到test目标上去
set_options("hello")
```
<p class="warning">
只有调用`set_options`进行关联生效后,[option](#option) 中定义的一些设置才会影响到此`target`目标,例如:宏定义、链接库、编译选项等等
</p>
##### target:set_symbols
###### 设置符号信息
设置目标的符号模式,如果当前没有定义target,那么将会设置到全局状态中,影响所有后续的目标。
目前主要支持一下几个级别:
| 值 | 描述 |
| ------ | ---------------------- |
| debug | 添加调试符号 |
| hidden | 设置符号不可见 |
这两个值也可以同时被设置,例如:
```lua
-- 添加调试符号, 设置符号不可见
set_symbols("debug", "hidden")
```
如果没有调用这个api,默认是禁用调试符号的。。
##### target:set_basename
###### 设置目标文件名
默认情况下,生成的目标文件名基于`target("name")`中配置的值,例如:
```lua
-- 目标文件名为:libxxx.a
target("xxx")
set_kind("static")
-- 目标文件名为:libxxx2.so
target("xxx2")
set_kind("shared")
```
默认的命名方式,基本上可以满足大部分情况下的需求,但是如果有时候想要更加定制化目标文件名
例如,按编译模式和架构区分目标名,这个时候可以使用这个接口,来设置:
```lua
target("xxx")
set_kind("static")
set_basename("xxx_$(mode)_$(arch)")
```
如果这个时候,编译配置为:`xmake f -m debug -a armv7`,那么生成的文件名为:`libxxx_debug_armv7.a`
如果还想进一步定制目标文件的目录名,可参考:[set_targetdir](#targetset_targetdir)。
或者通过编写自定义脚本,实现更高级的逻辑,具体见:[after_build](#targetafter_build)和[os.mv](#os-mv)。
##### target:set_warnings
###### 设置警告级别
设置当前目标的编译的警告级别,一般支持一下几个级别:
| 值 | 描述 |
| ----- | ---------------------- |
| none | 禁用所有警告 |
| less | 启用较少的警告 |
| more | 启用较多的警告 |
| all | 启用所有警告 |
| error | 将所有警告作为编译错误 |
这个api的参数是可以混合添加的,例如:
```lua
-- 启用所有警告,并且作为编译错误处理
set_warnings("all", "error")
```
如果当前没有目标,调用这个api将会设置到全局模式。。
##### target:set_optimize
###### 设置优化级别
设置目标的编译优化等级,如果当前没有设置目标,那么将会设置到全局状态中,影响所有后续的目标。
目前主要支持一下几个级别:
| 值 | 描述 |
| ---------- | ---------------------- |
| none | 禁用优化 |
| fast | 快速优化 |
| faster | 更快的优化 |
| fastest | 最快运行速度的优化 |
| smallest | 最小化代码优化 |
| aggressive | 过度优化 |
例如:
```lua
-- 最快运行速度的优化
set_optimize("fastest")
```
##### target:set_languages
###### 设置代码语言标准
设置目标代码编译的语言标准,如果当前没有目标存在,将会设置到全局模式中。。。
支持的语言标准目前主要有以下几个:
| 值 | 描述 |
| ---------- | ---------------------- |
| ansi | c语言标准: ansi |
| c89 | c语言标准: c89 |
| gnu89 | c语言标准: gnu89 |
| c99 | c语言标准: c99 |
| gnu99 | c语言标准: gnu99 |
| cxx98 | c++语言标准: `c++98` |
| gnuxx98 | c++语言标准: `gnu++98` |
| cxx11 | c++语言标准: `c++11` |
| gnuxx11 | c++语言标准: `gnu++11` |
| cxx14 | c++语言标准: `c++14` |
| gnuxx14 | c++语言标准: `gnu++14` |
| cxx1z | c++语言标准: `c++1z` |
| gnuxx1z | c++语言标准: `gnu++1z` |
| cxx17 | c++语言标准: `c++17` |
| gnuxx17 | c++语言标准: `gnu++17` |
c标准和c++标准可同时进行设置,例如:
```lua
-- 设置c代码标准:c99, c++代码标准:c++11
set_languages("c99", "cxx11")
```
<p class="warning">
并不是设置了指定的标准,编译器就一定会按这个标准来编译,毕竟每个编译器支持的力度不一样,但是xmake会尽最大可能的去适配当前编译工具的支持标准。。。
<br><br>
例如:
<br>
windows下vs的编译器并不支持按c99的标准来编译c代码,只能支持到c89,但是xmake为了尽可能的支持它,所以在设置c99的标准后,xmake会强制按c++代码模式去编译c代码,从一定程度上解决了windows下编译c99的c代码问题。。
用户不需要去额外做任何修改。。
</p>
##### target:set_headerdir
###### 设置头文件安装目录
设置头文件的输出目录,默认输出到build目录中。
```lua
target("test")
set_headerdir("$(buildir)/include")
```
对于需要安装哪些头文件,可参考[add_headers](#targetadd_headers)接口。
##### target:set_targetdir
###### 设置生成目标文件目录
设置目标程序文件的输出目录,一般情况下,不需要设置,默认会输出在build目录下
而build的目录可以在工程配置的时候,手动修改:
```bash
xmake f -o /tmp/build
```
修改成`/tmp/build`后,目标文件默认输出到`/tmp/build`下面。
而如果用这个接口去设置,就不需要每次敲命令修改了,例如:
```lua
target("test")
set_targetdir("/tmp/build")
```
<p class="tip">
如果显示设置了`set_targetdir`, 那么优先选择`set_targetdir`指定的目录为目标文件的输出目录。
</p>
##### target:set_objectdir
###### 设置对象文件生成目录
设置目标target的对象文件(`*.o/obj`)的输出目录,例如:
```lua
target("test")
set_objectdir("$(buildir)/.objs")
```
##### target:on_build
###### 自定义编译脚本
覆盖target目标默认的构建行为,实现自定义的编译过程,一般情况下,并不需要这么做,除非确实需要做一些xmake默认没有提供的编译操作。
你可以通过下面的方式覆盖它,来自定义编译操作:
```lua
target("test")
-- 设置自定义编译脚本
on_build(function (target)
print("build it")
end)
```
<p class="warning">
一旦对这个target目标设置了自己的build过程,那么xmake默认的构建过程将不再被执行。
</p>
##### target:on_clean
###### 自定义清理脚本
覆盖target目标的`xmake [c|clean}`的清理操作,实现自定义清理过程。
```lua
target("test")
-- 设置自定义清理脚本
on_clean(function (target)
-- 仅删掉目标文件
os.rm(target:targetfile())
end)
```
一些target接口描述如下:
| target接口 | 描述 |
| --------------------- | ---------------------------------------------------------------- |
| target:name() | 获取目标名 |
| target:targetfile() | 获取目标文件路径 |
| target:get("kind") | 获取目标的构建类型 |
| target:get("defines") | 获取目标的宏定义 |
| target:get("xxx") | 其他通过 `set_/add_`接口设置的target信息,都可以通过此接口来获取 |
##### target:on_package
###### 自定义打包脚本
覆盖target目标的`xmake [p|package}`的打包操作,实现自定义打包过程,如果你想对指定target打包成自己想要的格式,可以通过这个接口自定义它。
这个接口还是挺实用的,例如,编译玩jni后,将生成的so,打包进apk包中。
```lua
-- 定义一个android app的测试demo
target("demo")
-- 生成动态库:libdemo.so
set_kind("shared")
-- 设置对象的输出目录,可选
set_objectdir("$(buildir)/.objs")
-- 每次编译完的libdemo.so的生成目录,设置为app/libs/armeabi
set_targetdir("libs/armeabi")
-- 添加jni的代码文件
add_files("jni/*.c")
-- 设置自定义打包脚本,在使用xmake编译完libdemo.so后,执行xmake p进行打包
-- 会自动使用ant将app编译成apk文件
--
on_package(function (target)
-- 使用ant编译app成apk文件,输出信息重定向到日志文件
os.run("ant debug")
end)
```
##### target:on_install
###### 自定义安装脚本
覆盖target目标的`xmake [i|install}`的安装操作,实现自定义安装过程。
例如,将生成的apk包,进行安装。
```lua
target("test")
-- 设置自定义安装脚本,自动安装apk文件
on_install(function (target)
-- 使用adb安装打包生成的apk文件
os.run("adb install -r ./bin/Demo-debug.apk")
end)
```
##### target:on_uninstall
###### 自定义卸载脚本
覆盖target目标的`xmake [u|uninstall}`的卸载操作,实现自定义卸载过程。
```lua
target("test")
on_uninstall(function (target)
...
end)
```
##### target:on_run
###### 自定义运行脚本
覆盖target目标的`xmake [r|run}`的运行操作,实现自定义运行过程。
例如,运行安装好的apk程序:
```lua
target("test")
-- 设置自定义运行脚本,自动运行安装好的app程序,并且自动获取设备输出信息
on_run(function (target)
os.run("adb shell am start -n com.demo/com.demo.DemoTest")
os.run("adb logcat")
end)
```
##### target:before_build
###### 在构建之前执行一些自定义脚本
并不会覆盖默认的构建操作,只是在构建之前增加一些自定义的操作。
```lua
target("test")
before_build(function (target))
print("")
end
```
##### target:before_clean
###### 在清理之前执行一些自定义脚本
并不会覆盖默认的清理操作,只是在清理之前增加一些自定义的操作。
```lua
target("test")
before_clean(function (target))
print("")
end
```
##### target:before_package
###### 在打包之前执行一些自定义脚本
并不会覆盖默认的打包操作,只是在打包之前增加一些自定义的操作。
```lua
target("test")
before_package(function (target))
print("")
end
```
##### target:before_install
###### 在安装之前执行一些自定义脚本
并不会覆盖默认的安装操作,只是在安装之前增加一些自定义的操作。
```lua
target("test")
before_install(function (target))
print("")
end
```
##### target:before_uninstall
###### 在卸载之前执行一些自定义脚本
并不会覆盖默认的卸载操作,只是在卸载之前增加一些自定义的操作。
```lua
target("test")
before_uninstall(function (target))
print("")
end
```
##### target:before_run
###### 在运行之前执行一些自定义脚本
并不会覆盖默认的运行操作,只是在运行之前增加一些自定义的操作。
```lua
target("test")
before_run(function (target))
print("")
end
```
##### target:after_build
###### 在构建之后执行一些自定义脚本
并不会覆盖默认的构建操作,只是在构建之后增加一些自定义的操作。
例如,对于ios的越狱开发,构建完程序后,需要用`ldid`进行签名操作
```lua
target("test")
after_build(function (target))
os.run("ldid -S %s", target:targetfile())
end
```
##### target:after_clean
###### 在清理之后执行一些自定义脚本
并不会覆盖默认的清理操作,只是在清理之后增加一些自定义的操作。
一般可用于清理编译某target自动生成的一些额外的临时文件,这些文件xmake默认的清理规则可能没有清理到,例如:
```lua
target("test")
after_clean(function (target))
os.rm("$(buildir)/otherfiles")
end
```
##### target:after_package
###### 在打包之后执行一些自定义脚本
并不会覆盖默认的打包操作,只是在打包之后增加一些自定义的操作。
```lua
target("test")
after_package(function (target))
print("")
end
```
##### target:after_install
###### 在安装之后执行一些自定义脚本
并不会覆盖默认的安装操作,只是在安装之后增加一些自定义的操作。
```lua
target("test")
after_install(function (target))
print("")
end
```
##### target:after_uninstall
###### 在卸载之后执行一些自定义脚本
并不会覆盖默认的卸载操作,只是在卸载之后增加一些自定义的操作。
```lua
target("test")
after_uninstall(function (target))
print("")
end
```
##### target:after_run
###### 在运行之后执行一些自定义脚本
并不会覆盖默认的运行操作,只是在运行之后增加一些自定义的操作。
```lua
target("test")
after_run(function (target))
print("")
end
```
##### target:set_config_h
###### 设置自动生成的配置头文件路径
如果你想在xmake配置项目成功后,或者自动检测某个选项通过后,把检测的结果写入配置头文件,那么需要调用这个接口来启用自动生成`config.h`文件。
使用方式例如:
```lua
target("test")
-- 启用并设置需要自动生成的config.h文件路径
set_config_h("$(buildir)/config.h")
-- 设置自动检测生成的宏开关的名字前缀
set_config_h_prefix("TB_CONFIG")
```
当这个target中通过下面的这些接口,对这个target添加了相关的选项依赖、包依赖、接口依赖后,如果某依赖被启用,那么对应的一些宏定义配置,会自动写入被设置的`config.h`文件中去。
* [add_options](#targetadd_options)
* [add_packages](#targetadd_packages)
* [add_cfuncs](#targetadd_cfuncs)
* [add_cxxfuncs](#targetadd_cxxfuncs)
这些接口,其实底层都用到了[option](#option)选项中的一些检测设置,例如:
```lua
option("wchar")
-- 添加对wchar_t类型的检测
add_ctypes("wchar_t")
-- 如果检测通过,自动生成 TB_CONFIG_TYPE_HAVE_WCHAR的宏开关到config.h
add_defines_h_if_ok("$(prefix)_TYPE_HAVE_WCHAR")
target("test")
-- 启用头文件自动生成
set_config_h("$(buildir)/config.h")
set_config_h_prefix("TB_CONFIG")
-- 添加对wchar选项的依赖关联,只有加上这个关联,wchar选项的检测结果才会写入指定的config.h中去
add_options("wchar")
```
##### target:set_config_h_prefix
###### 设置自动生成的头文件中宏定义命名前缀
具体使用见:[set_config_h](#targetset_config_h)
如果设置了:
```lua
target("test")
set_config_h_prefix("TB_CONFIG")
```
那么,选项中`add_defines_h_if_ok("$(prefix)_TYPE_HAVE_WCHAR")`的$(prefix)会自动被替换成新的前缀值。
##### target:add_deps
###### 添加子工程目标依赖
添加当前目标的依赖目标,编译的时候,会去优先编译依赖的目标,然后再编译当前目标。。。
```lua
target("test1")
set_kind("static")
set_files("*.c")
target("test2")
set_kind("static")
set_files("*.c")
target("demo")
-- 添加依赖目标:test1, test2
add_deps("test1", "test2")
-- 链接libtest1.a,libtest2.a
add_links("test1", "test2")
```
上面的例子,在编译目标demo的时候,需要先编译test1, test2目标,因为demo会去用到他们
##### target:add_links
###### 添加链接库名
为当前目标添加链接库,一般这个要与[add_linkdirs](#targetadd_linkdirs)配对使用。
```lua
target("demo")
-- 添加对libtest.a的链接,相当于 -ltest
add_links("test")
-- 添加链接搜索目录
add_linkdirs("$(buildir)/lib")
```
##### target:add_files
###### 添加源代码文件
用于添加目标工程的源文件,甚至库文件,目前支持的一些文件类型:
| 支持的源文件类型 | 描述 |
| ------------------ | ---------------------------------- |
| .c/.cpp/.cc/.cxx | c++文件 |
| .s/.S/.asm | 汇编文件 |
| .m/.mm | objc文件 |
| .swift | swift文件 |
| .go | golang文件 |
| .o/.obj | 对象文件 |
| .a/.lib | 静态库文件,会自动合并库到目标程序 |
其中通配符`*`表示匹配当前目录下文件,而`**`则匹配多级目录下的文件。
例如:
```lua
add_files("src/test_*.c")
add_files("src/xxx/**.cpp")
add_files("src/asm/*.S", "src/objc/**/hello.m")
```
`add_files`的使用其实是相当灵活方便的,其匹配模式借鉴了premake的风格,但是又对其进行了改善和增强。
使得不仅可以匹配文件,还有可以在添加文件同时,过滤排除指定模式的一批文件。
例如:
```lua
-- 递归添加src下的所有c文件,但是不包括src/impl/下的所有c文件
add_files("src/**.c|impl/*.c")
-- 添加src下的所有cpp文件,但是不包括src/test.cpp、src/hello.cpp以及src下所有带xx_前缀的cpp文件
add_files("src/*.cpp|test.cpp|hello.cpp|xx_*.cpp")
```
其中分隔符`|`之后的都是需要排除的文件,这些文件也同样支持匹配模式,并且可以同时添加多个过滤模式,只要中间用`|`分割就行了。。
添加文件的时候支持过滤一些文件的一个好处就是,可以为后续根据不同开关逻辑添加文件提供基础。
<p class="tip">
为了使得描述上更加的精简,`|`之后的过滤描述都是基于起一个模式:`src/*.cpp` 中`*`之前的目录为基础的。
所以上面的例子后面过滤的都是在src下的文件,这个是要注意的。
</p>
##### target:add_headers
###### 添加安装的头文件
安装指定的头文件到build目录,如果设置了[set_headerdir](#targetset_headerdir), 则输出到指定目录。
安装规则的语法跟[add_files](#targetadd_files)类似,例如:
```lua
-- 安装tbox目录下所有的头文件(忽略impl目录下的文件),并且按()指定部分作为相对路径,进行安装
add_headers("../(tbox/**.h)|**/impl/**.h")
```
##### target:add_linkdirs
###### 添加链接库搜索目录
设置链接库的搜索目录,这个接口的使用方式如下:
```lua
target("test")
add_linkdirs("$(buildir)/lib")
```
一般他是与[add_links](#targetadd_links)配合使用的,当然也可以直接通过[add_ldflags](#targetadd_ldflags)或者[add_shflags](#targetadd_shflags)接口来添加,也是可以的。
<p class="tip">
如果不想在工程中写死,可以通过:`xmake f --linkdirs=xxx`或者`xmake f --ldflags="-L/xxx"`的方式来设置,当然这种手动设置的目录搜索优先级更高。
</p>
##### target:add_includedirs
###### 添加头文件搜索目录
设置头文件的搜索目录,这个接口的使用方式如下:
```lua
target("test")
add_includedirs("$(buildir)/include")
```
当然也可以直接通过[add_cxflags](#targetadd_cxflags)或者[add_mxflags](#targetadd_mxflags)等接口来设置,也是可以的。
<p class="tip">
如果不想在工程中写死,可以通过:`xmake f --includedirs=xxx`或者`xmake f --cxflags="-I/xxx"`的方式来设置,当然这种手动设置的目录搜索优先级更高。
</p>
##### target:add_defines
###### 添加宏定义
```lua
add_defines("DEBUG", "TEST=0", "TEST2=\"hello\"")
```
相当于设置了编译选项:
```
-DDEBUG -DTEST=0 -DTEST2=\"hello\"
```
##### target:add_undefines
###### 取消宏定义
```lua
add_undefines("DEBUG")
```
相当于设置了编译选项:`-UDEBUG`
在代码中相当于:`#undef DEBUG`
##### target:add_defines_h
###### 添加宏定义到头文件
添加宏定义到`config.h`配置文件,`config.h`的设置,可参考[set_config_h](#targetset_config_h)接口。
##### add_undefines_h
###### 取消宏定义到头文件
在`config.h`配置文件中通过`undef`禁用宏定义,`config.h`的设置,可参考[set_config_h](#targetset_config_h)接口。
##### target:add_cflags
###### 添加c编译选项
仅对c代码添加编译选项
```lua
add_cflags("-g", "-O2", "-DDEBUG")
```
<p class="warning">
所有选项值都基于gcc的定义为标准,如果其他编译器不兼容(例如:vc),xmake会自动内部将其转换成对应编译器支持的选项值。
用户无需操心其兼容性,如果其他编译器没有对应的匹配值,那么xmake会自动忽略器设置。
</p>
##### target:add_cxflags
###### 添加c/c++编译选项
同时对c/c++代码添加编译选项
##### target:add_cxxflags
###### 添加c++编译选项
仅对c++代码添加编译选项
##### target:add_mflags
###### 添加objcc编译选项
仅对objc代码添加编译选项
```lua
add_mflags("-g", "-O2", "-DDEBUG")
```
##### target:add_mxflags
###### 添加objc/objc++编译选项
同时对objc/objc++代码添加编译选项
```lua
add_mxflags("-framework CoreFoundation")
```
##### target:add_mxxflags
###### 添加objc++编译选项
仅对objc++代码添加编译选项
```lua
add_mxxflags("-framework CoreFoundation")
```
##### target:add_scflags
###### 添加swift编译选项
对swift代码添加编译选项
```lua
add_scflags("xxx")
```
##### target:add_asflags
###### 添加汇编编译选项
对汇编代码添加编译选项
```lua
add_asflags("xxx")
```
##### target:add_gcflags
###### 添加go编译选项
对golang代码添加编译选项
```lua
add_gcflags("xxx")
```
##### target:add_dcflags
###### 添加dlang编译选项
对dlang代码添加编译选项
```lua
add_dcflags("xxx")
```
##### target:add_rcflags
###### 添加rust编译选项
对rust代码添加编译选项
```lua
add_rcflags("xxx")
```
##### target:add_ldflags
###### 添加链接选项
添加静态链接库选项
```lua
add_ldflags("-L/xxx", "-lxxx")
```
##### target:add_arflags
###### 添加静态库归档选项
影响对静态库的生成
```lua
add_arflags("xxx")
```
##### target:add_shflags
###### 添加动态库链接选项
影响对动态库的生成
```lua
add_shflags("xxx")
```
##### target:add_cfunc
###### 添加单个c库函数检测
与[add_cfuncs](#targetadd_cfuncs)类似,只是仅对单个函数接口进行设置,并且仅对`target`域生效,`option`中不存在此接口。
此接口的目的主要是为了在`config.h`中更加高度定制化的生成宏开关,例如:
```lua
target("demo")
-- 设置和启用config.h
set_config_h("$(buildir)/config.h")
set_config_h_prefix("TEST")
-- 仅通过参数一设置模块名前缀
add_cfunc("libc", nil, nil, {"sys/select.h"}, "select")
-- 通过参数三,设置同时检测链接库:libpthread.a
add_cfunc("pthread", nil, "pthread", "pthread.h", "pthread_create")
-- 通过参数二设置接口别名
add_cfunc(nil, "PTHREAD", nil, "pthread.h", "pthread_create")
```
生成的结果如下:
```c
#ifndef TEST_H
#define TEST_H
// 宏命名规则:$(prefix)前缀 _ 模块名(如果非nil)_ HAVE _ 接口名或者别名 (大写)
#define TEST_LIBC_HAVE_SELECT 1
#define TEST_PTHREAD_HAVE_PTHREAD_CREATE 1
#define TEST_HAVE_PTHREAD 1
#endif
```
##### target:add_cxxfunc
###### 添加单个c++库函数检测
与[add_cfunc](#targetadd_cfunc)类似,只是检测的函数接口是c++函数。
##### target:add_cfuncs
###### 添加c库函数检测
<p class="warning">
此接口是`target`和`option`共用的接口,但是接口行为稍有不同。
</p>
| 接口域 | 描述 | 例子 |
| ------ | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| target | 头文件、链接库和函数接口同时指定 | `add_cfuncs("libc", nil, {"signal.h", "setjmp.h"}, "signal", "setjmp", "sigsetjmp{sigjmp_buf buf; sigsetjmp(buf, 0);}", "kill")` |
| option | 仅指定函数接口,头文件依赖[add_cincludes](#targetadd_cincludes)等独立接口 | `add_cincludes("setjmp.h")` `add_cfuncs("sigsetjmp")` |
对于`option`,这个接口的使用很简单,跟[add_cincludes](#targetadd_cincludes)类似,例如:
```lua
option("setjmp")
set_default(false)
add_cincludes("setjmp.h")
add_cfuncs("sigsetjmp", "setjmp")
add_defines_if_ok("HAVE_SETJMP")
target("test")
add_options("setjmp")
```
此选项检测是否存在`setjmp`的一些接口,如果检测通过那么`test`目标程序将会加上`HAVE_SETJMP`的宏定义。
<p class="warning">
需要注意的是,在`option`中使用此接口检测依赖函数,需要同时使用独立的[add_cincludes](#targetadd_cincludes)增加头文件搜索路径,指定[add_links](#targetadd_links)链接库(可选),否则检测不到指定函数。
<br><br>
并且某些头文件接口是通过宏开关分别定义的,那么检测的时候最好通过[add_defines](#targetadd_defines)带上依赖的宏开关。
</p>
对于`target`,此接口可以同时设置:依赖的头文件、依赖的链接模块、依赖的函数接口,保证检测环境的完整性,例如:
```lua
target("test")
-- 添加libc库接口相关检测
-- 第一个参数:模块名,用于最后的宏定义前缀生成
-- 第二个参数:链接库
-- 第三个参数:头文件
-- 之后的都是函数接口列表
add_cfuncs("libc", nil, {"signal.h", "setjmp.h"}, "signal", "setjmp", "sigsetjmp{sigjmp_buf buf; sigsetjmp(buf, 0);}", "kill")
-- 添加pthread库接口相关检测,同时指定需要检测`libpthread.a`链接库是否存在
add_cfuncs("posix", "pthread", "pthread.h", "pthread_mutex_init",
"pthread_create",
"pthread_setspecific",
"pthread_getspecific",
"pthread_key_create",
"pthread_key_delete")
```
设置`test`目标,依赖这些接口,构建时会预先检测他们,并且如果通过[set_config_h](#targetset_config_h)接口设置的自动生成头文件:`config.h`
那么,检测结果会自动加到对应的`config.h`上去,这也是`option`没有的功能,例如:
```c
#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
#define TB_CONFIG_LIBC_HAVE_SETJMP 1
#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1
#define TB_CONFIG_LIBC_HAVE_KILL 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1
```
由于,不同头文件中,函数的定义方式不完全相同,例如:宏函数、静态内联函数、extern函数等。
要想完全检测成功,检测语法上需要一定程度的灵活性,下面是一些语法规则:
| 检测语法 | 例子 |
| ------------- | ----------------------------------------------- |
| 纯函数名 | `sigsetjmp` |
| 单行调用 | `sigsetjmp((void*)0, 0)` |
| 函数块调用 | `sigsetjmp{sigsetjmp((void*)0, 0);}` |
| 函数块 + 变量 | `sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}` |
##### target:add_cxxfuncs
###### 添加c++库函数检测
与[add_cfuncs](#targetadd_cfuncs)类似,只是检测的函数接口是c++函数。
##### target:add_options
###### 添加关联选项
这个接口跟[set_options](#targetset_options)类似,唯一的区别就是,此处是追加选项,而[set_options](#targetset_options)每次设置会覆盖先前的设置。
##### target:add_packages
###### 添加包依赖
在target作用域中,添加集成包依赖,例如:
```lua
target("test")
add_packages("zlib", "polarssl", "pcre", "mysql")
```
这样,在编译test目标时,如果这个包存在的,将会自动追加包里面的宏定义、头文件搜索路径、链接库目录,也会自动链接包中所有库。
用户不再需要自己单独调用[add_links](#targetadd_links),[add_includedirs](#targetadd_includedirs), [add_ldflags](#targetadd_ldflags)等接口,来配置依赖库链接了。
对于如何设置包搜索目录,可参考:[add_packagedirs](#targetadd_packagedirs) 接口
##### target:add_languages
###### 添加语言标准
与[set_languages](#targetset_languages)类似,唯一区别是这个接口不会覆盖掉之前的设置,而是追加设置。
##### target:add_vectorexts
###### 添加向量扩展指令
添加扩展指令优化选项,目前支持以下几种扩展指令集:
```lua
add_vectorexts("mmx")
add_vectorexts("neon")
add_vectorexts("avx", "avx2")
add_vectorexts("sse", "sse2", "sse3", "ssse3")
```
<p class="tip">
如果当前设置的指令集编译器不支持,xmake会自动忽略掉,所以不需要用户手动去判断维护,只需要将你需要的指令集全部设置上就行了。
</p>
##### target:add_frameworks
###### 添加链接框架
目前主要用于`ios`和`macosx`平台的`objc`和`swift`程序,例如:
```lua
target("test")
add_frameworks("Foundation", "CoreFoundation")
```
当然也可以使用[add_mxflags](#targetadd_mxflags)和[add_ldflags](#targetadd_ldflags)来设置,不过比较繁琐,不建议这样设置。
```lua
target("test")
add_mxflags("-framework Foundation", "-framework CoreFoundation")
add_ldflags("-framework Foundation", "-framework CoreFoundation")
```
如果不是这两个平台,这些设置将会被忽略。
#### Configuration Option
定义和设置选项开关,每个`option`对应一个选项,可用于自定义编译配置选项、开关设置。
<p class="tip">
除了`target`以外的所有域接口,例如`option`,`task`等的接口,默认不能放置在外面的全局作用域中的(除非部分跟target共用的接口除外)。
如果要设置值影响所有`option`,`task`等选项,可以通过匿名全局域来设置。
</p>
例如:
```lua
-- 进入option的匿名全局域,里面的设置会同时影响test和test2选项
option()
add_defines("DEBUG")
option("test")
-- ...
-- 尽量保持缩进,因为这个之后的所有设置,都是针对test选项的
option("test2")
-- ...
```
<p class="tip">
`option`域是可以重复进入来实现分离设置的,如果要显示离开当前选项的作用域设置,可以手动调用[option_end](#option_end)接口。
</p>
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------------- | -------------------------------------------- | -------- |
| [option](#option) | 定义选项 | >= 2.0.1 |
| [option_end](#option_end) | 结束定义选项 | >= 2.1.1 |
| [set_default](#optionset_default) | 设置默认值 | >= 2.0.1 |
| [set_showmenu](#optionset_showmenu) | 设置是否启用菜单显示 | >= 1.0.1 |
| [set_category](#optionset_category) | 设置选项分类,仅用于菜单显示 | >= 1.0.1 |
| [set_description](#optionset_description) | 设置菜单显示描述 | >= 1.0.1 |
| [add_bindings](#optionadd_bindings) | 添加正向关联选项,同步启用和禁用 | >= 2.0.1 |
| [add_rbindings](#optionadd_rbindings) | 添加逆向关联选项,同步启用和禁用 | >= 2.0.1 |
| [add_links](#optionadd_links) | 添加链接库检测 | >= 1.0.1 |
| [add_linkdirs](#optionadd_linkdirs) | 添加链接库检测需要的搜索目录 | >= 1.0.1 |
| [add_cincludes](#optionadd_cincludes) | 添加c头文件检测 | >= 1.0.1 |
| [add_cxxincludes](#optionadd_cxxincludes) | 添加c++头文件检测 | >= 1.0.1 |
| [add_ctypes](#optionadd_ctypes) | 添加c类型检测 | >= 1.0.1 |
| [add_cxxtypes](#optionadd_cxxtypes) | 添加c++类型检测 | >= 1.0.1 |
| [add_defines_if_ok](#optionadd_defines_if_ok) | 如果检测选项通过,则添加宏定义 | >= 1.0.1 |
| [add_defines_h_if_ok](#optionadd_defines_h_if_ok) | 如果检测选项通过,则添加宏定义到配置头文件 | >= 1.0.1 |
| [add_undefines_if_ok](#optionadd_undefines_if_ok) | 如果检测选项通过,则取消宏定义 | >= 1.0.1 |
| [add_undefines_h_if_ok](#optionadd_undefines_h_if_ok) | 如果检测选项通过,则在配置头文件中取消宏定义 | >= 1.0.1 |
##### 通用接口 (target)
下面的这些接口,是跟`target`目标域接口通用的,在`option()`和`target()`域范围内都能同时使用,可直接参考上面`target`中的接口描述。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------- | ------------------------------------ | -------- |
| [set_warnings](#targetset_warnings) | 设置警告级别 | >= 1.0.1 |
| [set_optimize](#targetset_optimize) | 设置优化级别 | >= 1.0.1 |
| [set_languages](#targetset_languages) | 设置代码语言标准 | >= 1.0.1 |
| [add_links](#targetadd_links) | 添加链接库名 | >= 1.0.1 |
| [add_linkdirs](#targetadd_linkdirs) | 添加链接库搜索目录 | >= 1.0.1 |
| [add_includedirs](#targetadd_includedirs) | 添加头文件搜索目录 | >= 1.0.1 |
| [add_defines](#targetadd_defines) | 添加宏定义 | >= 1.0.1 |
| [add_undefines](#targetadd_undefines) | 取消宏定义 | >= 1.0.1 |
| [add_defines_h](#targetadd_defines_h) | 添加宏定义到头文件 | >= 1.0.1 |
| [add_undefines_h](#targetadd_undefines_h) | 取消宏定义到头文件 | >= 1.0.1 |
| [add_cflags](#targetadd_cflags) | 添加c编译选项 | >= 1.0.1 |
| [add_cxflags](#targetadd_cxflags) | 添加c/c++编译选项 | >= 1.0.1 |
| [add_cxxflags](#targetadd_cxxflags) | 添加c++编译选项 | >= 1.0.1 |
| [add_mflags](#targetadd_mflags) | 添加objc编译选项 | >= 2.0.1 |
| [add_mxflags](#targetadd_mxflags) | 添加objc/objc++编译选项 | >= 2.0.1 |
| [add_mxxflags](#targetadd_mxxflags) | 添加objc++编译选项 | >= 2.0.1 |
| [add_scflags](#targetadd_scflags) | 添加swift编译选项 | >= 2.1.1 |
| [add_asflags](#targetadd_asflags) | 添加汇编编译选项 | >= 2.1.1 |
| [add_gcflags](#targetadd_gcflags) | 添加go编译选项 | >= 2.1.1 |
| [add_dcflags](#targetadd_dcflags) | 添加dlang编译选项 | >= 2.1.1 |
| [add_rcflags](#targetadd_rcflags) | 添加rust编译选项 | >= 2.1.1 |
| [add_ldflags](#targetadd_ldflags) | 添加链接选项 | >= 2.1.1 |
| [add_arflags](#targetadd_arflags) | 添加静态库归档选项 | >= 2.1.1 |
| [add_shflags](#targetadd_shflags) | 添加动态库链接选项 | >= 2.0.1 |
| [add_cfuncs](#targetadd_cfuncs) | 添加c库函数检测 | >= 1.0.1 |
| [add_cxxfuncs](#targetadd_cxxfuncs) | 添加c++库函数接口 | >= 1.0.1 |
| [add_languages](#targetadd_languages) | 添加语言标准 | >= 2.0.1 |
| [add_vectorexts](#targetadd_vectorexts) | 添加向量扩展指令 | >= 2.0.1 |
| [add_frameworks](#targetadd_frameworks) | 添加链接框架 | >= 2.1.1 |
##### option
###### 定义选项
定义和设置选项开关,可用于自定义编译配置选项、开关设置。
例如,定义一个是否启用test的选项:
```lua
option("test")
set_default(false)
set_showmenu(true)
add_defines("-DTEST")
```
然后关联到指定的target中去:
```lua
target("demo")
add_options("test")
```
这样,一个选项就算定义好了,如果这个选项被启用,那么编译这个target的时候,就会自动加上`-DTEST`的宏定义。
```lua
# 手动启用这个选项
$ xmake f --test=y
$ xmake
```
##### option_end
###### 结束定义选项
这是一个可选api,显示离开选项作用域,用法和[target_end](#target_end)类似。
##### option:set_default
###### 设置选项默认值
在没有通过`xmake f --option=[y|n}`等命令修改选项值的时候,这个选项本身也是有个默认值的,可以通过这个接口来设置:
```lua
option("test")
-- 默认禁用这个选项
set_default(false)
```
选项的值不仅支持boolean类型,也可以是字符串类型,例如:
```lua
option("test")
set_default("value")
```
| 值类型 | 描述 | 配置 |
| ------ | -------------------------------------- | -----------------------------------------------|
| boolean | 一般用作参数开关,值范围:`true/false` | `xmake f --optionname=[y/n/yes/no/true/false]` |
| string | 可以是任意字符串,一般用于模式判断 | `xmake f --optionname=value` |
如果是`boolean`值的选项,可以通过[is_option](#is_option)来进行判断,选项是否被启用。
如果是`string`类型的选项,可以在内建变量中直接使用,例如:
```lua
-- 定义一个路径配置选项,默认使用临时目录
option("rootdir")
set_default("$(tmpdir)")
set_showmenu(true)
target("test")
-- 添加指定选项目录中的源文件
add_files("$(rootdir)/*.c")
```
其中,`$(rootdir)` 就是自定义的选项内建变量,通过手动配置,可以动态修改它的值:
```bash
$ xmake f --rootdir=~/projectdir/src
$ xmake
```
给这个`rootdir`选项指定一个其他的源码目录路径,然后编译。
选项的检测行为:
| default值 | 检测行为 |
| ---------- | --------------------------------------------------------------------------------------------- |
| 没有设置 | 优先手动配置修改,默认禁用,否则自动检测,可根据手动传入的值类型,自动切换boolean和string类型 |
| false | 开关选项,不自动检测,默认禁用,可手动配置修改 |
| true | 开关选项,不自动检测,默认启用,可手动配置修改 |
| string类型 | 无开关状态,不自动检测,可手动配置修改,一般用于配置变量传递 |
##### option:set_showmenu
###### 设置是否启用菜单显示
如果设置为`true`,那么在`xmake f --help`里面就会出现这个选项,也就能通过`xmake f --optionname=xxx`进行配置,否则只能在`xmake.lua`内部使用,无法手动配置修改。
```lua
option("test")
set_showmenu(true)
```
设置为启用菜单后,执行`xmake f --help`可以看到,帮助菜单里面多了一项:
```
Options:
...
--test=TEST
```
##### option:set_category
###### 设置选项分类,仅用于菜单显示
这个是个可选配置,仅用于在帮助菜单中,进行分类显示选项,同一类别的选项,会在同一个分组里面显示,这样菜单看起来更加的美观。
例如:
```lua
option("test1")
set_showmenu(true)
set_category("test")
option("test2")
set_showmenu(true)
set_category("test")
option("demo1")
set_showmenu(true)
set_category("demo")
option("demo2")
set_showmenu(true)
set_category("demo")
```
这里四个选项分别归类于两个分组:`test`和`demo`,那么显示的布局类似这样:
```bash
Options:
...
--test1=TEST1
--test2=TEST2
--demo1=DEMO1
--demo2=DEMO2
```
这个接口,仅仅是为了调整显示布局,更加美观而已,没其他用途。
##### option:set_description
###### 设置菜单显示描述
设置选项菜单显示时,右边的描述信息,用于帮助用户更加清楚的知道这个选项的用途,例如:
```lua
option("test")
set_default(false)
set_showmenu(true)
set_description("Enable or disable test")
```
生成的菜单内容如下:
```
Options:
...
--test=TEST Enable or disable test (default: false)
```
这个接口也支持多行显示,输出更加详细的描述信息,例如:
```lua
option("mode")
set_default("debug")
set_showmenu(true)
set_description("Set build mode"
" - debug"
" - release"
" - profile")
```
生成的菜单内容如下:
```
Options:
...
--mode=MODE Set build mode (default: debug)
- debug
- release
- profile
```
看到这个菜单,用户就能清楚地知道,定义的这个`mode`选项的具体用处,以及如何使用了:
```bash
$ xmake f --mode=release
```
##### option:add_bindings
###### 添加正向关联选项,同步启用和禁用
绑定关联选项,例如我想在命令行中配置一个`smallest`的参数:`xmake f --smallest=y`
这个时候,需要同时禁用多个其他的选项开关,来禁止编译多个模块,就是这个需求,相当于一个选项 与其他 多个选项之间 是有联动效应的。
而这个接口就是用来设置需要正向绑定的一些关联选项,例如:
```lua
-- 定义选项开关: --smallest=y|n
option("smallest")
-- 添加正向绑定,如果smallest被启用,下面的所有选项开关也会同步被启用
add_bindings("nozip", "noxml", "nojson")
```
##### option:add_rbindings
###### 添加逆向关联选项,同步启用和禁用
逆向绑定关联选项,被关联选项的开关状态是相反的。
```lua
-- 定义选项开关: --smallest=y|n
option("smallest")
-- 添加反向绑定,如果smallest被启用,下面的所有模块全部禁用
add_rbindings("xml", "zip", "asio", "regex", "object", "thread", "network", "charset", "database")
add_rbindings("zlib", "mysql", "sqlite3", "openssl", "polarssl", "pcre2", "pcre", "base")
```
<p class="warning">
需要注意的是,命令行配置是有顺序的,你可以先通过启用smallest禁用所有模块,然后添加其他选项,逐一启用。
</p>
例如:
```bash
-- 禁用所有模块,然后仅仅启用xml和zip模块
$ xmake f --smallest=y --xml=y --zip=y
```
##### option:add_links
###### 添加链接库检测
如果指定的链接库检测通过,此选项将被启用,并且对应关联的target会自动加上此链接,例如:
```lua
option("pthread")
set_default(false)
add_links("pthread")
add_linkdirs("/usr/local/lib")
target("test")
add_options("pthread")
```
如果检测通过,`test`目标编译的时候就会自动加上:`-L/usr/local/lib -lpthread` 编译选项
##### option:add_linkdirs
###### 添加链接库检测时候需要的搜索目录
这个是可选的,一般系统库不需要加这个,也能检测通过,如果确实没找到,可以自己追加搜索目录,提高检测通过率。具体使用见:[add_links](#optionadd_links)
##### option:add_cincludes
###### 添加c头文件检测
如果c头文件检测通过,此选项将被启用,例如:
```lua
option("pthread")
set_default(false)
add_cincludes("pthread.h")
add_defines_if_ok("ENABLE_PTHREAD")
target("test")
add_options("pthread")
```
此选项检测是否存在`pthread.h`的头文件,如果检测通过那么`test`目标程序将会加上`ENABLE_PTHREAD`的宏定义。
##### option:add_cxxincludes
###### 添加c++头文件检测
与[add_cincludes](#optionadd_cincludes)类似,只是检测的头文件类型是c++头文件。
##### option:add_ctypes
###### 添加c类型检测
如果c类型检测通过,此选项将被启用,例如:
```lua
option("wchar")
set_default(false)
add_cincludes("wchar_t")
add_defines_if_ok("HAVE_WCHAR")
target("test")
add_options("wchar")
```
此选项检测是否存在`wchar_t`的类型,如果检测通过那么`test`目标程序将会加上`HAVE_WCHAR`的宏定义。
##### option:add_cxxtypes
###### 添加c++类型检测
与[add_ctypes](#optionadd_ctypes)类似,只是检测的类型是c++类型。
##### option:add_defines_if_ok
###### 如果检测选项通过,则添加宏定义
检测选项通过后才会被设置,具体使用见[add_cincludes](#optionadd_cincludes)中的例子。
##### option:add_defines_h_if_ok
###### 如果检测选项通过,则添加宏定义到配置头文件
跟[add_defines_if_ok](#optionadd_defines_if_ok)类似,只是检测通过后,会在`config.h`头文件中自动加上被设置的宏定义。
例如:
```lua
option("pthread")
set_default(false)
add_cincludes("pthread.h")
add_defines_h_if_ok("ENABLE_PTHREAD")
target("test")
add_options("pthread")
```
通过后,会在`config.h`中加上:
```c
#define ENABLE_PTHREAD 1
```
具体`config.h`如何设置,见:[set_config_h](#targetset_config_h)
##### option:add_undefines_if_ok
###### 如果检测选项通过,则取消宏定义
跟[add_defines_if_ok](#optionadd_defines_if_ok)类似,只是检测通过后,取消被设置的宏定义。
##### option:add_undefines_h_if_ok
###### 如果检测选项通过,则在配置头文件中取消宏定义
跟[add_defines_h_if_ok](#optionadd_defines_h_if_ok)类似,只是检测通过后,会在`config.h`中取消被设置的宏定义。
```c
#undef DEFINED_MACRO
```
具体`config.h`如何设置,见:[set_config_h](#targetset_config_h)
#### Plugin and Task
xmake可以实现自定义任务或者插件,其两者的核心就是`task`任务,其两者实际上是一样的,xmake的插件都是用`task`实现的。
本质上都是任务,只是[set_category](#taskset_category)分类不同而已。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [task](#task) | 定义插件或者任务 | >= 2.0.1 |
| [task_end](#task_end) | 结束定义插件或任务 | >= 2.1.1 |
| [set_menu](#taskset_menu) | 设置任务菜单 | >= 2.0.1 |
| [set_category](#taskset_category) | 设置任务类别 | >= 2.0.1 |
| [on_run](#taskon_run) | 设置任务运行脚本 | >= 2.0.1 |
##### task
###### 定义插件或者任务
`task`域用于描述一个自定义的任务实现,与[target](#target)和[option](#option)同级。
例如,这里定义一个最简单的任务:
```lua
task("hello")
-- 设置运行脚本
on_run(function ()
print("hello xmake!")
end)
```
这个任务只需要打印`hello xmake!`,那如何来运行呢?
由于这里没有使用[set_menu](#taskset_menu)设置菜单,因此这个任务只能再`xmake.lua`的自定义脚本或者其他任务内部调用,例如:
```lua
target("test")
after_build(function (target)
-- 导入task模块
import("core.project.task")
-- 运行hello任务
task.run("hello")
end)
```
在构建完`test`目标后运行`hello`任务。
##### task_end
###### 结束定义插件或任务
这是一个可选api,显示离开选项作用域,用法和[target_end](#target_end)类似。
##### task:set_menu
###### 设置任务菜单
通过设置一个菜单,这个任务就可以开放给用户自己通过命令行手动调用,菜单的设置如下:
```lua
task("echo")
-- 设置运行脚本
on_run(function ()
-- 导入参数选项模块
import("core.base.option")
-- 初始化颜色模式
local modes = ""
for _, mode in ipairs({"bright", "dim", "blink", "reverse"}) do
if option.get(mode) then
modes = modes .. " " .. mode
end
end
-- 获取参数内容并且显示信息
cprint("${%s%s}%s", option.get("color"), modes, table.concat(option.get("contents") or {}, " "))
end)
-- 设置插件的命令行选项,这里没有任何参数选项,仅仅显示插件描述
set_menu {
-- 设置菜单用法
usage = "xmake echo [options]"
-- 设置菜单描述
, description = "Echo the given info!"
-- 设置菜单选项,如果没有选项,可以设置为{}
, options =
{
-- 设置k模式作为key-only型bool参数
{'b', "bright", "k", nil, "Enable bright." }
, {'d', "dim", "k", nil, "Enable dim." }
, {'-', "blink", "k", nil, "Enable blink." }
, {'r', "reverse", "k", nil, "Reverse color." }
-- 菜单显示时,空白一行
, {}
-- 设置kv作为key-value型参数,并且设置默认值:black
, {'c', "color", "kv", "black", "Set the output color."
, " - red"
, " - blue"
, " - yellow"
, " - green"
, " - magenta"
, " - cyan"
, " - white" }
-- 设置`vs`作为values多值型参数,还有`v`单值类型
-- 一般放置在最后,用于获取可变参数列表
, {}
, {nil, "contents", "vs", nil, "The info contents." }
}
}
```
定义完这个任务后,执行`xmake --help`,就会多出一个任务项来:
```
Tasks:
...
echo Echo the given info!
```
如果通过[set_category](#taskset_category)设置分类为`plugin`,那么这个任务就是一个插件了:
```
Plugins:
...
echo Echo the given info!
```
想要手动运行这个任务,可以执行:
```bash
$ xmake echo hello xmake!
```
就行了,如果要看这个任务定义的菜单,只需要执行:`xmake echo [-h|--help]`,显示结果如下:
```bash
Usage: $xmake echo [options]
Echo the given info!
Options:
-v, --verbose Print lots of verbose information.
--backtrace Print backtrace information for debugging.
--profile Print performance data for debugging.
--version Print the version number and exit.
-h, --help Print this help message and exit.
-F FILE, --file=FILE Read a given xmake.lua file.
-P PROJECT, --project=PROJECT Change to the given project directory.
Search priority:
1. The Given Command Argument
2. The Envirnoment Variable: XMAKE_PROJECT_DIR
3. The Current Directory
-b, --bright Enable bright.
-d, --dim Enable dim.
--, --blink Enable blink.
-r, --reverse Reverse color.
-c COLOR, --color=COLOR Set the output color. (default: black)
- red
- blue
- yellow
- green
- magenta
- cyan
- white
contents ... The info contents.
```
<p class="tip">
其中菜单最开头的部分选项,是xmake内置的常用选项,基本上每个任务都会用到,不需要自己额外定义,简化菜单定义。
</p>
下面,我们来实际运行下这个任务,例如我要显示红色的`hello xmake!`,只需要:
```bash
$ xmake echo -c red hello xmake!
```
也可以使用选项全名,并且加上高亮:
```bash
$ xmake echo --color=red --bright hello xmake!
```
最后面的可变参数列表,在`run`脚本中通过`option.get("contents")`获取,返回的是一个`table`类型的数组。
##### task:set_category
###### 设置任务类别
仅仅用于菜单的分组显示,当然插件默认会用`plugin`,内置任务默认会用:`action`,但也仅仅只是个约定。
<p class="tips">
你可以使用任何自己定义的名字,相同名字会分组归类到一起显示,如果设置为`plugin`,就会显示到xmake的Plugins分组中去。
</p>
例如:
```lua
Plugins:
l, lua Run the lua script.
m, macro Run the given macro.
doxygen Generate the doxygen document.
project Generate the project file.
hello Hello xmake!
app2ipa Generate .ipa file from the given .app
echo Echo the given info!
```
如果没有调用这个接口设置分类,默认使用`Tasks`分组显示,代表普通任务。
##### task:on_run
###### 设置任务运行脚本
可以有两种设置方式,最简单的就是设置内嵌函数:
```lua
task("hello")
on_run(function ()
print("hello xmake!")
end)
```
这种对于小任务很方便,也很简洁,但是对于大型任务就不太适用了,例如插件等,需要复杂的脚本支持。
这个时候就需要独立的模块文件来设置运行脚本,例如:
```lua
task("hello")
on_run("main")
```
这里的`main`设置为脚本运行主入口模块,文件名为`main.lua`,放在定义`task`的`xmake.lua`的同目录下,当然你可以起其他文件名。
目录结构如下:
```
projectdir
- xmake.lua
- main.lua
```
`main.lua`里面内容如下:
```lua
function main(...)
print("hello xmake!")
end
```
就是一个简单的带`main`主函数的脚本文件,你可以通过[import](#import)导入各种扩展模块,实现复杂功能,例如:
```lua
-- 导入参数选项模块
import("core.base.option")
-- 入口函数
function main(...)
-- 获取参数内容
print("color: %s", option.get("color"))
end
```
你也可以在当前目录下,创建多个自定义的模块文件,通过[import](#import)导入后使用,例如:
```
projectdir
- xmake.lua
- main.lua
- module.lua
```
`module.lua`的内容如下:
```lua
-- 定义一个导出接口
function hello()
print("hello xmake!")
end
```
<p class="tip">
私有接口,通过`_hello`带下滑线前缀命名,这样导入的模块就不会包含此接口,只在模块自身内部使用。
</p>
然后在`main.lua`进行调用:
```lua
import("module")
function main(...)
module.hello()
end
```
更多模块介绍见:[内置模块](#内置模块)和[扩展模块](扩展模块)
其中,`main(...)`中参数,是通过`task.run`指定的,例如:
```lua
task.run("hello", {color="red"}, arg1, arg2, arg3)
```
里面的`arg1, arg2`这些就是传入`hello`任务`main(...)`入口的参数列表,而`{color="red"}`用来指定任务菜单中的参数选项。
更加详细的`task.run`描述,见:[task.run](#task-run)
#### Extension Platforms
xmake除了内置的一些构建平台,还可以自己扩展自定义构建平台,可以将自己实现的平台放置在以下目录即可, xmake会自动检测并且加载他们:
| 平台目录 | 描述 |
| --------------------------- | ------------------------------------ |
| projectdir/.xmake/platforms | 当前工程的平台目录, 只对当前工程有效 |
| globaldir/.xmake/platforms | 全局配置的平台目录,当前主机全局有效 |
| installdir/xmake/platforms | xmake安装后内置的平台目录 |
用户可根据不同需求,将自定义的平台放置在对应的目录中。
<p class="warning">
平台的扩展定义,尽量不要放到工程`xmake.lua`中去,新建一个单独的平台目录放置相关描述实现。
</p>
平台描述的目录结构:
```
platforms
- myplat1
- xmake.lua
- myplat2
- xmake.lua
```
其中`xmake.lua`为每个平台的主描述文件,相当于入口描述。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [platform](#platform) | 定义平台 | >= 2.0.1 |
| [platform_end](#platform_end) | 结束定义平台 | >= 2.1.1 |
| [set_os](#platformset_os) | 设置平台系统 | >= 2.0.1 |
| [set_menu](#platformset_menu) | 设置平台菜单 | >= 2.0.1 |
| [set_hosts](#platformset_hosts) | 设置平台支持的主机环境 | >= 2.0.1 |
| [set_archs](#platformset_archs) | 设置平台支持的架构环境 | >= 2.0.1 |
| [set_tooldirs](#platformset_tooldirs) | 设置平台工具的搜索目录 | >= 2.0.1 |
| [on_load](#platformon_load) | 设置加载平台环境配置脚本 | >= 2.0.1 |
| [on_check](#platformon_check) | 设置平台工具的检测脚本 | >= 2.0.1 |
| [on_install](#platformon_install) | 设置平台相关的工程目标安装脚本 | >= 2.0.5 |
| [on_uninstall](#platformon_uninstall) | 设置平台相关的工程目标卸载脚本 | >= 2.0.5 |
##### platform
###### 定义平台
自定义一个平台域,例如:
```lua
platform("iphoneos")
-- 设置操作系统
set_os("ios")
-- 设置主机环境
set_hosts("macosx")
-- 设置支持的架构
set_archs("armv7", "armv7s", "arm64", "i386", "x86_64")
-- 设置gcc, clang等平台相关工具的搜索目录
set_tooldirs("/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin")
-- 设置gcc,clang等工具的检测脚本文件
on_check("check")
-- 设置平台初始化加载脚本文件,如果实现不复杂的话,可以使用内嵌函数
on_load("load")
-- 设置平台的帮助菜单
set_menu {
config =
{
{}
, {nil, "xcode_dir", "kv", "auto", "the xcode application directory" }
, {nil, "xcode_sdkver", "kv", "auto", "the sdk version for xcode" }
, {nil, "target_minver", "kv", "auto", "the target minimal version" }
, {}
, {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" }
, {nil, "codesign", "kv", "auto", "The Code Signing Indentity" }
, {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" }
}
, global =
{
{}
, {nil, "xcode_dir", "kv", "auto", "the xcode application directory" }
, {}
, {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" }
, {nil, "codesign", "kv", "auto", "The Code Signing Indentity" }
, {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" }
}
}
```
<p class="warning">
是在`platforms`目录相关平台的`xmake.lua`中编写,而不是在工程目录的`xmake.lua`中。
</p>
##### platform_end
###### 结束定义平台
这是一个可选api,显示离开选项作用域,用法和[target_end](#target_end)类似。
##### set_os
###### 设置平台系统
设置目标平台的操作系统,例如:`ios`, `android`, `linux`, `windows` 等
```lua
platform("iphoneos")
set_os("ios")
```
这个一般用于在自定义脚本和插件开发中,[core.platform.platform](#core-platform-platform)模块中进行访问,获取当前平台的操作系统。
##### set_menu
###### 设置平台菜单
先给个设置的例子:
```lua
platform("iphoneos")
...
-- 设置平台的帮助菜单
set_menu {
config =
{
{}
, {nil, "xcode_dir", "kv", "auto", "the xcode application directory" }
, {nil, "xcode_sdkver", "kv", "auto", "the sdk version for xcode" }
, {nil, "target_minver", "kv", "auto", "the target minimal version" }
, {}
, {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" }
, {nil, "codesign", "kv", "auto", "The Code Signing Indentity" }
, {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" }
}
, global =
{
{}
, {nil, "xcode_dir", "kv", "auto", "the xcode application directory" }
, {}
, {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" }
, {nil, "codesign", "kv", "auto", "The Code Signing Indentity" }
, {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" }
}
}
```
其中`config`组用来设置:`xmake f --help`中的本地工程菜单,`global`用来设置:`xmake g --help`全局平台配置中的菜单。
具体设置格式可参考:[task:set_menu](#taskset_menu)。
##### set_hosts
###### 设置平台支持的主机环境
用来设置当前目标平台支持主机构建环境,例如`iphoneos`平台可以在`macosx`主机系统上构建,那么可以设置为:
```lua
platform("iphoneos")
set_hosts("macosx")
```
而`android`平台可以同时在`linux`, "macosx", `windows`主机环境中构建,那么可以设置为:
```lua
platform("android")
set_hosts("linux", "macosx", "windows")
```
##### set_archs
###### 设置平台支持的架构环境
用来设置当前目标平台支持的编译架构环境,例如`iphoneos`平台可以构建`armv7`, `armv7s`, `arm64`, `i386`, `x86_64`等架构,那么可以设置为:
```lua
platform("iphoneos")
set_archs("armv7", "armv7s", "arm64", "i386", "x86_64")
```
配置好架构后,执行:`xmake f -h`,就会在对应arch参数描述,自动显示设置的架构列表:
```
-a ARCH, --arch=ARCH Compile for the given architecture. (default: auto)
- android: armv5te armv6 armv7-a armv8-a arm64-v8a
- iphoneos: armv7 armv7s arm64 i386 x86_64
- linux: i386 x86_64
- macosx: i386 x86_64
- mingw: i386 x86_64
- watchos: armv7k i386
- windows: x86 x64 amd64 x86_amd64
```
##### set_tooldirs
###### 设置平台工具的搜索目录
xmake会自动检测当前平台支持的一些构建工具是否存在,例如编译器、链接器等,如果要提高检测通过率,可以在平台配置的时候,设置一些工具环境搜索目录,例如:
```lua
platform("linux")
-- 在linux下检测这些目录环境
set_tooldirs("/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin")
```
##### on_load
###### 设置加载平台环境配置脚本
一般用于在平台刚加载时,设置一些基本配置:生成目标文件命名格式、平台相关编译选项等
```lua
platform("windows")
-- on load
on_load(function ()
-- init the file formats
_g.formats = {}
_g.formats.static = {"", ".lib"}
_g.formats.object = {"", ".obj"}
_g.formats.shared = {"", ".dll"}
_g.formats.binary = {"", ".exe"}
_g.formats.symbol = {"", ".pdb"}
-- init flags for dlang
local dc_archs = { x86 = "-m32", x64 = "-m64", amd64 = "-m64", x86_amd64 = "-m64" }
_g.dcflags = { dc_archs[arch] or "" }
_g["dc-shflags"] = { dc_archs[arch] or "" }
_g["dc-ldflags"] = { dc_archs[arch] or "" }
-- ok
return _g
end)
```
如果加载逻辑比较复杂,可以独立成单独`init.lua`文件,然后设置为:
```lua
platform("xxxx")
on_load("init")
```
通过这种方式,会自动加载平台脚本目录下对应的`init.lua`文件,调用`function main() end`函数入口,完成复杂加载逻辑。
##### on_check
###### 设置平台工具的检测脚本
由于每个平台检测的工具非常多,脚本比较复杂,一般直接独立成`check.lua`文件来实现检测逻辑,例如:
```lua
platform("xxx")
on_check("check")
```
具体的检测代码入口如下:
```lua
-- check it
function main(kind)
-- init the check list of config
_g.config =
{
__check_arch
, checker.check_ccache
, _check_toolchains
}
-- init the check list of global
_g.global =
{
checker.check_ccache
, _check_ndk_sdkver
}
-- check it
checker.check(kind, _g)
end
```
具体实现这里就不介绍了,可以参考xmake源码目录下的`platforms`平台配置代码: [check.lua](https://github.com/tboox/xmake/blob/master/xmake/platforms/macosx/check.lua)
##### on_install
###### 设置目标工程在指定平台的安装脚本
具体实现逻辑见xmake源码:[install.lua](https://github.com/tboox/xmake/blob/master/xmake/platforms/macosx/install.lua)
##### on_uninstall
###### 设置目标工程在指定平台的卸载脚本
具体实现逻辑见xmake源码:[uninstall.lua](https://github.com/tboox/xmake/blob/master/xmake/platforms/macosx/uninstall.lua)
#### Extension Languages
有待后续完善。。
#### Project Templates
##### template
##### set_description
##### set_projectdir
##### add_macros
##### add_macrofiles
#### Builtin Variables
xmake提供了 `$(varname)` 的语法,来支持内置变量的获取,例如:
```lua
add_cxflags("-I$(buildir)")
```
它将会在在实际编译的时候,将内置的 `buildir` 变量转换为实际的构建输出目录:`-I./build`
一般内置变量可用于在传参时快速获取和拼接变量字符串,例如:
```lua
target("test")
-- 添加工程源码目录下的源文件
add_files("$(projectdir)/src/*.c")
-- 添加构建目录下的头文件搜索路径
add_includedirs("$(buildir)/inc")
```
也可以在自定义脚本的模块接口中使用,例如:
```lua
target("test")
on_run(function (target)
-- 复制当前脚本目录下的头文件到输出目录
os.cp("$(scriptdir)/xxx.h", "$(buildir)/inc")
end)
```
这种使用内置变量的方式,使得描述编写更加的简洁易读,下面是一些xmake内置的变量,可以直接获取:
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [$(os)](#var-os) | 获取当前编译平台的操作系统 | >= 2.0.1 |
| [$(host)](#var-host) | 获取本机操作系统 | >= 2.0.1 |
| [$(tmpdir)](#var-tmpdir) | 获取临时目录 | >= 2.0.1 |
| [$(curdir)](#var-curdir) | 获取当前目录 | >= 2.0.1 |
| [$(buildir)](#var-buildir) | 获取构建输出目录 | >= 2.0.1 |
| [$(scriptdir)](#var-scriptdir) | 获取工程描述脚本目录 | >= 2.1.1 |
| [$(globaldir)](#var-globaldir) | 获取全局配置目录 | >= 2.0.1 |
| [$(configdir)](#var-configdir) | 获取本地工程配置目录 | >= 2.0.1 |
| [$(projectdir)](#var-projectdir) | 获取工程根目录 | >= 2.0.1 |
| [$(packagedir)](#var-packagedir) | 获取依赖包目录 | >= 2.0.1 |
| [$(shell)](#var-shell) | 执行外部shell命令 | >= 2.0.1 |
当然这种变量模式,也是可以扩展的,默认通过`xmake f --var=val`命令,配置的参数都是可以直接获取,例如:
```lua
target("test")
add_defines("-DTEST=$(var)")
```
既然支持直接从配置选项中获取,那么当然也就能很方便的扩展自定义的选项,来获取自定义的变量了,具体如何自定义选项见:[option](#option)
##### var.$(os)
###### 获取当前编译平台的操作系统
如果当前编译的是iphoneos,那么这个值就是:`ios`,以此类推。
##### var.$(host)
###### 获取本机操作系统
指的是当前本机环境的主机系统,如果你是在macOS上编译,那么系统就是:`macosx`
##### var.$(tmpdir)
###### 获取临时目录
一般用于临时存放一些非永久性文件。
##### var.$(curdir)
###### 获取当前目录
一般默认是执行`xmake`命令时的工程根目录,当然如果通过[os.cd](#os-cd)改变了目录的话,这个值也会一起改变。
##### var.$(buildir)
###### 获取当前的构建输出目录
默认一般为当前工程根目录下的:`./build`目录,也可以通过执行:`xmake f -o /tmp/build`命令来修改默认的输出目录。
##### var.$(scriptdir)
###### 获取当前工程描述脚本的目录
也就是对应`xmake.lua`所在的目录路径。
##### var.$(globaldir)
###### 全局配置目录
xmake的`xmake g|global`全局配置命令,数据存储的目录路径,在里面可以放置一些自己的插件、平台脚本。
默认为:`~/.config`
##### var.$(configdir)
###### 当前工程配置目录
当前工程的配置存储目录,也就是`xmake f|config`配置命令的存储目录,默认为:`projectdir/.config`
##### var.$(projectdir)
###### 工程根目录
也就是`xmake -P xxx`命令中指定的目录路径,默认不指定就是`xmake`命令执行时的当前目录,一般用于定位工程文件。
##### var.$(packagedir)
###### 依赖包目录
也就是加载依赖包的搜索目录,通常用于获取一些包文件。
##### var.$(shell)
###### 执行外部shell命令
除了内置的变量处理,xmake还支持原生shell的运行,来处理一些xmake内置不支持的功能
例如,现在有个需求,我想用在编译linux程序时,调用`pkg-config`获取到实际的第三方链接库名,可以这么做:
```lua
target("test")
set_kind("binary")
if is_plat("linux") then
add_ldflags("$(shell pkg-config --libs sqlite3)")
end
```
当然,xmake有自己的自动化第三库检测机制,一般情况下不需要这么麻烦,而且lua自身的脚本化已经很不错了。。
但是这个例子可以说明,xmake是完全可以通过原生shell,来与一些第三方的工具进行配合使用。。
#### Builtin Modules
在自定义脚本、插件脚本、任务脚本、平台扩展、模板扩展等脚本代码中使用,也就是在类似下面的代码块中,可以使用这些模块接口:
```lua
on_run(function (target)
print("hello xmake!")
end)
```
<p class="warning">
为了保证外层的描述域尽可能简洁、安全,一般不建议在这个域使用接口和模块操作api,因此大部分模块接口只能再脚本域使用,来实现复杂功能。</br>
当然少部分只读的内置接口还是可以在描述域使用的,具体见下表:
</p>
| 接口 | 描述 | 可使用域 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------------------------- | -------- |
| [import](#import) | 导入扩展摸块 | 脚本域 | >= 2.0.1 |
| [inherit](#inherit) | 导入并继承基类模块 | 脚本域 | >= 2.0.1 |
| [ifelse](#ifelse) | 类似三元条件判断 | 描述域、脚本域 | >= 2.0.1 |
| [try-catch-finally](#try-catch-finally) | 异常捕获 | 脚本域 | >= 2.0.1 |
| [pairs](#pairs) | 用于遍历字典 | 描述域、脚本域 | >= 2.0.1 |
| [ipairs](#ipairs) | 用于遍历数组 | 描述域、脚本域 | >= 2.0.1 |
| [print](#print) | 换行打印终端日志 | 描述域、脚本域 | >= 2.0.1 |
| [printf](#printf) | 无换行打印终端日志 | 脚本域 | >= 2.0.1 |
| [cprint](#cprint) | 换行彩色打印终端日志 | 脚本域 | >= 2.0.1 |
| [cprintf](#cprintf) | 无换行彩色打印终端日志 | 脚本域 | >= 2.0.1 |
| [format](#format) | 格式化字符串 | 描述域、脚本域 | >= 2.0.1 |
| [raise](#raise) | 抛出异常中断程序 | 脚本域 | >= 2.0.1 |
| [os](#os) | 系统操作模块 | 部分只读操作描述域、脚本域 | >= 2.0.1 |
| [io](#io) | 文件操作模块 | 脚本域 | >= 2.0.1 |
| [path](#path) | 路径操作模块 | 描述域、脚本域 | >= 2.0.1 |
| [table](#table) | 数组和字典操作模块 | 描述域、脚本域 | >= 2.0.1 |
| [string](#string) | 字符串操作模块 | 描述域、脚本域 | >= 2.0.1 |
| [process](#process) | 进程操作模块 | 脚本域 | >= 2.0.1 |
| [coroutine](#coroutine) | 协程操作模块 | 脚本域 | >= 2.0.1 |
在描述域使用接口调用的实例如下,一般仅用于条件控制:
```lua
-- 扫描当前xmake.lua目录下的所有子目录,以每个目录的名字定义一个task任务
for _, taskname in ipairs(os.dirs("*"), path.basename) do
task(taskname)
on_run(function ()
end)
end
```
上面所说的脚本域、描述域主要是指:
```lua
-- 描述域
target("test")
-- 描述域
set_kind("static")
add_files("src/*.c")
on_run(function (target)
-- 脚本域
end)
-- 描述域
```
##### import
###### 导入扩展摸块
import的主要用于导入xmake的扩展类库以及一些自定义的类库模块,一般用于:
* 自定义脚本([on_build](#targeton_build), [on_run](#targeton_run) ..)
* 插件开发
* 模板开发
* 平台扩展
* 自定义任务task
导入机制如下:
1. 优先从当前脚本目录下导入
2. 再从扩展类库中导入
导入的语法规则:
基于`.`的类库路径规则,例如:
导入core核心扩展模块
```lua
import("core.base.option")
import("core.project")
import("core.project.task")
import("core")
function main()
-- 获取参数选项
print(option.get("version"))
-- 运行任务和插件
task.run("hello")
project.task.run("hello")
core.project.task.run("hello")
end
```
导入当前目录下的自定义模块:
目录结构:
```
plugin
- xmake.lua
- main.lua
- modules
- hello1.lua
- hello2.lua
```
在main.lua中导入modules
```lua
import("modules.hello1")
import("modules.hello2")
```
导入后就可以直接使用里面的所有公有接口,私有接口用`_`前缀标示,表明不会被导出,不会被外部调用到。。
除了当前目录,我们还可以导入其他指定目录里面的类库,例如:
```lua
import("hello3", {rootdir = "/home/xxx/modules"})
```
为了防止命名冲突,导入后还可以指定的别名:
```lua
import("core.platform.platform", {alias = "p"})
function main()
-- 这样我们就可以使用p来调用platform模块的plats接口,获取所有xmake支持的平台列表了
table.dump(p.plats())
end
```
import不仅可以导入类库,还支持导入的同时作为继承导入,实现模块间的继承关系
```lua
import("xxx.xxx", {inherit = true})
```
这样导入的不是这个模块的引用,而是导入的这个模块的所有公有接口本身,这样就会跟当前模块的接口进行合并,实现模块间的继承。
##### inherit
###### 导入并继承基类模块
这个等价于[import](#import)接口的`inherit`模式,也就是:
```lua
import("xxx.xxx", {inherit = true})
```
用`inherit`接口的话,会更简洁些:
```lu
inherit("xxx.xxx")
```
使用实例,可以参看xmake的tools目录下的脚本:[clang.lua](#https://github.com/tboox/xmake/blob/master/xmake/tools/clang.lua)
这个就是clang工具模块继承了gcc的部分实现。
##### ifelse
###### 类似三元条件判断
由于lua没有内置的三元运算符,通过封装`ifelse`接口,实现更加简洁的条件选择:
```lua
local ok = ifelse(a == 0, "ok", "no")
```
##### try-catch-finally
###### 异常捕获
lua原生并没有提供try-catch的语法来捕获异常处理,但是提供了`pcall/xpcall`等接口,可在保护模式下执行lua函数。
因此,可以通过封装这两个接口,来实现try-catch块的捕获机制。
我们可以先来看下,封装后的try-catch使用方式:
```lua
try
{
-- try 代码块
function ()
error("error message")
end,
-- catch 代码块
catch
{
-- 发生异常后,被执行
function (errors)
print(errors)
end
}
}
```
上面的代码中,在try块内部认为引发了一个异常,并且抛出错误消息,在catch中进行了捕获,并且将错误消息进行输出显示。
而finally的处理,这个的作用是对于`try{}`代码块,不管是否执行成功,都会执行到finally块中
也就说,其实上面的实现,完整的支持语法是:`try-catch-finally`模式,其中catch和finally都是可选的,根据自己的实际需求提供
例如:
```lua
try
{
-- try 代码块
function ()
error("error message")
end,
-- catch 代码块
catch
{
-- 发生异常后,被执行
function (errors)
print(errors)
end
},
-- finally 代码块
finally
{
-- 最后都会执行到这里
function (ok, errors)
-- 如果try{}中存在异常,ok为true,errors为错误信息,否则为false,errors为try中的返回值
end
}
}
```
或者只有finally块:
```lua
try
{
-- try 代码块
function ()
return "info"
end,
-- finally 代码块
finally
{
-- 由于此try代码没发生异常,因此ok为true,errors为返回值: "info"
function (ok, errors)
end
}
}
```
处理可以在finally中获取try里面的正常返回值,其实在仅有try的情况下,也是可以获取返回值的:
```lua
-- 如果没发生异常,result 为返回值:"xxxx",否则为nil
local result = try
{
function ()
return "xxxx"
end
}
```
在xmake的自定义脚本、插件开发中,也是完全基于此异常捕获机制
这样使得扩展脚本的开发非常的精简可读,省去了繁琐的`if err ~= nil then`返回值判断,在发生错误时,xmake会直接抛出异常进行中断,然后高亮提示详细的错误信息。
例如:
```lua
target("test")
set_kind("binary")
add_files("src/*.c")
-- 在编译完ios程序后,对目标程序进行ldid签名
after_build(function (target))
os.run("ldid -S %s", target:targetfile())
end
```
只需要一行`os.run`就行了,也不需要返回值判断是否运行成功,因为运行失败后,xmake会自动抛异常,中断程序并且提示错误
如果你想在运行失败后,不直接中断xmake,继续往下运行,可以自己加个try快就行了:
```lua
target("test")
set_kind("binary")
add_files("src/*.c")
after_build(function (target))
try
{
function ()
os.run("ldid -S %s", target:targetfile())
end
}
end
```
如果还想捕获出错信息,可以再加个catch:
```lua
target("test")
set_kind("binary")
add_files("src/*.c")
after_build(function (target))
try
{
function ()
os.run("ldid -S %s", target:targetfile())
end,
catch
{
function (errors)
print(errors)
end
}
}
end
```
不过一般情况下,在xmake中写自定义脚本,是不需要手动加try-catch的,直接调用各种api,出错后让xmake默认的处理程序接管,直接中断就行了。。
##### pairs
###### 用于遍历字典
这个是lua原生的内置api,在xmake中,在原有的行为上对其进行了一些扩展,来简化一些日常的lua遍历代码。
先看下默认的原生写法:
```lua
local t = {a = "a", b = "b", c = "c", d = "d", e = "e", f = "f"}
for key, val in pairs(t) do
print("%s: %s", key, val)
end
```
这对于通常的遍历操作就足够了,但是如果我们相对其中每个遍历出来的元素,获取其大写,我们可以这么写:
```lua
for key, val in pairs(t, function (v) return v:upper() end) do
print("%s: %s", key, val)
end
```
甚至传入一些参数到第二个`function`中,例如:
```lua
for key, val in pairs(t, function (v, a, b) return v:upper() .. a .. b end, "a", "b") do
print("%s: %s", key, val)
end
```
##### ipairs
###### 用于遍历数组
这个是lua原生的内置api,在xmake中,在原有的行为上对其进行了一些扩展,来简化一些日常的lua遍历代码。
先看下默认的原生写法:
```lua
for idx, val in ipairs({"a", "b", "c", "d", "e", "f"}) do
print("%d %s", idx, val)
end
```
扩展写法类似[pairs](#pairs)接口,例如:
```lua
for idx, val in ipairs({"a", "b", "c", "d", "e", "f"}, function (v) return v:upper() end) do
print("%d %s", idx, val)
end
for idx, val in ipairs({"a", "b", "c", "d", "e", "f"}, function (v, a, b) return v:upper() .. a .. b end, "a", "b") do
print("%d %s", idx, val)
end
```
这样可以简化`for`块代码的逻辑,例如我要遍历指定目录,获取其中的文件名,但不包括路径,就可以通过这种扩展方式,简化写法:
```lua
for _, filename in ipairs(os.dirs("*"), path.filename) do
-- ...
end
```
##### print
###### 换行打印终端日志
此接口也是lua的原生接口,xmake在原有行为不变的基础上也进行了扩展,同时支持:格式化输出、多变量输出。
先看下原生支持的方式:
```lua
print("hello xmake!")
print("hello", "xmake!", 123)
```
并且同时还支持扩展的格式化写法:
```lua
print("hello %s!", "xmake")
print("hello xmake! %d", 123)
```
xmake会同时支持这两种写法,内部会去自动智能检测,选择输出行为。
##### printf
###### 无换行打印终端日志
类似[print](#print)接口,唯一的区别就是不换行。
##### cprint
###### 换行彩色打印终端日志
行为类似[print](#print),区别就是此接口还支持彩色终端输出,并且支持`emoji`字符输出。
例如:
```lua
cprint('${bright}hello xmake')
cprint('${red}hello xmake')
cprint('${bright green}hello ${clear}xmake')
cprint('${blue onyellow underline}hello xmake${clear}')
cprint('${red}hello ${magenta}xmake')
cprint('${cyan}hello ${dim yellow}xmake')
```
显示结果如下:

跟颜色相关的描述,都放置在 `${ }` 里面,可以同时设置多个不同的属性,例如:
```
${bright red underline onyellow}
```
表示:高亮红色,背景黄色,并且带下滑线
所有这些描述,都会影响后面一整行字符,如果只想显示部分颜色的文字,可以在结束位置,插入`${clear}`清楚前面颜色描述
例如:
```
${red}hello ${clear}xmake
```
这样的话,仅仅hello是显示红色,其他还是正常默认黑色显示。
其他颜色属于,我这里就不一一介绍,直接贴上xmake代码里面的属性列表吧:
```lua
colors.keys =
{
-- 属性
reset = 0 -- 重置属性
, clear = 0 -- 清楚属性
, default = 0 -- 默认属性
, bright = 1 -- 高亮
, dim = 2 -- 暗色
, underline = 4 -- 下划线
, blink = 5 -- 闪烁
, reverse = 7 -- 反转颜色
, hidden = 8 -- 隐藏文字
-- 前景色
, black = 30
, red = 31
, green = 32
, yellow = 33
, blue = 34
, magenta = 35
, cyan = 36
, white = 37
-- 背景色
, onblack = 40
, onred = 41
, ongreen = 42
, onyellow = 43
, onblue = 44
, onmagenta = 45
, oncyan = 46
, onwhite = 47
```
除了可以色彩高亮显示外,如果你的终端是在macosx下,lion以上的系统,xmake还可以支持emoji表情的显示哦,对于不支持系统,会
忽略显示,例如:
```lua
cprint("hello xmake${beer}")
cprint("hello${ok_hand} xmake")
```
上面两行代码,我打印了一个homebrew里面经典的啤酒符号,下面那行打印了一个ok的手势符号,是不是很炫哈。。

所有的emoji表情,以及xmake里面对应的key,都可以通过[emoji符号](http://www.emoji-cheat-sheet.com/)里面找到。。
##### cprintf
###### 无换行彩色打印终端日志
此接口类似[cprint](#cprint),区别就是不换行输出。
##### format
###### 格式化字符串
如果只是想格式化字符串,不进行输出,可以使用这个接口,此接口跟[string.format](#string-format)接口等价,只是个接口名简化版。
```lua
local s = format("hello %s", xmake)
```
##### raise
###### 抛出异常中断程序
如果想在自定义脚本、插件任务中中断xmake运行,可以使用这个接口跑出异常,如果上层没有显示调用[try-catch](#try-catch-finally)捕获的话,xmake就会中断执行,并且显示出错信息。
```lua
if (errors) raise(errors)
```
如果在try块中抛出异常,就会在catch和finally中进行errors信息捕获,具体见:[try-catch](#try-catch-finally)
##### os
系统操作模块,属于内置模块,无需使用[import](#import)导入,可直接脚本域调用其接口。
此模块也是lua的原生模块,xmake在其基础上进行了扩展,提供更多实用的接口。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [os.cp](#os-cp) | 复制文件或目录 | >= 2.0.1 |
| [os.mv](#os-mv) | 移动重命名文件或目录 | >= 2.0.1 |
| [os.rm](#os-rm) | 删除文件或目录树 | >= 2.0.1 |
| [os.cd](#os-cd) | 进入指定目录 | >= 2.0.1 |
| [os.rmdir](#os-rmdir) | 删除目录树 | >= 2.0.1 |
| [os.mkdir](#os-mkdir) | 创建指定目录 | >= 2.0.1 |
| [os.isdir](#os-isdir) | 判断目录是否存在 | >= 2.0.1 |
| [os.isfile](#os-isfile) | 判断文件是否存在 | >= 2.0.1 |
| [os.exists](#os-exists) | 判断文件或目录是否存在 | >= 2.0.1 |
| [os.dirs](#os-dirs) | 遍历获取指定目录下的所有目录 | >= 2.0.1 |
| [os.files](#os-files) | 遍历获取指定目录下的所有文件 | >= 2.0.1 |
| [os.filedirs](#os-filedirs) | 遍历获取指定目录下的所有文件或目录 | >= 2.0.1 |
| [os.run](#os-run) | 安静运行程序 | >= 2.0.1 |
| [os.exec](#os-exec) | 回显运行程序 | >= 2.0.1 |
| [os.iorun](#os-iorun) | 运行并获取程序输出内容 | >= 2.0.1 |
| [os.getenv](#os-getenv) | 获取环境变量 | >= 2.0.1 |
| [os.setenv](#os-setenv) | 设置环境变量 | >= 2.0.1 |
| [os.tmpdir](#os-tmpdir) | 获取临时目录路径 | >= 2.0.1 |
| [os.tmpfile](#os-tmpfile) | 获取临时文件路径 | >= 2.0.1 |
| [os.curdir](#os-curdir) | 获取当前目录路径 | >= 2.0.1 |
| [os.scriptdir](#os-scriptdir) | 获取脚本目录路径 | >= 2.0.1 |
| [os.arch](#os-arch) | 获取当前系统架构 | >= 2.0.1 |
| [os.host](#os-host) | 获取当前主机系统 | >= 2.0.1 |
###### os.cp
- 复制文件或目录
行为和shell中的`cp`命令类似,支持路径通配符匹配(使用的是lua模式匹配),支持多文件复制,以及内置变量支持。
例如:
```lua
os.cp("$(scriptdir)/*.h", "$(projectdir)/src/test/**.h", "$(buildir)/inc")
```
上面的代码将:当前`xmake.lua`目录下的所有头文件、工程源码test目录下的头文件全部复制到`$(buildir)`输出目录中。
其中`$(scriptdir)`, `$(projectdir)` 这些变量是xmake的内置变量,具体详情见:[内置变量](#内置变量)的相关文档。
而`*.h`和`**.h`中的匹配模式,跟[add_files](#targetadd_files)中的类似,前者是单级目录匹配,后者是递归多级目录匹配。
此接口同时支持目录的`递归复制`,例如:
```lua
-- 递归复制当前目录到临时目录
os.cp("$(curdir)/test/", "$(tmpdir)/test")
```
<p class="tip">
尽量使用`os.cp`接口,而不是`os.run("cp ..")`,这样更能保证平台一致性,实现跨平台构建描述。
</p>
###### os.mv
- 移动重命名文件或目录
跟[os.cp](#os-cp)的使用类似,同样支持多文件移动操作和模式匹配,例如:
```lua
-- 移动多个文件到临时目录
os.mv("$(buildir)/test1", "$(buildir)/test2", "$(tmpdir)")
-- 文件移动不支持批量操作,也就是文件重命名
os.mv("$(buildir)/libtest.a", "$(buildir)/libdemo.a")
```
###### os.rm
- 删除文件或目录树
支持递归删除目录,批量删除操作,以及模式匹配和内置变量,例如:
```lua
os.rm("$(buildir)/inc/**.h", "$(buildir)/lib/")
```
###### os.cd
- 进入指定目录
这个操作用于目录切换,同样也支持内置变量,但是不支持模式匹配和多目录处理,例如:
```lua
-- 进入临时目录
os.cd("$(tmpdir)")
```
如果要离开进入之前的目录,有多种方式:
```lua
-- 进入上级目录
os.cd("..")
-- 进入先前的目录,相当于:cd -
os.cd("-")
-- 进入目录前保存之前的目录,用于之后跨级直接切回
local oldir = os.cd("./src")
...
os.cd(oldir)
```
###### os.rmdir
- 仅删除目录
如果不是目录就无法删除。
###### os.mkdir
- 创建目录
支持批量创建和内置变量,例如:
```lua
os.mkdir("$(tmpdir)/test", "$(buildir)/inc")
```
###### os.isdir
- 判断是否为目录
如果目录不存在,则返回false
```lua
if os.isdir("src") then
-- ...
end
```
###### os.isfile
- 判断是否为文件
如果文件不存在,则返回false
```lua
if os.isfile("$(buildir)/libxxx.a") then
-- ...
end
```
###### os.exists
- 判断文件或目录是否存在
如果文件或目录不存在,则返回false
```lua
-- 判断目录存在
if os.exists("$(buildir)") then
-- ...
end
-- 判断文件存在
if os.exists("$(buildir)/libxxx.a") then
-- ...
end
```
###### os.dirs
- 遍历获取指定目录下的所有目录
支持[add_files](#targetadd_files)中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:
```lua
-- 递归遍历获取所有子目录
for _, dir in ipairs(os.dirs("$(buildir)/inc/**")) do
print(dir)
end
```
###### os.files
- 遍历获取指定目录下的所有文件
支持[add_files](#targetadd_files)中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:
```lua
-- 非递归遍历获取所有子文件
for _, filepath in ipairs(os.files("$(buildir)/inc/*.h")) do
print(filepath)
end
```
###### os.filedirs
- 遍历获取指定目录下的所有文件和目录
支持[add_files](#targetadd_files)中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:
```lua
-- 递归遍历获取所有子文件和目录
for _, filedir in ipairs(os.filedirs("$(buildir)/**")) do
print(filedir)
end
```
###### os.run
- 安静运行原生shell命令
用于执行第三方的shell命令,但不会回显输出,仅仅在出错后,高亮输出错误信息。
此接口支持参数格式化、内置变量,例如:
```lua
-- 格式化参数传入
os.run("echo hello %s!", "xmake")
-- 列举构建目录文件
os.run("ls -l $(buildir)")
```
<p class="warning">
使用此接口执行shell命令,容易使构建跨平台性降低,对于`os.run("cp ..")`这种尽量使用`os.cp`代替。<br>
如果必须使用此接口运行shell程序,请自行使用[config.plat](#config-plat)接口判断平台支持。
</p>
更加高级的进程运行和控制,见[process](#process)模块接口。
###### os.exec
- 回显运行原生shell命令
与[os.run](#os-run)接口类似,唯一的不同是,此接口执行shell程序时,是带回显输出的,一般调试的时候用的比较多
###### os.iorun
- 安静运行原生shell命令并获取输出内容
与[os.run](#os-run)接口类似,唯一的不同是,此接口执行shell程序后,会获取shell程序的执行结果,相当于重定向输出。
可同时获取`stdout`, `stderr`中的内容,例如:
```lua
local outdata, errdata = os.iorun("echo hello xmake!")
```
###### os.getenv
- 获取系统环境变量
```lua
print(os.getenv("PATH"))
```
###### os.setenv
- 设置系统环境变量
```lua
os.setenv("HOME", "/tmp/")
```
###### os.tmpdir
- 获取临时目录
跟[$(tmpdir)](#var-tmpdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。
```lua
print(path.join(os.tmpdir(), "file.txt"))
```
等价于:
```lua
print("$(tmpdir)/file.txt"))
```
###### os.tmpfile
- 获取临时文件路径
用于获取生成一个临时文件路径,仅仅是个路径,文件需要自己创建。
###### os.curdir
- 获取当前目录路径
跟[$(curdir)](#var-curdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。
用法参考:[os.tmpdir](#os-tmpdir)。
###### os.scriptdir
- 获取当前描述脚本的路径
跟[$(scriptdir)](#var-scriptdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。
用法参考:[os.tmpdir](#os-tmpdir)。
###### os.arch
- 获取当前系统架构
也就是当前主机系统的默认架构,例如我在`linux x86_64`上执行xmake进行构建,那么返回值是:`x86_64`
###### os.host
- 获取当前主机的操作系统
跟[$(host)](#var-host)结果一致,例如我在`linux x86_64`上执行xmake进行构建,那么返回值是:`linux`
##### io
io操作模块,扩展了lua内置的io模块,提供更多易用的接口。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [io.open](#io-open) | 打开文件用于读写 | >= 2.0.1 |
| [io.load](#io-load) | 从指定路径文件反序列化加载所有table内容 | >= 2.0.1 |
| [io.save](#io-save) | 序列化保存所有table内容到指定路径文件 | >= 2.0.1 |
| [io.read](#io-read) | 从指定路径文件读取所有内容 | >= 2.0.1 |
| [io.write](#io-write) | 写入所有内容到指定路径文件 | >= 2.0.1 |
| [io.gsub](#io-gsub) | 全文替换指定路径文件的内容 | >= 2.0.1 |
| [io.tail](#io-tail) | 读取和显示文件的尾部内容 | >= 2.0.1 |
| [io.cat](#io-cat) | 读取和显示文件的所有内容 | >= 2.0.1 |
| [io.print](#io-print) | 带换行格式化输出内容到文件 | >= 2.0.1 |
| [io.printf](#io-printf) | 无换行格式化输出内容到文件 | >= 2.0.1 |
###### io.open
- 打开文件用于读写
这个是属于lua的原生接口,详细使用可以参看lua的官方文档:[The Complete I/O Model](https://www.lua.org/pil/21.2.html)
如果要读取文件所有内容,可以这么写:
```lua
local file = io.open("$(tmpdir)/file.txt", "r")
if file then
local data = file:read("*all")
file:close()
end
```
或者可以使用[io.read](#io-read)更加快速地读取。
如果要写文件,可以这么操作:
```lua
-- 打开文件:w 为写模式, a 为追加写模式
local file = io.open("xxx.txt", "w")
if file then
-- 用原生的lua接口写入数据到文件,不支持格式化,无换行,不支持内置变量
file:write("hello xmake\n")
-- 用xmake扩展的接口写入数据到文件,支持格式化,无换行,不支持内置变量
file:writef("hello %s\n", "xmake")
-- 使用xmake扩展的格式化传参写入一行,带换行符,并且支持内置变量
file:print("hello %s and $(buildir)", "xmake")
-- 使用xmake扩展的格式化传参写入一行,无换行符,并且支持内置变量
file:printf("hello %s and $(buildir) \n", "xmake")
-- 关闭文件
file:close()
end
```
###### io.load
- 从指定路径文件反序列化加载所有table内容
可以从文件中加载序列化好的table内容,一般与[io.save](#io-save)配合使用,例如:
```lua
-- 加载序列化文件的内容到table
local data = io.load("xxx.txt")
if data then
-- 在终端中dump打印整个table中内容,格式化输出
table.dump(data)
end
```
###### io.save
- 序列化保存所有table内容到指定路径文件
可以序列化存储table内容到指定文件,一般与[io.load](#io-load)配合使用,例如:
```lua
io.save("xxx.txt", {a = "a", b = "b", c = "c"})
```
存储结果为:
```
{
["b"] = "b"
, ["a"] = "a"
, ["c"] = "c"
}
```
###### io.read
- 从指定路径文件读取所有内容
可在不打开文件的情况下,直接读取整个文件的内容,更加的方便,例如:
```lua
local data = io.read("xxx.txt")
```
###### io.write
- 写入所有内容到指定路径文件
可在不打开文件的情况下,直接写入整个文件的内容,更加的方便,例如:
```lua
io.write("xxx.txt", "all data")
```
###### io.gsub
- 全文替换指定路径文件的内容
类似[string.gsub](#string-gsub)接口,全文模式匹配替换内容,不过这里是直接操作文件,例如:
```lua
-- 移除文件所有的空白字符
io.gsub("xxx.txt", "%s+", "")
```
###### io.tail
- 读取和显示文件的尾部内容
读取文件尾部指定行数的数据,并显示,类似`cat xxx.txt | tail -n 10`命令,例如:
```lua
-- 显示文件最后10行内容
io.tail("xxx.txt", 10)
```
###### io.cat
- 读取和显示文件的所有内容
读取文件的所有内容并显示,类似`cat xxx.txt`命令,例如:
```lua
io.cat("xxx.txt")
```
###### io.print
- 带换行格式化输出内容到文件
直接格式化传参输出一行字符串到文件,并且带换行,例如:
```lua
io.print("xxx.txt", "hello %s!", "xmake")
```
###### io.printf
- 无换行格式化输出内容到文件
直接格式化传参输出一行字符串到文件,不带换行,例如:
```lua
io.printf("xxx.txt", "hello %s!\n", "xmake")
```
##### path
路径操作模块,实现跨平台的路径操作,这是xmake的一个自定义的模块。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [path.join](#path-join) | 拼接路径 | >= 2.0.1 |
| [path.translate](#path-translate) | 转换路径到当前平台的路径风格 | >= 2.0.1 |
| [path.basename](#path-basename) | 获取路径最后不带后缀的文件名 | >= 2.0.1 |
| [path.filename](#path-filename) | 获取路径最后带后缀的文件名 | >= 2.0.1 |
| [path.extension](#path-extension) | 获取路径的后缀名 | >= 2.0.1 |
| [path.directory](#path-directory) | 获取路径最后的目录名 | >= 2.0.1 |
| [path.relative](#path-relative) | 转换成相对路径 | >= 2.0.1 |
| [path.absolute](#path-absolute) | 转换成绝对路径 | >= 2.0.1 |
| [path.is_absolute](#path-is_absolute) | 判断是否为绝对路径 | >= 2.0.1 |
###### path.join
- 拼接路径
将多个路径项进行追加拼接,由于`windows/unix`风格的路径差异,使用api来追加路径更加跨平台,例如:
```lua
print(path.join("$(tmpdir)", "dir1", "dir2", "file.txt"))
```
上述拼接在unix上相当于:`$(tmpdir)/dir1/dir2/file.txt`,而在windows上相当于:`$(tmpdir)\\dir1\\dir2\\file.txt`
如果觉得这样很繁琐,不够清晰简洁,可以使用:[path.translate](path-translate)方式,格式化转换路径字符串到当前平台支持的格式。
###### path.translate
- 转换路径到当前平台的路径风格
格式化转化指定路径字符串到当前平台支持的路径风格,同时支持`windows/unix`格式的路径字符串参数传入,甚至混合传入,例如:
```lua
print(path.translate("$(tmpdir)/dir/file.txt"))
print(path.translate("$(tmpdir)\\dir\\file.txt"))
print(path.translate("$(tmpdir)\\dir/dir2//file.txt"))
```
上面这三种不同格式的路径字符串,经过`translate`规范化后,就会变成当前平台支持的格式,并且会去掉冗余的路径分隔符。
###### path.basename
- 获取路径最后不带后缀的文件名
```lua
print(path.basename("$(tmpdir)/dir/file.txt"))
```
显示结果为:`file`
###### path.filename
- 获取路径最后带后缀的文件名
```lua
print(path.filename("$(tmpdir)/dir/file.txt"))
```
显示结果为:`file.txt`
###### path.extension
- 获取路径的后缀名
```lua
print(path.extensione("$(tmpdir)/dir/file.txt"))
```
显示结果为:`.txt`
###### path.directory
- 获取路径最后的目录名
```lua
print(path.directory("$(tmpdir)/dir/file.txt"))
```
显示结果为:`dir`
###### path.relative
- 转换成相对路径
```lua
print(path.relative("$(tmpdir)/dir/file.txt", "$(tmpdir)"))
```
显示结果为:`dir/file.txt`
第二个参数是指定相对的根目录,如果不指定,则默认相对当前目录:
```lua
os.cd("$(tmpdir)")
print(path.relative("$(tmpdir)/dir/file.txt"))
```
这样结果是一样的。
###### path.absolute
- 转换成绝对路径
```lua
print(path.absolute("dir/file.txt", "$(tmpdir)"))
```
显示结果为:`$(tmpdir)/dir/file.txt`
第二个参数是指定相对的根目录,如果不指定,则默认相对当前目录:
```lua
os.cd("$(tmpdir)")
print(path.absolute("dir/file.txt"))
```
这样结果是一样的。
###### path.is_absolute
- 判断是否为绝对路径
```lua
if path.is_absolute("/tmp/file.txt") then
-- 如果是绝对路径
end
```
##### table
table属于lua原生提供的模块,对于原生接口使用可以参考:[lua官方文档](http://www.lua.org/manual/5.1/manual.html#5.5)
xmake中对其进行了扩展,增加了一些扩展接口:
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [table.join](#table-join) | 合并多个table并返回 | >= 2.0.1 |
| [table.join2](#table-join2) | 合并多个table到第一个table | >= 2.0.1 |
| [table.dump](#table-dump) | 输出table的所有内容 | >= 2.0.1 |
| [table.unique](#table-unique) | 对table中的内容进行去重 | >= 2.0.1 |
| [table.slice](#table-slice) | 获取table的切片 | >= 2.0.1 |
###### table.join
- 合并多个table并返回
可以将多个table里面的元素进行合并后,返回到一个新的table中,例如:
```lua
local newtable = table.join({1, 2, 3}, {4, 5, 6}, {7, 8, 9})
```
结果为:`{1, 2, 3, 4, 5, 6, 7, 8, 9}`
并且它也支持字典的合并:
```lua
local newtable = table.join({a = "a", b = "b"}, {c = "c"}, {d = "d"})
```
结果为:`{a = "a", b = "b", c = "c", d = "d"}`
###### table.join2
- 合并多个table到第一个table
类似[table.join](#table.join),唯一的区别是,合并的结果放置在第一个参数中,例如:
```lua
local t = {0, 9}
table.join2(t, {1, 2, 3})
```
结果为:`t = {0, 9, 1, 2, 3}`
###### table.dump
- 输出table的所有内容
递归格式化打印table中的所有内容,一般用于调试, 例如:
```lua
table.dump({1, 2, 3})
```
结果为:`{1, 2, 3}`
###### table.unique
- 对table中的内容进行去重
去重table的元素,一般用于数组table,例如:
```lua
local newtable = table.unique({1, 1, 2, 3, 4, 4, 5})
```
结果为:`{1, 2, 3, 4, 5}`
###### table.slice
- 获取table的切片
用于提取数组table的部分元素,例如:
```lua
-- 提取第4个元素后面的所有元素,结果:{4, 5, 6, 7, 8, 9}
table.slice({1, 2, 3, 4, 5, 6, 7, 8, 9}, 4)
-- 提取第4-8个元素,结果:{4, 5, 6, 7, 8}
table.slice({1, 2, 3, 4, 5, 6, 7, 8, 9}, 4, 8)
-- 提取第4-8个元素,间隔步长为2,结果:{4, 6, 8}
table.slice({1, 2, 3, 4, 5, 6, 7, 8, 9}, 4, 8, 2)
```
##### string
字符串模块为lua原生自带的模块,具体使用见:[lua官方手册](http://www.lua.org/manual/5.1/manual.html#5.4)
xmake中对其进行了扩展,增加了一些扩展接口:
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [string.startswith](#string-startswith) | 判断字符串开头是否匹配 | >= 1.0.1 |
| [string.endswith](#string-endswith) | 判断字符串结尾是否匹配 | >= 1.0.1 |
| [string.split](#string-split) | 分割字符串 | >= 1.0.1 |
| [string.trim](#string-trim) | 去掉字符串左右空白字符 | >= 1.0.1 |
| [string.ltrim](#string-ltrim) | 去掉字符串左边空白字符 | >= 1.0.1 |
| [string.rtrim](#string-rtrim) | 去掉字符串右边空白字符 | >= 1.0.1 |
###### string.startswith
- 判断字符串开头是否匹配
```lua
local s = "hello xmake"
if s:startswith("hello") then
print("match")
end
```
###### string.endswith
- 判断字符串结尾是否匹配
```lua
local s = "hello xmake"
if s:endswith("xmake") then
print("match")
end
```
###### string.split
- 分割字符串
通过指定的分隔符进行字符串分割,分隔符可以是:字符,字符串、模式匹配字符串,例如:
```lua
local s = "hello xmake!"
s:split("%s+")
```
根据连续空白字符进行分割,结果为:`hello`, `xmake!`
```lua
local s = "hello,xmake:123"
s:split("[,:]")
```
上面的代码根据`,`或者`:`字符进行分割,结果为:`hello`, `xmake`, `123`
###### string.trim
- 去掉字符串左右空白字符
```lua
string.trim(" hello xmake! ")
```
结果为:"hello xmake!"
###### string.ltrim
- 去掉字符串左边空白字符
```lua
string.ltrim(" hello xmake! ")
```
结果为:"hello xmake! "
###### string.rtrim
- 去掉字符串右边空白字符
```lua
string.rtrim(" hello xmake! ")
```
结果为:" hello xmake!"
##### process
这个是xmake扩展的进程控制模块,用于更加灵活的控制进程,比起:[os.run](#os-run)系列灵活性更高,也更底层。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [process.open](#process-open) | 打开进程 | >= 2.0.1 |
| [process.wait](#process-wait) | 等待进程结束 | >= 2.0.1 |
| [process.close](#process-close) | 关闭进程对象 | >= 2.0.1 |
| [process.waitlist](#process-waitlist) | 同时等待多个进程 | >= 2.0.1 |
###### process.open
- 打开进程
通过路径创建运行一个指定程序,并且返回对应的进程对象:
```lua
-- 打开进程,后面两个参数指定需要捕获的stdout, stderr文件路径
local proc = process.open("echo hello xmake!", outfile, errfile)
if proc then
-- 等待进程执行完成
--
-- 参数二为等待超时,-1为永久等待,0为尝试获取进程状态
-- 返回值waitok为等待状态:1为等待进程正常结束,0为进程还在运行中,-1位等待失败
-- 返回值status为,等待进程结束后,进程返回的状态码
local waitok, status = process.wait(proc, -1)
-- 释放进程对象
process.close(proc)
end
```
###### process.wait
- 等待进程结束
具体使用见:[process.open](#process-open)
###### process.close
- 关闭进程对象
具体使用见:[process.open](#process-open)
###### process.waitlist
- 同时等待多个进程
```lua
-- 第二个参数是等待超时,返回进程状态列表
for _, procinfo in ipairs(process.waitlist(procs, -1)) do
-- 每个进程的:进程对象、进程pid、进程结束状态码
local proc = procinfo[1]
local procid = procinfo[2]
local status = procinfo[3]
end
```
##### coroutine
协程模块是lua原生自带的模块,具使用见:[lua官方手册](http://www.lua.org/manual/5.1/manual.html#5.2)
#### Extension Modules
所有扩展模块的使用,都需要通过[import](#import)接口,进行导入后才能使用。
##### core.base.option
一般用于获取xmake命令参数选项的值,常用于插件开发。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [option.get](#option-get) | 获取参数选项值 | >= 2.0.1 |
###### option.get
- 获取参数选项值
在插件开发中用于获取参数选项值,例如:
```lua
-- 导入选项模块
import("core.base.option")
-- 插件入口函数
function main(...)
print(option.get("info"))
end
```
上面的代码获取hello插件,执行:`xmake hello --info=xxxx` 命令时候传入的`--info=`选项的值,并显示:`xxxx`
对于非main入口的task任务或插件,可以这么使用:
```lua
task("hello")
on_run(function ())
import("core.base.option")
print(option.get("info"))
end)
```
##### core.tool.linker
链接器相关操作,常用于插件开发。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [linker.link](#linker-link) | 执行链接 | >= 2.0.1 |
| [linker.linkcmd](#linker-linkcmd) | 获取链接命令行 | >= 2.0.1 |
| [linker.linkflags](#linker-linkflags) | 获取链接选项 | >= 2.0.1 |
###### linker.link
- 执行链接
针对target,链接指定对象文件列表,生成对应的目标文件,例如:
```lua
linker.link({"a.o", "b.o", "c.o"}, target:targetfile(), target)
```
其中[target](#target),为工程目标,这里传入,主要用于获取target特定的链接选项,具体如果获取工程目标对象,见:[core.project.project](#core-project-project)
当然也可以不指定target,例如:
```lua
linker.link({"a.o", "b.o", "c.o"}, "/tmp/targetfile")
```
###### linker.linkcmd
- 获取链接命令行
直接获取[linker.link](#linker-link)中执行的命令行字符串,相当于:
```lua
os.run(linker.linkcmd({"a.o", "b.o", "c.o"}, target:targetfile(), target))
```
###### linker.linkflags
- 获取链接选项
获取[linker.linkcmd](#linker-linkcmd)中的链接选项字符串部分,不带shellname和对象文件列表,例如:
```lua
print(linker.linkflags(target))
```
获取target工程目标中的链接选项:`-L/tmp -lz -ldl ..`
##### core.tool.compiler
编译器相关操作,常用于插件开发。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [compiler.compile](#compiler-compile) | 执行编译 | >= 2.0.1 |
| [compiler.compcmd](#compiler-compcmd) | 获取编译命令行 | >= 2.0.1 |
| [compiler.compflags](#compiler-compflags) | 获取编译选项 | >= 2.0.1 |
###### compiler.compile
- 执行编译
针对target,链接指定对象文件列表,生成对应的目标文件,例如:
```lua
compiler.compile("xxx.c", "xxx.o", "xxx.h.d", target)
```
其中[target](#target),为工程目标,这里传入主要用于获取taeget的特定编译选项,具体如果获取工程目标对象,见:[core.project.project](#core-project-project)
而`xxx.h.d`文件用于存储为此源文件的头文件依赖文件列表,最后这两个参数都是可选的,编译的时候可以不传他们:
```lua
compiler.compile("xxx.c", "xxx.o")
```
来单纯编译一个源文件。
###### compiler.compcmd
- 获取编译命令行
直接获取[compiler.compile](#compiler-compile)中执行的命令行字符串,相当于:
```lua
os.run(compiler.compcmd("xxx.c", "xxx.o", incdepfile, target))
```
###### compiler.compflags
- 获取编译选项
获取[compiler.compcmd](#compiler-compcmd)中的编译选项字符串部分,不带shellname和文件列表,例如:
```lua
print(compiler.compflags(sourcefile, target))
```
其中第一个返回值是所有编译选项的字符串,第二个返回值是所有选项的数组列表,更加便于操作,例如:
```lua
local flagstr, flags = compiler.compcmd("xxx.c", "xxx.o")
```
##### core.project.config
用于获取工程编译时候的配置信息,也就是`xmake f|config --xxx=val` 传入的参数选项值。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [config.get](#config-get) | 获取指定配置值 | >= 2.0.1 |
| [config.load](#config-load) | 加载配置 | >= 2.0.1 |
| [config.arch](#config-arch) | 获取当前工程的架构配置 | >= 2.0.1 |
| [config.plat](#config-plat) | 获取当前工程的平台配置 | >= 2.0.1 |
| [config.mode](#config-mode) | 获取当前工程的编译模式配置 | >= 2.0.1 |
| [config.buildir](#config-buildir) | 获取当前工程的输出目录配置 | >= 2.0.1 |
| [config.directory](#config-directory) | 获取当前工程的配置信息目录 | >= 2.0.1 |
| [config.dump](#config-dump) | 打印输出当前工程的所有配置信息 | >= 2.0.1 |
###### config.get
- 获取指定配置值
用于获取`xmake f|config --xxx=val`的配置值,例如:
```lua
target("test")
on_run(function (target)
-- 导入配置模块
import("core.project.config")
-- 获取配置值
print(config.get("xxx"))
end)
```
###### config.load
- 加载配置
一般用于插件开发中,插件任务中不像工程的自定义脚本,环境需要自己初始化加载,默认工程配置是没有被加载的,如果要用[config.get](#config-get)接口获取工程配置,那么需要先:
```lua
-- 导入配置模块
import("core.project.config")
function main(...)
-- 先加载工程配置
config.load()
-- 获取配置值
print(config.get("xxx"))
end
```
###### config.arch
- 获取当前工程的架构配置
也就是获取`xmake f|config --arch=armv7`的平台配置,相当于`config.get("arch")`。
###### config.plat
- 获取当前工程的平台配置
也就是获取`xmake f|config --plat=iphoneos`的平台配置,相当于`config.get("plat")`。
###### config.mode
- 获取当前工程的编译模式配置
也就是获取`xmake f|config --mode=debug`的平台配置,相当于`config.get("mode")`。
###### config.buildir
- 获取当前工程的输出目录配置
也就是获取`xmake f|config -o /tmp/output`的平台配置,相当于`config.get("buildir")`。
###### config.directory
- 获取当前工程的配置信息目录
获取工程配置的存储目录,默认为:`projectdir/.config`
###### config.dump
- 打印输出当前工程的所有配置信息
输出结果例如:
```lua
{
sh = "xcrun -sdk macosx clang++"
, xcode_dir = "/Applications/Xcode.app"
, ar = "xcrun -sdk macosx ar"
, small = true
, object = false
, arch = "x86_64"
, xcode_sdkver = "10.12"
, ex = "xcrun -sdk macosx ar"
, cc = "xcrun -sdk macosx clang"
, rc = "rustc"
, plat = "macosx"
, micro = false
, host = "macosx"
, as = "xcrun -sdk macosx clang"
, dc = "dmd"
, gc = "go"
, openssl = false
, ccache = "ccache"
, cxx = "xcrun -sdk macosx clang"
, sc = "xcrun -sdk macosx swiftc"
, mm = "xcrun -sdk macosx clang"
, buildir = "build"
, mxx = "xcrun -sdk macosx clang++"
, ld = "xcrun -sdk macosx clang++"
, mode = "release"
, kind = "static"
}
```
##### core.project.global
用于获取xmake全局的配置信息,也就是`xmake g|global --xxx=val` 传入的参数选项值。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [global.get](#global-get) | 获取指定配置值 | >= 2.0.1 |
| [global.load](#global-load) | 加载配置 | >= 2.0.1 |
| [global.directory](#global-directory) | 获取全局配置信息目录 | >= 2.0.1 |
| [global.dump](#global-dump) | 打印输出所有全局配置信息 | >= 2.0.1 |
###### global.get
- 获取指定配置值
类似[config.get](#config-get),唯一的区别就是这个是从全局配置中获取。
###### global.load
- 加载配置
类似[global.get](#global-get),唯一的区别就是这个是从全局配置中加载。
###### global.directory
- 获取全局配置信息目录
默认为`~/.config`目录。
###### global.dump
- 打印输出所有全局配置信息
输出结果如下:
```lua
{
clean = true
, ccache = "ccache"
, xcode_dir = "/Applications/Xcode.app"
}
```
##### core.project.task
用于任务操作,一般用于在自定义脚本中、插件任务中,调用运行其他task任务。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [task.run](#task-run) | 运行指定任务 | >= 2.0.1 |
###### task.run
- 运行指定任务
用于在自定义脚本、插件任务中运行[task](#task)定义的任务或插件,例如:
```lua
task("hello")
on_run(function ()
print("hello xmake!")
end)
target("demo")
on_clean(function(target)
-- 导入task模块
import("core.project.task")
-- 运行这个hello task
task.run("hello")
end)
```
我们还可以在运行任务时,增加参数传递,例如:
```lua
task("hello")
on_run(function (arg1, arg2)
print("hello xmake: %s %s!", arg1, arg2)
end)
target("demo")
on_clean(function(target)
-- 导入task
import("core.project.task")
-- {} 这个是给第一种选项传参使用,这里置空,这里在最后面传入了两个参数:arg1, arg2
task.run("hello", {}, "arg1", "arg2")
end)
```
对于`task.run`的第二个参数,用于传递命令行菜单中的选项,而不是直接传入`function (arg, ...)`函数入口中,例如:
```lua
-- 导入task
import("core.project.task")
-- 插件入口
function main(...)
-- 运行内置的xmake配置任务,相当于:xmake f|config --plat=iphoneos --arch=armv7
task.run("config", {plat="iphoneos", arch="armv7"})
emd
```
##### core.project.project
用于获取当前工程的一些描述信息,也就是在`xmake.lua`工程描述文件中定义的配置信息,例如:[target](#target)、[option](#option)等。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [project.load](#project-load) | 加载工程配置 | >= 2.0.1 |
| [project.directory](#project-directory) | 获取工程目录 | >= 2.0.1 |
| [project.target](#project-target) | 获取指定工程目标对象 | >= 2.0.1 |
| [project.targets](#project-targets) | 获取工程目标对象列表 | >= 2.0.1 |
| [project.name](#project-name) | 获取当前工程名 | >= 2.0.1 |
| [project.version](#project-version) | 获取当前工程版本号 | >= 2.0.1 |
###### project.load
- 加载工程描述配置
仅在插件中使用,因为这个时候还没有加载工程配置信息,在工程目标的自定义脚本中,不需要执行此操作,就可以直接访问工程配置。
```lua
-- 导入工程模块
import("core.project.project")
-- 插件入口
function main(...)
-- 加载工程描述配置
project.load()
-- 访问工程描述,例如获取指定工程目标
local target = project.target("test")
end
```
###### project.directory
- 获取工程目录
获取当前工程目录,也就是`xmake -P xxx`中指定的目录,否则为默认当前`xmake`命令执行目录。
###### project.target
- 获取指定工程目标对象
获取和访问指定工程目标配置,例如:
```lua
local target = project.target("test")
if target then
-- 获取目标文件名
print(target:targetfile())
-- 获取目标类型,也就是:binary, static, shared
print(target:targetkind())
-- 获取目标名
print(target:name())
-- 获取目标源文件
local sourcefiles = target:sourcefiles()
-- 获取目标安装头文件列表
local srcheaders, dstheaders = target:headerfiles()
-- 获取目标依赖
print(target:get("deps"))
end
```
###### project.targets
- 获取工程目标对象列表
返回当前工程的所有编译目标,例如:
```lua
for targetname, target in pairs(project.targets())
-- ...
end
```
###### project.name
- 获取当前工程名
也就是获取[set_project](#set_project)的工程名配置。
```lua
print(project.name())
```
###### project.version
- 获取当前工程版本号
也就是获取[set_version](#set_version)的工程版本配置。
```lua
print(project.version())
```
##### core.language.language
用于获取编译语言相关信息,一般用于代码文件的操作。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [language.extensions](#language-extensions) | 获取所有语言的代码后缀名列表 | >= 2.1.1 |
| [language.targetkinds](#language-targetkinds) | 获取所有语言的目标类型列表 | >= 2.1.1 |
| [language.sourcekinds](#language-sourcekinds) | 获取所有语言的源文件类型列表 | >= 2.1.1 |
| [language.sourceflags](#language-sourceflags) | 加载所有语言的源文件编译选项名列表 | >= 2.1.1 |
| [language.load](#language-load) | 加载指定语言 | >= 2.1.1 |
| [language.load_sk](#language-load_sk) | 从源文件类型加载指定语言 | >= 2.1.1 |
| [language.load_ex](#language-load_ex) | 从源文件后缀名加载指定语言 | >= 2.1.1 |
| [language.sourcekind_of](#language-sourcekind_of) | 获取指定源文件的源文件类型 | >= 2.1.1 |
###### language.extensions
- 获取所有语言的代码后缀名列表
获取结果如下:
```lua
{
[".c"] = cc
, [".cc"] = cxx
, [".cpp"] = cxx
, [".m"] = mm
, [".mm"] = mxx
, [".swift"] = sc
, [".go"] = gc
}
```
###### language.targetkinds
- 获取所有语言的目标类型列表
获取结果如下:
```lua
{
binary = {"ld", "gc-ld", "dc-ld"}
, static = {"ar", "gc-ar", "dc-ar"}
, shared = {"sh", "dc-sh"}
}
```
###### language.sourcekinds
- 获取所有语言的源文件类型列表
获取结果如下:
```lua
{
cc = ".c"
, cxx = {".cc", ".cpp", ".cxx"}
, mm = ".m"
, mxx = ".mm"
, sc = ".swift"
, gc = ".go"
, rc = ".rs"
, dc = ".d"
, as = {".s", ".S", ".asm"}
}
```
###### language.sourceflags
- 加载所有语言的源文件编译选项名列表
获取结果如下:
```lua
{
cc = {"cflags", "cxflags"}
, cxx = {"cxxflags", "cxflags"}
, ...
}
```
###### language.load
- 加载指定语言
从语言名称加载具体语言对象,例如:
```lua
local lang = language.load("c++")
if lang then
print(lang:name())
end
```
###### language.load_sk
- 从源文件类型加载指定语言
从源文件类型:`cc, cxx, mm, mxx, sc, gc, as ..`加载具体语言对象,例如:
```lua
local lang = language.load_sk("cxx")
if lang then
print(lang:name())
end
```
###### language.load_ex
- 从源文件后缀名加载指定语言
从源文件后缀名:`.cc, .c, .cpp, .mm, .swift, .go ..`加载具体语言对象,例如:
```lua
local lang = language.load_sk(".cpp")
if lang then
print(lang:name())
end
```
###### language.sourcekind_of
- 获取指定源文件的源文件类型
也就是从给定的一个源文件路径,获取它是属于那种源文件类型,例如:
```lua
print(language.sourcekind_of("/xxxx/test.cpp"))
```
显示结果为:`cxx`,也就是`c++`类型,具体对应列表见:[language.sourcekinds](#language-sourcekinds)
##### core.platform.platform
平台信息相关操作
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [platform.get](#platform-get) | 获取指定平台相关配置信息 | >= 2.0.1 |
###### platform.get
- 获取指定平台相关配置信息
获取平台配置`xmake.lua`中设置的信息,一般只有在写插件的时候会用到,例如:
```lua
-- 获取当前平台的所有支持架构
print(platform.get("archs"))
-- 获取指定iphoneos平台的目标文件格式信息
local formats = platform.get("formats", "iphoneos")
table.dump(formats)
```
具体有哪些可读的平台配置信息,可参考:[platform](#platform)
##### core.platform.environment
环境相关操作,用于进入和离开指定环境变量对应的终端环境,一般用于`path`环境的进入和离开,尤其是一些需要特定环境的构建工具,例如:msvc的工具链。
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| [environment.enter](#environment-enter) | 进入指定环境 | >= 2.0.1 |
| [environment.leave](#environment-leave) | 离开指定环境 | >= 2.0.1 |
目前支持的环境有:
| 接口 | 描述 | 支持版本 |
| ----------------------------------------------- | -------------------------------------------- | -------- |
| toolchains | 工具链执行环境 | >= 2.0.1 |
###### environment.enter
- 进入指定环境
进入指定环境,例如msvc有自己的环境变量环境用于运行构建工具,例如:`cl.exe`, `link.exe`这些,这个时候想要在xmake里面运行他们,需要:
```lua
-- 进入工具链环境
environment.enter("toolchains")
-- 这个时候运行cl.exe才能正常运行,这个时候的path等环境变量都会进入msvc的环境模式
os.run("cl.exe ..")
-- 离开工具链环境
environment.leave("toolchains")
```
因此为了通用性,默认xmake编译事都会设置这个环境,在linux下基本上内部环境不需要特殊切换,目前仅对windows下msvc进行了处理。
###### environment.leave
- 离开指定环境
具体使用见:[environment.enter](#environment-enter)
|