aboutsummaryrefslogtreecommitdiff
blob: 3c634d6f6555ecc39bf51fb3dcf1044bf49b6c53 (plain)
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
# Copyright 2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

# @ECLASS: dlang-utils.eclass
# @MAINTAINER:
# Andrei Horodniceanu <a.horodniceanu@proton.me>
# @AUTHOR:
# Andrei Horodniceanu <a.horodniceanu@proton.me>
# Based on python-utils-r1.eclass by Michał Górny <mgorny@gentoo.org> et al
# with logic taken from dlang.eclass by Marco Leise <marco.leise@gmx.de>.
# @BUGREPORTS:
# Please report bugs via https://github.com/gentoo/dlang/issues
# @VCSURL: https://github.com/gentoo/dlang
# @SUPPORTED_EAPIS: 8
# @PROVIDES: dlang-compilers-r1
# @BLURB: Utility functions for packages with Dlang parts.
# @DESCRIPTION:
# A utility eclass providing functions to query Dlang implementations
# and install Dlang libraries.
#
# This eclass does not set any metadata variables nor export any phase
# functions. It can be inherited safely.

case ${EAPI} in
	8) ;;
	*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
esac

if [[ ! ${_DLANG_UTILS_R1_ECLASS} ]]; then
_DLANG_UTILS_R1_ECLASS=1

inherit dlang-compilers-r1 multilib toolchain-funcs

# @ECLASS_VARIABLE: DMDFLAGS
# @USER_VARIABLE
# @DESCRIPTION:
# Flags that will be passed to dmd implementations during compilation.
#
# Example value:
# @CODE
# -O -release -mcpu=native
# @CODE

# @ECLASS_VARIABLE: GDCFLAGS
# @USER_VARIABLE
# @DESCRIPTION:
# Flags that will be passed to gdc implementations during compilation.
#
# Example value:
# @CODE
# -O2 -pipe -march=native -frelease
# @CODE

# @ECLASS_VARIABLE: LDCFLAGS
# @USER_VARIABLE
# @DESCRIPTION:
# Flags that will be passed to ldc2 implementations during compilation.
#
# Example value:
# @CODE
# -O2 -release -mcpu=native
# @CODE

# @FUNCTION: _dlang_set_impls
# @INTERNAL
# @DESCRIPTION:
# Set two global variables based on DLANG_COMPAT
#
# - _DLANG_SUPPORTED_IMPLS containing valid implementations supported
#   by the ebuild (DLANG_COMPAT - dead implementations),
#
# - and _DLANG_UNSUPPORTED_IMPLS containing valid implementations that
#   are not supported by the ebuild.
#
# Implementations in both variables are ordered using the pre-defined
# eclass implementation ordering.
#
# This function must be called once in global scope by an eclass
# utilizing DLANG_COMPAT.
_dlang_set_impls() {
	if ! declare -p DLANG_COMPAT &>/dev/null; then
		die 'DLANG_COMPAT not declared.'
	fi
	if [[ ${DLANG_COMPAT@a} != *a* ]]; then
		die 'DLANG_COMPAT must be an array'
	fi

	local supp=() unsupp=()

	local i
	for i in "${_DLANG_ALL_IMPLS[@]}"; do
		if has "${i}" "${DLANG_COMPAT[@]}"; then
			supp+=( "${i}" )
		else
			unsupp+=( "${i}" )
		fi
	done

	if [[ ! ${supp[@]} ]]; then
		die "No supported implementation in DLANG_COMPAT."
	fi

	if [[ ${_DLANG_SUPPORTED_IMPLS[@]} ]]; then
		# set once already, verify integrity
		if [[ ${_DLANG_SUPPORTED_IMPLS[@]} != ${supp[@]} ]]; then
			eerror "Supported impls (DLANG_COMPAT) changed between inherits!"
			eerror "Before: ${_DLANG_SUPPORTED_IMPLS[*]}"
			eerror "Now   : ${supp[*]}"
			die "_DLANG_SUPPORTED_IMPLS integrity check failed"
		fi
		if [[ ${_DLANG_UNSUPPORTED_IMPLS[@]} != ${unsupp[@]} ]]; then
			eerror "Unsupported impls changed between inherits!"
			eerror "Before: ${_DLANG_UNSUPPORTED_IMPLS[*]}"
			eerror "Now   : ${unsupp[*]}"
			die "_DLANG_UNSUPPORTED_IMPLS integrity check failed"
		fi
	else
		_DLANG_SUPPORTED_IMPLS=( "${supp[@]}" )
		_DLANG_UNSUPPORTED_IMPLS=( "${unsupp[@]}" )
		readonly _DLANG_SUPPORTED_IMPLS _DLANG_UNSUPPORTED_IMPLS
	fi
}

# @ECLASS_VARIABLE: DC
# @DEFAULT_UNSET
# @DESCRIPTION:
# The absolute path to the current Dlang compiler.
#
# Example values (each line is a possible value):
# @CODE
# /usr/lib/ldc2/1.36/bin/ldc2
# /usr/lib/dmd/2.106/bin/dmd
# /usr/x86_64-pc-linux-gnu/gcc-bin/12/gdc
# @CODE

# @ECLASS_VARIABLE: EDC
# @DEFAULT_UNSET
# @DESCRIPTION:
# The executable name of the current Dlang compiler.
#
# Please note that this names don't necessarily map to actual
# executables in $PATH so there's no guarantee that calling $EDC will
# work. Instead, use $DC or $(dlang_get_dmdw).
#
# Example values (each line is a possible value):
# @CODE
# dmd-2.106
# ldc2-1.32
# gdc-12
# @CODE

# @ECLASS_VARIABLE: DCFLAGS
# @DEFAULT_UNSET
# @DESCRIPTION:
# The flags the user provided for the current Dlang implementation.
#
# Example value:
# @CODE
# --O2 --release
# @CODE

# @ECLASS_VARIABLE: DLANG_LDFLAGS
# @DEFAULT_UNSET
# @DESCRIPTION:
# The contents of $LDFLAGS converted to something the current Dlang
# implementation can understand.
#
# Example value:
# @CODE
# -L--as-needed -L-O1
# @CODE

# @FUNCTION: dlang_get_dmdw
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the full path of the dmd wrapper for the current
# implementation. If no implementation is provided, ${EDC} will be
# used.
dlang_get_dmdw() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DMDW
	echo "${DMDW}"
}

# @FUNCTION: dlang_get_dmdw_dcflags
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the user flags for the compiler denoted by given
# implementation, in a form that can be passed to the dmd wrapper of the
# same compiler. If no implementation is provided, ${EDC} will be used.
dlang_get_dmdw_dcflags() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DMDW_DCFLAGS
	echo "${DMDW_DCFLAGS}"
}

# @FUNCTION: dlang_get_dmdw_ldflags
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the contents of $LDFLAGS, converted to what the dmd
# wrapper of the given implementation understands. If no implementation
# is provided, ${EDC} will be used.
dlang_get_dmdw_ldflags() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_DMDW_LDFLAGS
	echo "${DLANG_DMDW_LDFLAGS}"
}

# @FUNCTION: dlang_get_libdir
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the path to the library directory of the current
# implementation. If no implementation is provided, ${EDC} will be used.
#
# This function uses $ABI to calculate to result. For packages that
# support multiple abis care must be taken to set $ABI properly _before_
# calling this function.
dlang_get_libdir() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_LIBDIR
	echo "${DLANG_LIBDIR}"
}

# @FUNCTION: dlang_get_import_dir
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the path to the include directory shared across
# implementations. This value doesn't depend on <impl> as it is always:
# @CODE
# /usr/include/dlang
# @CODE
dlang_get_import_dir() {
	debug-print-function ${FUNCNAME} "${@}"

	echo "/usr/include/dlang"
}

# @FUNCTION: dlang_get_fe_version
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the frontend version of the given Dlang
# implementation. If no implementation is provided, ${EDC} will be used.
#
# Example:
# @CODE
# dlang_get_fe_version dmd-2.101 # echo 2.101
# dlang_get_fe_version ldc-1_35  # echo 2.105
# dlang_get_fe_version gdc-12    # echo 2.100
# @CODE
dlang_get_fe_version() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_FE_VERSION
	echo "${DLANG_FE_VERSION}"
}

# @FUNCTION: dlang_get_be_version
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the backend version of the given Dlang
# implementation. If no implementation is provided, ${EDC} will be used.
#
# Example:
# @CODE
# dlang_get_be_version dmd-2.101 # echo 2.101
# dlang_get_be_version ldc-1_35  # echo 1.35
# dlang_get_be_version gdc-12    # echo 12
# @CODE
dlang_get_be_version() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_BE_VERSION
	echo "${DLANG_BE_VERSION}"
}

# @FUNCTION: dlang_get_debug_flag
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the compiler debug flag for the given
# implementation. If no implementation is provided, ${EDC} will be
# used.
dlang_get_debug_flag() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_DEBUG_FLAG
	echo "${DLANG_DEBUG_FLAG}"
}

# @FUNCTION: dlang_get_linker_flag
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the compiler linker flag for the given
# implementation. If no implementation is provided, ${EDC} will be
# used.
dlang_get_linker_flag() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_LINKER_FLAG
	echo "${DLANG_LINKER_FLAG}"
}

# @FUNCTION: dlang_get_model_flag
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print a flag to be appended to $DCFLAGS to compile for the
# current ABI. If no implementation is provided, ${EDC} will be used.
#
# If not in a multilib profile nothing will be printed. If on amd64/x86
# multilib, which is the only one supported by the eclass, either -m64
# or -m32 is printed based on the value of $ABI.
#
# Since all implementations accept the -m* flag the value of <impl>
# doesn't matter.
dlang_get_model_flag() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_MODEL_FLAG
	echo "${DLANG_MODEL_FLAG}"
}

# @FUNCTION: dlang_get_output_flag
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the compiler output flag for the given
# implementation. If no implementation is provided, ${EDC} will be
# used.
dlang_get_output_flag() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_OUTPUT_FLAG
	echo "${DLANG_OUTPUT_FLAG}"
}

# @FUNCTION: dlang_get_unittest_flag
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the compiler unittest flag for the given
# implementation. If no implementation is provided, ${EDC} will be
# used.
dlang_get_unittest_flag() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_UNITTEST_FLAG
	echo "${DLANG_UNITTEST_FLAG}"
}

# @FUNCTION: dlang_get_version_flag
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the compiler version flag for the given
# implementation. If no implementation is provided, ${EDC} will be
# used.
dlang_get_version_flag() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_VERSION_FLAG
	echo "${DLANG_VERSION_FLAG}"
}

# @FUNCTION: dlang_get_wno_error_flag
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the compiler flag which turns warnings into messaged
# instead of errors for the given implementation. If no implementation
# is provided, ${EDC} will be used.
dlang_get_wno_error_flag() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_WNO_ERROR_FLAG
	echo "${DLANG_WNO_ERROR_FLAG}"
}

# @FUNCTION: dlang_print_system_import_paths
# @USAGE: [<impl>]
# @DESCRIPTION:
# Print a list of standard import paths, $EPREFIX included, for the
# current Dlang implementation. If no implementation is provided, ${EDC}
# will be used.
#
# The entries are each printed on a separate line. Entries include the
# paths to phobos, druntime and implementation specific directories, if
# any.
dlang_print_system_import_paths() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_SYSTEM_IMPORT_PATHS
	echo "${DLANG_SYSTEM_IMPORT_PATHS}"
}

# @VARIABLE: imports
# @DEFAULT_UNSET
# @DESCRIPTION:
# A space separated list of import paths that dlang_compile_* will add
# to the command line during compilation.
#
# Example usage:
# @CODE
# local imports="mydir/mylib subdir"
# dlang_compile_bin main main.d # dmd -ofmain main.d -Imydir/mylib -Isubdir
# @CODE

# @VARIABLE: string_imports
# @DEFAULT_UNSET
# @DESCRIPTION:
# A space separated list of string import paths that dlang_compile_*
# will add to the command line during compilation.
#
# Example usage:
# @CODE
# local string_imports="pix more/pix"
# dlang_compile_bin main main.d # dmd -ofmain main.d -Jpix -Jmore/pix
# @CODE

# @VARIABLE: versions
# @DEFAULT_UNSET
# @DESCRIPTION:
# A space separated list of versions that dlang_compile_* will enable
# during compilation.
#
# Example usage:
# @CODE
# local versions="foo bar"
# dlang_compile_bin main main.d # dmd -ofmain main.d -version=foo -version=bar
# @CODE

# @VARIABLE: libs
# @DEFAULT_UNSET
# @DESCRIPTION:
# A space separated list of libraries that dlang_compile_* will link with.
#
# Example usage:
# @CODE
# local libs="gtkd gtk"
# dlang_compile_bin main main.d # dmd -ofmain main.d -L-lgtkd -L-lgtk
# @CODE

# @FUNCTION: dlang_compile_lib.so
# @USAGE: <output> <soname> <args>...
# @DESCRIPTION:
# Compiles a D shared library. The first argument is the output file
# name, the second argument is the soname (typically file name without
# patch level suffix), the other arguments are source files or arguments
# for the compiler.
#
# Additional variables can be set to fine tune the compilation.
# Check $imports, $string_imports, $versions and $libs.
dlang_compile_lib.so() {
	debug-print-function ${FUNCNAME} "${@}"

	local libname="${1}"
	local soname="${2}"
	local sources="${@:3}"

	# See dlang_compile_bin comment about these variables.
	#local DC DCFLAGS DLANG_LDFLAGS
	local DLANG_MODEL_FLAG DLANG_LINKER_FLAG DLANG_OUTPUT_FLAG
	_dlang_export DLANG_MODEL_FLAG DLANG_LINKER_FLAG DLANG_OUTPUT_FLAG

	# Put these variables here instead of in _dlang_export to not
	# complicate it any further.
	local so_flags=$(_dlang_echo_implementation_string \
						 "${EDC}" \
						 "-shared -defaultlib=libphobos2.so -fPIC" \
						 "-shared -fpic" \
						 "-shared -relocation-model=pic")

	local cmd=(
		${DC} $(_dlang_compile_extra_flags)
		${DLANG_MODEL_FLAG}
		${so_flags}
		${DLANG_LINKER_FLAG}-soname=${soname}
		${DLANG_OUTPUT_FLAG}${libname}
		${sources}
		# Put the user flags last
		${DCFLAGS} ${DLANG_LDFLAGS}
	)

	dlang_exec "${cmd[@]}"
}

# @FUNCTION: dlang_compile_lib.a
# @USAGE: <output> <args>...
# @DESCRIPTION:
# Compiles a D static library. The first argument is the output file
# name, the other arguments are source files or arguments to the
# compiler.
#
# Additional variables can be set to fine tune the compilation.
# Check $imports, $string_imports, $versions and $libs.
dlang_compile_lib.a() {
	debug-print-function ${FUNCNAME} "${@}"

	local libname="${1}"
	local sources="${@:2}"

	# See dlang_compile_bin comment about these variables.
	#local DC DCFLAGS DLANG_LDFLAGS
	local DLANG_MODEL_FLAG DLANG_LINKER_FLAG DLANG_OUTPUT_FLAG
	_dlang_export DLANG_MODEL_FLAG DLANG_LINKER_FLAG DLANG_OUTPUT_FLAG

	if [[ ${EDC::3} == @(dmd|ldc) ]]; then
		# Put these variables here instead of in _dlang_export to not
		# complicate it any further.
		local a_flags=$(_dlang_echo_implementation_string \
							"${EDC}" \
							"-lib -fPIC" \
							"" \
							"-lib -relocation-model=pic")

		local cmd=(
			${DC} $(_dlang_compile_extra_flags)
			${DLANG_MODEL_FLAG}
			${a_flags}
			${DLANG_OUTPUT_FLAG}${libname}
			${sources}
			# Put the user flags last
			${DCFLAGS} ${DLANG_LDFLAGS}
		)

		dlang_exec "${cmd[@]}"
	else
		# 2 step, first compile, then ar
		local tmpFile=${libname}.dlang-eclass.o
		local cmd=(
			${DC} $(_dlang_compile_extra_flags)
			${DLANG_MODEL_FLAG}
			-c ${DLANG_OUTPUT_FLAG}${tmpFile}
			${sources}
			# Put the user flags last
			${DCFLAGS} ${DLANG_LDFLAGS}
		)
		dlang_exec "${cmd[@]}"

		cmd=( $(tc-getAR) ${ARFLAGS} rcs ${libname} ${tmpFile} )
		dlang_exec "${cmd[@]}"
	fi
}

# @FUNCTION: dlang_compile_bin
# @USAGE: <output> <args>...
# @DESCRIPTION:
# Compiles a D application. The first argument is the output file name,
# the other arguments are source files or compiler arguments.
#
# Additional variables can be set to fine tune the compilation.
# Check $imports, $string_imports, $versions and $libs.
dlang_compile_bin() {
	debug-print-function ${FUNCNAME} "${@}"
	local output=${1} sources=${@:2}

	# These should already be set by dlang-r1 or dlang-single
	#local DC DCFLAGS DLANG_LDFLAGS
	# We don't set them here to support dmd[selfhost] which
	# wants to overwrite some of these values.
	local DLANG_OUTPUT_FLAG
	_dlang_export DLANG_OUTPUT_FLAG

	local cmd=(
		${DC} $(_dlang_compile_extra_flags)
		${DLANG_OUTPUT_FLAG}${output}
		${sources}
		# Put the user flags last.
		${DCFLAGS} ${DLANG_LDFLAGS}
	)

	dlang_exec "${cmd[@]}"
}

# @FUNCTION: dlang_exec
# @USAGE: <cmd>...
# @DESCRIPTION:
# Execute the command passed as arguments, die on failure.
dlang_exec() {
	echo "${@}"
	${@} || die
}

# @FUNCTION: dlang_dolib.so
# @USAGE: <passthrough-args>...
# @DESCRIPTION:
# A dolib.so wrapper that will install the library to the library
# directory of the current Dlang implementation, denoted by ${EDC}.
#
# The `into' destination needs to be `/usr', if you changed it do:
# @CODE
# into /usr
# @CODE
# before running this function.
dlang_dolib.so() {
	debug-print-function ${FUNCNAME} "${@}"

	local DLANG_LIBDIR
	_dlang_export DLANG_LIBDIR

	local LIBDIR_${ABI}=${DLANG_LIBDIR}
	dolib.so "${@}"
}

# @FUNCTION: dlang_dolib.a
# @USAGE: <passthrough-args>...
# @DESCRIPTION:
# A dolib.a wrapper that will install the library to the library
# directory of the current Dlang implementation, denoted by ${EDC}.
#
# The `into' destination needs to be `/usr', if you changed it before do:
# @CODE
# into /usr
# @CODE
# before running this function.
dlang_dolib.a() {
	debug-print-function ${FUNCNAME} "${@}"

	local DLANG_LIBDIR
	_dlang_export DLANG_LIBDIR

	local LIBDIR_${ABI}=${DLANG_LIBDIR}
	dolib.a "${@}"
}

# @FUNCTION: dlang_get_dcflags
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the flags the user has set up for the given
# implementation. If no implementation is provided, ${EDC} will be used.
#
# See also: $DMDFLAGS, $GDCFLAGS, $LDCFLAGS
dlang_get_dcflags() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DCFLAGS
	echo "${DCFLAGS}"
}

# @FUNCTION: dlang_get_ldflags
# @USAGE: [<impl>]
# @DESCRIPTION:
# Obtain and print the contents of $LDFLAGS, converted to what the given
# implementation understands. If no implementation is provided, ${EDC}
# will be used.
dlang_get_ldflags() {
	debug-print-function ${FUNCNAME} "${@}"

	_dlang_export "${@}" DLANG_LDFLAGS
	echo "${DLANG_LDFLAGS}"
}

# @FUNCTION: dlang-filter-dflags
# @USAGE: <pattern> <flags>
# @DESCRIPTION:
# Remove particular <flags> from {DMD,GDC,LDC}FLAGS based on
# <pattern> and also from {DMDW_,}DCFLAGS if they are set.
# <flags> accept shell globs.
#
# For the syntax of <pattern> please see _dlang_impl_matches.
# Note that you will probably want to use globbing for the pattern
# and restrict to one of the three compilers, e.g. "dmd*", "gdc*".
#
# Example:
# @CODE
# DMDFLAGS="-a -b -c -d -e -ff"
# dlang-filter-dflags "dmd*" -e
# echo "${DMDFLAGS}" # "-a -b -c -d -ff"
# @CODE
#
# @CODE
# DCFLAGS="-a -b -c -d -e -ff"
# dlang-filter-dflags '*' '-?'
# echo "${DCFLAGS}" # "-ff"
# @CODE
#
# @CODE
# LDCFLAGS='-O -O1 -flag -O3'
# dlang-filter-dflags 'ldc*' '-O*'
# echo "${LDCFLAGS}" # "-flag"
# @CODE
dlang-filter-dflags() {
	local pattern="${1}"
	shift

	_dlang_verify_patterns "${pattern}"

	# One implementation from each compiler, the
	# version doesn't matter.
	local impl
	for impl in ldc2-1.32 dmd-2.102 gdc-12; do
		if _dlang_impl_matches "${impl}" "${pattern}"; then
			local flagVar="${impl::3}" # either dmd, gdc or ldc
			flagVar="${flagVar^^}FLAGS" # {DMD,GDC,LDC}FLAGS

			# Taken from _filter-var from flag-o-matic.eclass
			local x f new=()
			for f in ${!flagVar}; do
				for x; do
					[[ ${f} == ${x} ]] && continue 2
				done
				new+=( "${f}" )
			done

			export ${flagVar}="${new[*]}"
		fi
	done

	# If the flags are set, udpate them.
	for v in {DMDW_,}DCFLAGS; do
		[[ ${v} ]] && _dlang_export "${v}"
	done

	return 0
}

# @FUNCTION: dlang_get_abi_bits
# @USAGE: [<abi>]
# @DESCRIPTION:
# Echo the bits of the given abi. When unspecified take the value from
# $ABI.
#
# If the abi is x86, echo 32, if amd64 echo 64, otherwise do nothing.
dlang_get_abi_bits() {
	case "${1:-${ABI}}" in
		amd64*) echo 64 ;;
		x86*) echo 32 ;;
	esac
}

# @FUNCTION: _dlang_export
# @USAGE: [<impl>] <variables>...
# @INTERNAL
# @DESCRIPTION:
# Set and export the Dlang implementation-relevant variables passed
# as parameters.
#
# The optional first parameter may specify the requested Dlang
# implementation (either as DLANG_TARGETS value, e.g. dmd-2_106,
# ldc2-1_32, gdc-12, or an EDC one, e.g. dmd-2.106, ldc2-1.32, gdc-12).
# If no implementation has been passed, the current one will be obtained
# from ${EDC}.
#
# Some variables, like DLANG_LIBIDR and DLANG_MODEL_FLAG, are calculated
# based on $ABI. For this reason ebuilds that handle multiple abis
# should handle first the abis then the dlang portions. Shortly:
# @CODE
# multilib_foreach_abi dlang_foreach_impl some_function # good
# dlang_foreach_impl multilib_foreach_abi some_function # bad
# @CODE
#
# Note that there is one more form of <impl> that is accepted. It may be
# in the form "dmd-wrap-<actual_impl>" where <actual_impl> is in the
# form described above. This is only used internally to keep LDFLAGS
# logic in the same place. Be aware of this but don't use it unless
# necessary or it will become hard to keep track of stuff very fast.
_dlang_export() {
	debug-print-function ${FUNCNAME} "${@}"

	local impl
	case "${1}" in
		dmd-*|ldc2-*|gdc-*)
			impl=${1/_/.}
			shift
			;;
		*)
			impl=${EDC}
			if [[ -z ${impl} ]]; then
				die "_dlang_export called without a dlang implementation and EDC is unset"
			fi
			;;
	esac
	debug-print "${FUNCNAME}: implementation: ${impl}"

	local var
	for var; do
		case "${var}" in
			EDC)
				export EDC=${impl}
				debug-print "${FUNCNAME}: EDC = ${EDC}"
				;;
			DC)
				export DC=$(
					_dlang_echo_implementation_string \
						"${impl}" \
						"${EPREFIX}/usr/lib/dmd/${impl#dmd-}/bin/dmd" \
						"${EPREFIX}/usr/${CHOST_default}/gcc-bin/${impl#gdc-}/gdc" \
						"${EPREFIX}/usr/lib/ldc2/${impl#ldc2-}/bin/ldc2"
					   )
				# We could have the path, in the case of gdc, be ${CHOST}-gdc but
				# that breaks checks like `if(basename(DC) == gdc)` which seem to
				# be quite common. For this reason keep the basename gdc.
				debug-print "${FUNCNAME}: DC = ${DC}"
				;;
			DMDW)
				export DMDW=$(
					_dlang_echo_implementation_string \
						"${impl}" \
						"${EPREFIX}/usr/lib/dmd/${impl#dmd-}/bin/dmd" \
						"${EPREFIX}/usr/${CHOST_default}/gcc-bin/${impl#gdc-}/gdmd" \
						"${EPREFIX}/usr/lib/ldc2/${impl#ldc2-}/bin/ldmd2"
					   )
				# Same observation about ${CHOST}-gdmd as above.
				debug-print "${FUNCNAME}: DMDW = ${DMDW}"
				;;
			DLANG_LIBDIR)
				# There are two supported use cases for dlang packages:
				# no-multilib profile and amd64/x86 multilib.
				pick_nomulti_amd64_x86() {
					if ! has_multilib_profile; then
						echo "${1}"
					else
						case "${ABI}" in
							amd64*) echo "${2}" ;;
							x86*) echo "${3}" ;;
							*)
								eerror "ABI ${ABI} is not supported in a multilib configuration."
								die "Multilib abi is not x86/amd64!"
						esac
					fi
				}

				local libdirname
				case "${impl::3}" in
					ldc)
						# Old dlang.eclass always picked lib<bits> which
						# isn't always correct. The proper calculation
						# is found in runtime/CMakeLists.txt which is:
						# - native abi is always put in lib<LIB_SUFFIX>
						#   which is set by cmake.eclass to $(get_libdir)
						# - x86 on amd64 is put in lib<bits>
						libdirname=$(pick_nomulti_amd64_x86 \
										 "$(get_libdir)" "$(get_libdir)" "lib32")
						;;
					gdc)
						# I have no idea how gcc does it but the line
						# below gives the correct result, probably.
						libdirname=$(pick_nomulti_amd64_x86 "" "" "/32")
						;;
					dmd)
						# Wonderful old dmd. It only supports x86 and
						# amd64 so we only have to consider these two
						# arches, either independently or multilib.
						#
						# The logic is controlled by us so the calculation
						# is found in dlang.eclass. Just copy it here, mostly.
						# Simplify the ABI usage a little.
						[[ ${ABI} == @(x86|amd64) ]] ||
							die "Unknown ABI ${ABI} for dmd implementation."
						local model=$(dlang_get_abi_bits)

						if has_multilib_profile || [[ ${model} == 64 ]]; then
							libdirname=lib${model}
						else
							libdirname=lib
						fi
						;;
				esac

				export DLANG_LIBDIR=$(
					_dlang_echo_implementation_string \
						"${impl}" \
						"lib/dmd/${impl#dmd-}/" \
						"lib/gcc/${CHOST_default}/${impl#gdc-}" \
						"lib/ldc2/${impl#ldc2-}/"
					   )${libdirname}
				debug-print "${FUNCNAME}: DLANG_LIBDIR = ${DLANG_LIBDIR}"
				;;
			DLANG_IMPORT_DIR)
				# This is the only variable which is treated
				# differently. Since it doesn't depend on <impl> we want
				# to allow setting its value even if $EDC is unset.
				export DLANG_IMPORT_DIR="$(dlang_get_import_dir)"
				debug-print "${FUNCNAME}: DLANG_IMPORT_DIR = ${DLANG_IMPORT_DIR}"
				;;
			DLANG_MODEL_FLAG)
				if has_multilib_profile; then
					# Only x86/amd64 multilib is supported
					[[ ${ABI} == @(x86|amd64) ]] ||
						die "ABI ${ABI} is not supported in a multilib configuration."
					DLANG_MODEL_FLAG=-m$(dlang_get_abi_bits)
				else
					DLANG_MODEL_FLAG=
				fi
				export DLANG_MODEL_FLAG
				debug-print "${FUNCNAME}: DLANG_MODEL_FLAG = ${DLANG_MODEL_FLAG}"
				;;
			DCFLAGS)
				# Old dlang.eclass added -op (do not strip paths from
				# source files) to LDCFLAGS. This doesn't seem like
				# something that should be toggled unconditionally so it
				# is not added here.
				#
				# Changes in the behavior of packages with this flag
				# enabled I've observed in dev-lang/ldc2 where a regex
				# match gets messed up though there don't seem to be any
				# relevant consequences (observe the `Host D compiler
				# linker args' config line).
				#
				# The old eclass added -shared-libphobos to
				# GDCFLAGS. This is quite important but, since it a flag
				# that affects linking, it has been moved to DLANG_LDFLAGS.
				export DCFLAGS=$(
					_dlang_echo_implementation_string \
						"${impl}" "${DMDFLAGS}" "${GDCFLAGS}" "${LDCFLAGS}")
				debug-print "${FUNCNAME}: DCFLAGS = ${DCFLAGS}"
				;;
			DMDW_DCFLAGS)
				# Don't copy the logic from above, just re-call.
				local DCFLAGS
				_dlang_export "${impl}" DCFLAGS
				case "${impl}" in
					# dmd understands his own flags and ldmd2 passes
					# through unknown flags to ldc2.
					dmd*|ldc*) DMDW_DCFLAGS="${DCFLAGS}" ;;
					gdc*)
						local flags=( ${DCFLAGS} )
						if [[ ${flags[*]} == *,* ]]; then
						eerror "gdc-style flags can not be converted to gdmd-style"
						eerror "because they contain a comma: ${flags[*]}"

						die 'flags contain a nonconvertible comma.'
					fi
					# `-arg1' `-arg2' => `-q,-arg1' `-q,-arg2'
					DMDW_DCFLAGS="${flags[@]/#/-q,}"
					;;
				esac
				export DMDW_DCFLAGS
				debug-print "${FUNCNAME}: DMDW_DCFLAGS = ${DMDW_DCFLAGS}"
				;;
			DLANG_LDFLAGS)
				# In case some $LDFLAGS fail with some Dlang
				# implementations this is where they should be
				# stripped. Out of the old eclass:
				#
				# --gc-sections, fails until dmd-2.072
				#
				# --icf= still has an open bug but I can't reproduce it
				# so I won't remove it. I've tested building dub with
				# -L--icf=safe with both ld.gold and ld.lld, static and
				# dynamic phobos. The old eclass only removed it for dmd.
				# See: https://issues.dlang.org/show_bug.cgi?id=17515
				#
				# Very important, add -shared-libphobos for gdc. It
				# _will_ be linked statically otherwise.
				case "${impl::3}" in
					dmd|ldc)
						# Old dlang.eclass picked -L for dmd and -L= for
						# ldc2. Meson doesn't like -L= however so we go
						# with -L for both. See:
						# 391ce890a1ca37cce3ee643f61c63c06f428d0dc
						local prefix=-L

						# Convert -Wl arguments
						local flags=() flag
						for flag in ${LDFLAGS}; do
							if [[ ${flag::4} == -Wl, ]]; then
								# -Wl,a,b,c -> -La -Lb -Lc
								flag="${prefix}${flag#-Wl,}" # flag="-La,b,c"
								flag="${flag//,/ ${prefix}}" # flag="-La -Lb -Lc"
							fi
							flags+=( "${flag}" )
						done
						DLANG_LDFLAGS="${flags[*]}"

						# Then convert -Xlinker

						# This substitution can fail if there is more
						# than one space. It's better than the old eclass which
						# didn't do it at all (though it tried to).
						DLANG_LDFLAGS="${DLANG_LDFLAGS//-Xlinker /${prefix}}"
						;;
					gdc)
						DLANG_LDFLAGS="${LDFLAGS} -shared-libphobos"
						;;
				esac
				export DLANG_LDFLAGS
				debug-print "${FUNCNAME}: DLANG_LDFLAGS = ${DLANG_LDFLAGS}"
				;;
			DLANG_DMDW_LDFLAGS)
				# It would be very easy if we could go like in
				# DMDW_DCFLAGS and just insert some -q, for gdc. The
				# problem is $LDFLAGS typically contain commas (-Wl,-O1)
				# so that solution is busted.  Because of this we have
				# to do an actual conversions.
				#
				# But a dmd wrapper is close enough to a dmd
				# implementation so the logic from DLANG_LDFLAGS should
				# suffice, in this case at least.
				local DLANG_LDFLAGS
				case "${impl::3}" in
					dmd|ldc) _dlang_export "${impl}" DLANG_LDFLAGS ;;
					gdc)
						_dlang_export "dmd-wrap-${impl}" DLANG_LDFLAGS
						# Do not forget the very important flag
						DLANG_LDFLAGS+=" -q,-shared-libphobos"
						;;
				esac
				export DLANG_DMDW_LDFLAGS=${DLANG_LDFLAGS}
				debug-print "${FUNCNAME}: DLANG_DMDW_LDFLAGS = ${DLANG_DMDW_LDFLAGS}"
				;;
			DLANG_DEBUG_FLAG)
				export DLANG_DEBUG_FLAG=$(
					_dlang_echo_implementation_string \
						"${impl}" "-debug" "-fdebug" "-d-debug")
				debug-print "${FUNCNAME}: DLANG_DEBUG_FLAG = ${DLANG_DEBUG_FLAG}"
				;;
			DLANG_LINKER_FLAG)
				export DLANG_LINKER_FLAG=$(
					_dlang_echo_implementation_string \
						"${impl}" "-L" "-Wl," "-L")
				debug-print "${FUNCNAME}: DLANG_LINKER_FLAG = ${DLANG_LINKER_FLAG}"
				;;
			DLANG_OUTPUT_FLAG)
				export DLANG_OUTPUT_FLAG=$(
					_dlang_echo_implementation_string \
						"${impl}" "-of" "-o" "-of=")
				debug-print "${FUNCNAME}: DLANG_OUTPUT_FLAG = ${DLANG_OUTPUT_FLAG}"
				;;
			DLANG_UNITTEST_FLAG)
				export DLANG_UNITTEST_FLAG=$(
					_dlang_echo_implementation_string \
						"${impl}" "-unittest" "-funittest" "-unittest")
				debug-print "${FUNCNAME}: DLANG_UNITTEST_FLAG = ${DLANG_UNITTEST_FLAG}"
				;;
			DLANG_VERSION_FLAG)
				export DLANG_VERSION_FLAG=$(
					_dlang_echo_implementation_string \
						"${impl}" "-version" "-fversion" "-d-version")
				debug-print "${FUNCNAME}: DLANG_VERSION_FLAG = ${DLANG_VERSION_FLAG}"
				;;
			DLANG_FE_VERSION)
				local implDetails=( $(_dlang_get_impl_details "${impl}") )
				export DLANG_FE_VERSION=${implDetails[1]}
				debug-print "${FUNCNAME}: DLANG_FE_VERSION = ${DLANG_FE_VERSION}"
				;;
			DLANG_BE_VERSION)
				export DLANG_BE_VERSION=${impl#*-}
				debug-print "${FUNCNAME}: DLANG_BE_VERSION = ${DLANG_BE_VERSION}"
				;;
			DLANG_WNO_ERROR_FLAG)
				export DLANG_WNO_ERROR_FLAG=$(
					_dlang_echo_implementation_string \
						"${impl}" "-wi" "-Wno-error" "--wi")
				debug-print "${FUNCNAME}: DLANG_WNO_ERROR_FLAG = ${DLANG_WNO_ERROR_FLAG}"
				;;
			DLANG_SYSTEM_IMPORT_PATHS)
				# Basically copy the output of each compiler when they
				# can't find a module.
				#
				# Right now there's only 1 path for each implementation
				# but if there were more they need to be separated by
				# \n.
				#
				# Old dlang.eclass added include/d/ldc for ldc2 but that
				# doesn't make much sense as the compiler can't import
				# the modules in that folder by default. Since the only
				# consumer of this variable is dcd which is used for
				# autocompletion it's better to go with the rationale
				# above, i.e. whatever the compiler finds by default.
				export DLANG_SYSTEM_IMPORT_PATHS=$(
					_dlang_echo_implementation_string \
						"${impl}" \
						"${EPREFIX}/usr/lib/dmd/${impl#dmd-}/import" \
						"${EPREFIX}/usr/lib/gcc/${CHOST_default}/${impl#gdc-}/include/d" \
						"${EPREFIX}/usr/lib/ldc2/${impl#ldc2-}/include/d"
					   )

				debug-print "${FUNCNAME}: DLANG_SYSTEM_IMPORT_PATHS = ${DLANG_SYSTEM_IMPORT_PATHS}"
				;;
			DLANG_PKG_DEP)
				_dlang_check_DLANG_REQ_USE
				local usedep=${DLANG_REQ_USE[${impl%-*}]}
				if [[ ${usedep} ]]; then
					usedep=$(
						_dlang_echo_implementation_string \
							"${impl}" "[${usedep}]" "[d,${usedep}]" "[${usedep}]")
				else
					usedep=$(
						_dlang_echo_implementation_string \
							"${impl}" "" "[d]" "")
				fi

				# The eclass guarantees both a Dlang compiler and a dmd
				# wrapper of said compiler. ldmd2 comes with
				# dev-lang/ldc2 but gdmd has to be installed separately.
				#
				# dmd and ldc2 should have ABI compatible patch releases
				# but we will use :slot= just in case.
				export DLANG_PKG_DEP=$(
					_dlang_echo_implementation_string \
						"${impl}" \
						"dev-lang/dmd:${impl#dmd-}=${usedep}" \
						"sys-devel/gcc:${impl#gdc-}${usedep} dev-util/gdmd:${impl#gdc-}" \
						"dev-lang/ldc2:${impl#ldc2-}=${usedep}"
					)
				debug-print "${FUNCNAME}: DLANG_PKG_DEP = ${DLANG_PKG_DEP}"
				;;
			*)
				die "_dlang_export: unknown variable ${var}"
		esac
	done
}

# @FUNCTION: _dlang_wrapper_setup
# @USAGE: [<path> [<impl>]]
# @INTERNAL
# @DESCRIPTION:
# Create proper dlang executable setup and pkg-config wrapper (if
# available) in the directory named by <path>. Set up PATH and
# PKG_CONFIG_PATH appropriately. <path> defaults to ${T}/${EDC}.
#
# The wrappers will be created for implementation named by <impl>, or
# for one named by ${EDC} if no <impl> is passed.
#
# If the named directory contains a mark file, it will be assumed to
# contain proper wrappers already and only environment setup will be
# done. If wrapper update is requested, the directory shall be removed
# first.
#
# It is important to note that this function uses $DLANG_LIBDIR which
# uses $ABI to be calculated. Make sure that $ABI is set properly
# _before_ this function is called otherwise wrong variables will be
# generated.
_dlang_wrapper_setup() {
	debug-print-function ${FUNCNAME} "${@}"

	local workdir=${1:-${T}/${EDC}}
	local impl=${2:-${EDC}}

	[[ ${workdir} ]] || die "${FUNCNAME}: no workdir specified."
	[[ ${impl} ]] || die "${FUNCNAME}: no impl nor EDC specified."

	local compiler=${impl%-*}

	if [[ ! -x ${workdir}/.dlang_marked ]]; then
		mkdir -p "${workdir}" || die
		touch "${workdir}"/.dlang_marked || die

		mkdir -p "${workdir}"/bin || die

		# Clean up, in case we were supposed to do a cheap update. We
		# have to remove any previous compilers, so no use but to glob.
		# We can be more specific, by doing dmd*, ldc2*, gdc* but that's
		# too many lines.
		rm -f "${workdir}"/bin/* || die
		rm -f "${workdir}"/pkgconfig || die

		local EDC DC DLANG_LIBDIR
		_dlang_export "${impl}" EDC DC DLANG_LIBDIR

		# Dlang compiler
		ln -s "${DC}" "${workdir}/bin/${compiler}" || die
		# pkg-config, this may create a broken symlink
		ln -s "${EPREFIX}/usr/${DLANG_LIBDIR}/pkgconfig" "${workdir}"/pkgconfig || die

		# dmd and ldc2 use $CC to link so specify it.
		tc-export CC
		# With dmd $CC is split by spaces, with ldc it is not. See:
		# https://github.com/ldc-developers/ldc/pull/4582. We can solve
		# this by:
		if [[ ${CC} == *' '* ]]; then
			# Only make a script if $CC differs from itself when it is
			# expanded.
			cat > "${workdir}/bin/${CC}" <<EOF
#!/bin/sh
exec ${CC} "\${@}"
EOF
			chmod +x "${workdir}/bin/${CC}"
			# which creates a script that properly expands $CC that will
			# be called when ldc2 tries to link stuff. This is better
			# than the old eclass which disregarded this value.
		fi
	fi

	# Now, set the environment.
	# But note that ${workdir} may be shared with something else,
	# and thus already on top of PATH.
	if [[ ${PATH##:*} != ${workdir}/bin ]]; then
		PATH=${workdir}/bin${PATH:+:${PATH}}
	fi
	if [[ ${PKG_CONFIG_PATH##:*} != ${workdir/pkgconfig} ]]; then
		PKG_CONFIG_PATH=${workdir}/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}
	fi

	export PATH PKG_CONFIG_PATH
}

# @FUNCTION: _dlang_compile_extra_flags
# @INTERNAL
# @DESCRIPTION:
# Generate and echo implementation dependent compiler arguments for:
#
# - import directories, specified by $imports
#
# - string import directories, specified by $string_imports
#
# - version to enable, specified by $versions
#
# - libraries to link, specified by $libs
#
# The implementation is taken from ${EDC}.
_dlang_compile_extra_flags() {
	debug-print-function ${FUNCNAME} "${@}"

	local imports=( ${imports} )
	local simports=( ${string_imports} )
	local versions=( ${versions} )
	local libs=( ${libs} )

	debug-print "${FUNCNAME}: imports: ${imports[*]}"
	debug-print "${FUNCNAME}: simports: ${simports[*]}"
	debug-print "${FUNCNAME}: versions: ${versions[*]}"
	debug-print "${FUNCNAME}: libs: ${libs[*]}"

	local DLANG_VERSION_FLAG DLANG_LINKER_FLAG
	_dlang_export DLANG_VERSION_FLAG DLANG_LINKER_FLAG

	# Just like old dlang.eclass, though maybe ldc2 can use -I and -J
	local import_prefix simport_prefix
	case "${EDC::3}" in
		dmd|gdc)
			import_prefix=-I
			simport_prefix=-J
			;;
		ldc)
			import_prefix=-I=
			simport_prefix=-J=
			;;
	esac

	echo \
		"${imports[@]/#/${import_prefix}}" \
		"${simports[@]/#/${simport_prefix}}" \
		"${versions[@]/#/${DLANG_VERSION_FLAG}=}" \
		"${libs[@]/#/${DLANG_LINKER_FLAG}-l}"
}

# @FUNCTION: _dlang_echo_implementation_string
# @USAGE: <impl> <if-dmd> <if-gdc> <if-ldc2>
# @INTERNAL
# @DESCRIPTION:
# Based on an implementation, echo one of the parameters.
_dlang_echo_implementation_string() {
	debug-print-function ${FUNCNAME} "${@}"

	case "${1::3}" in
		dmd) echo "${2}" ;;
		gdc) echo "${3}" ;;
		ldc) echo "${4}" ;;
		*) die "Unknown implementation: ${1}." ;;
	esac
}

# @FUNCTION: _dlang_check_DLANG_REQ_USE
# @INTERNAL
# @DESCRIPTION:
# Check the $DLANG_REQ_USE variable and make sure it's in the correct
# format.
#
# More precisely, check that it's an associative array and that it only
# contains the keys: "dmd", "gdc", or "ldc2".
_dlang_check_DLANG_REQ_USE() {
	debug-print-function ${FUNCNAME} "${@}"

	! declare -p DLANG_REQ_USE &>/dev/null && return
	[[ ${DLANG_REQ_USE@a} != *A* ]] && die "DLANG_REQ_USE must be an associative array!"

	local key
	for key in "${!DLANG_REQ_USE[@]}"; do
		case "${key}" in
			dmd|gdc|ldc2) ;;
			ldc) die "Unknown key ${key} in DLANG_REQ_USE, perhaps you meant ldc2?" ;;
			*) die "Unknown key ${key} in DLANG_REQ_USE!" ;;
		esac
	done
}

# @FUNCTION: _dlang_impl_matches
# @USAGE: <impl> [<pattern>...]
# @INTERNAL
# @DESCRIPTION:
# Check whether the specified <impl> matches at least one of the
# patterns following it. Return 0 if it does, 1 otherwise. Matches
# if no patterns are provided.
#
# <impl> can be in DLANG_COMPAT or EDC form. The patterns can
# either be fnmatch-style or frontend versions, e.g "2.100".
_dlang_impl_matches() {
	[[ ${#} -ge 1 ]] || die "${FUNCNAME}: takes at least 1 parameter"
	[[ ${#} -eq 1 ]] && return 0

	local impl=${1/./_} pattern
	shift

	for pattern; do
		case ${pattern} in
			2.[0-9][0-9][0-9])
				local DLANG_FE_VERSION
				_dlang_export "${impl}" DLANG_FE_VERSION
				[[ ${pattern} == ${DLANG_FE_VERSION} ]] && return 0
				;;
			*)
				# unify value style to allow lax matching
				[[ ${impl} == ${pattern/./_} ]] && return 0
				;;
		esac
	done

	return 1

}

# @FUNCTION: _dlang_verify_patterns
# @USAGE: <pattern>...
# @INTERNAL
# @DESCRIPTION:
# Verify whether the patterns passed to the eclass function are correct
# (i.e. can match any valid implementation).  Dies on wrong pattern.
_dlang_verify_patterns() {
	debug-print-function ${FUNCNAME} "${@}"

	local impl pattern
	for pattern; do
		case ${pattern} in
			# Only check for versions as they appear in
			# _DLANG_*_FRONTENDS, not in _DLANG_HISTORICAL_IMPLS.
			2.10[01234567])
				continue
				;;
		esac

		for impl in "${_DLANG_ALL_IMPLS[@]}" "${_DLANG_HISTORICAL_IMPLS[@]}"
		do
			[[ ${impl} == ${pattern/./_} ]] && continue 2
		done

		die "Invalid implementation pattern: ${pattern}"
	done
}

fi