Skip to content

Commit c58bbd1

Browse files
committed
[OffloadBundler] Rework the ctor of OffloadTargetInfo to support generic target
The current parsing of target string assumes to be in a form of `kind-triple-targetid:feature`, such as `hipv4-amdgcn-amd-amdhsa-gfx1030:+xnack`. Specifically, the target id does not contain any `-`, which is not the case for generic target. Also, a generic target may contain one or more `-`, such as `gfx10-3-generic` and `gfx12-generic`. As a result, we can no longer depend on `rstrip` to get things work right. This patch reworks the logic to parse the target string to make it more robust, as well as supporting generic target.
1 parent 0d352b2 commit c58bbd1

7 files changed

+57
-61
lines changed

clang/docs/ClangOffloadBundler.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,15 +266,14 @@ without differentiation based on offload kind.
266266
The target triple of the code object. See `Target Triple
267267
<https://clang.llvm.org/docs/CrossCompilation.html#target-triple>`_.
268268

269-
The bundler accepts target triples with or without the optional environment
270-
field:
269+
LLVM target triples can be with or without the optional environment field:
271270

272271
``<arch><sub>-<vendor>-<sys>``, or
273272
``<arch><sub>-<vendor>-<sys>-<env>``
274273

275274
However, in order to standardize outputs for tools that consume bitcode
276-
bundles, bundles written by the bundler internally use only the 4-field
277-
target triple:
275+
bundles, the bundler only accepts target triples with the 4-field target
276+
triple:
278277

279278
``<arch><sub>-<vendor>-<sys>-<env>``
280279

clang/lib/Driver/OffloadBundler.cpp

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -84,31 +84,19 @@ OffloadTargetInfo::OffloadTargetInfo(const StringRef Target,
8484
: BundlerConfig(BC) {
8585

8686
// TODO: Add error checking from ClangOffloadBundler.cpp
87-
auto TargetFeatures = Target.split(':');
88-
auto TripleOrGPU = TargetFeatures.first.rsplit('-');
89-
90-
if (clang::StringToOffloadArch(TripleOrGPU.second) !=
91-
clang::OffloadArch::UNKNOWN) {
92-
auto KindTriple = TripleOrGPU.first.split('-');
93-
this->OffloadKind = KindTriple.first;
94-
95-
// Enforce optional env field to standardize bundles
96-
llvm::Triple t = llvm::Triple(KindTriple.second);
97-
this->Triple = llvm::Triple(t.getArchName(), t.getVendorName(),
98-
t.getOSName(), t.getEnvironmentName());
99-
100-
this->TargetID = Target.substr(Target.find(TripleOrGPU.second));
101-
} else {
102-
auto KindTriple = TargetFeatures.first.split('-');
103-
this->OffloadKind = KindTriple.first;
104-
105-
// Enforce optional env field to standardize bundles
106-
llvm::Triple t = llvm::Triple(KindTriple.second);
107-
this->Triple = llvm::Triple(t.getArchName(), t.getVendorName(),
108-
t.getOSName(), t.getEnvironmentName());
109-
110-
this->TargetID = "";
111-
}
87+
// <kind>-<triple>[-<target id>]
88+
// <triple> := <arch>-<vendor>-<os>-<env>
89+
SmallVector<StringRef, 6> Components;
90+
Target.split(':').first.split(Components, '-', /*MaxSplit=*/5);
91+
assert((Components.size() == 5 || Components.size() == 6) &&
92+
"malformed target string");
93+
94+
this->OffloadKind = Components.front();
95+
this->TargetID = Components.size() == 6 ? Components.back() : "";
96+
ArrayRef<StringRef> TripleSlice{&Components[1], /*length=*/4};
97+
llvm::Triple T = llvm::Triple(llvm::join(TripleSlice, "-"));
98+
this->Triple = llvm::Triple(T.getArchName(), T.getVendorName(), T.getOSName(),
99+
T.getEnvironmentName());
112100
}
113101

114102
bool OffloadTargetInfo::hasHostKind() const {
@@ -148,7 +136,7 @@ bool OffloadTargetInfo::operator==(const OffloadTargetInfo &Target) const {
148136
}
149137

150138
std::string OffloadTargetInfo::str() const {
151-
return Twine(OffloadKind + "-" + Triple.str() + "-" + TargetID).str();
139+
return Twine(OffloadKind + "-" + Triple.normalize() + "-" + TargetID).str();
152140
}
153141

154142
static StringRef getDeviceFileExtension(StringRef Device,

clang/test/Driver/clang-offload-bundler-asserts-on.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@
1515
// Check code object compatibility for archive unbundling
1616
//
1717
// Create few code object bundles and archive them to create an input archive
18-
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-amdgcn-amd-amdhsa-gfx906,openmp-amdgcn-amd-amdhsa--gfx908 -input=%t.o -input=%t.tgt1 -input=%t.tgt2 -output=%t.simple.bundle
18+
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-amdgcn-amd-amdhsa--gfx906,openmp-amdgcn-amd-amdhsa--gfx908 -input=%t.o -input=%t.tgt1 -input=%t.tgt2 -output=%t.simple.bundle
1919
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-amdgcn-amd-amdhsa--gfx906:sramecc+:xnack+,openmp-amdgcn-amd-amdhsa--gfx908:sramecc+:xnack+ -inputs=%t.o,%t.tgt1,%t.tgt1 -outputs=%t.targetID1.bundle
2020
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-amdgcn-amd-amdhsa--gfx906:sramecc+:xnack-,openmp-amdgcn-amd-amdhsa--gfx908:sramecc+:xnack- -inputs=%t.o,%t.tgt1,%t.tgt1 -outputs=%t.targetID2.bundle
2121
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-amdgcn-amd-amdhsa--gfx906:xnack-,openmp-amdgcn-amd-amdhsa--gfx908:xnack- -inputs=%t.o,%t.tgt1,%t.tgt1 -outputs=%t.targetID3.bundle
2222
// RUN: llvm-ar cr %t.input-archive.a %t.simple.bundle %t.targetID1.bundle %t.targetID2.bundle %t.targetID3.bundle
2323

2424
// Tests to check compatibility between Bundle Entry ID formats i.e. between presence/absence of extra hyphen in case of missing environment field
25-
// RUN: clang-offload-bundler -unbundle -type=a -targets=openmp-amdgcn-amd-amdhsa--gfx906,openmp-amdgcn-amd-amdhsa-gfx908 -input=%t.input-archive.a -output=%t-archive-gfx906-simple.a -output=%t-archive-gfx908-simple.a -debug-only=CodeObjectCompatibility 2>&1 | FileCheck %s -check-prefix=BUNDLECOMPATIBILITY
26-
// BUNDLECOMPATIBILITY: Compatible: Exact match: [CodeObject: openmp-amdgcn-amd-amdhsa--gfx906] : [Target: openmp-amdgcn-amd-amdhsa--gfx906]
27-
// BUNDLECOMPATIBILITY: Compatible: Exact match: [CodeObject: openmp-amdgcn-amd-amdhsa--gfx908] : [Target: openmp-amdgcn-amd-amdhsa--gfx908]
25+
// RUN: clang-offload-bundler -unbundle -type=a -targets=openmp-amdgcn-amd-amdhsa--gfx906,openmp-amdgcn-amd-amdhsa--gfx908 -input=%t.input-archive.a -output=%t-archive-gfx906-simple.a -output=%t-archive-gfx908-simple.a -debug-only=CodeObjectCompatibility 2>&1 | FileCheck %s -check-prefix=BUNDLECOMPATIBILITY
26+
// BUNDLECOMPATIBILITY: Compatible: Exact match: [CodeObject: openmp-amdgcn-amd-amdhsa-unknown-gfx906] : [Target: openmp-amdgcn-amd-amdhsa-unknown-gfx906]
27+
// BUNDLECOMPATIBILITY: Compatible: Exact match: [CodeObject: openmp-amdgcn-amd-amdhsa-unknown-gfx908] : [Target: openmp-amdgcn-amd-amdhsa-unknown-gfx908]
2828

29-
// RUN: clang-offload-bundler -unbundle -type=a -targets=hip-amdgcn-amd-amdhsa--gfx906,hipv4-amdgcn-amd-amdhsa-gfx908 -input=%t.input-archive.a -output=%t-hip-archive-gfx906-simple.a -output=%t-hipv4-archive-gfx908-simple.a -hip-openmp-compatible -debug-only=CodeObjectCompatibility 2>&1 | FileCheck %s -check-prefix=HIPOpenMPCOMPATIBILITY
30-
// HIPOpenMPCOMPATIBILITY: Compatible: Target IDs are compatible [CodeObject: openmp-amdgcn-amd-amdhsa--gfx906] : [Target: hip-amdgcn-amd-amdhsa--gfx906]
31-
// HIPOpenMPCOMPATIBILITY: Compatible: Target IDs are compatible [CodeObject: openmp-amdgcn-amd-amdhsa--gfx908] : [Target: hipv4-amdgcn-amd-amdhsa--gfx908]
29+
// RUN: clang-offload-bundler -unbundle -type=a -targets=hip-amdgcn-amd-amdhsa--gfx906,hipv4-amdgcn-amd-amdhsa--gfx908 -input=%t.input-archive.a -output=%t-hip-archive-gfx906-simple.a -output=%t-hipv4-archive-gfx908-simple.a -hip-openmp-compatible -debug-only=CodeObjectCompatibility 2>&1 | FileCheck %s -check-prefix=HIPOpenMPCOMPATIBILITY
30+
// HIPOpenMPCOMPATIBILITY: Compatible: Target IDs are compatible [CodeObject: openmp-amdgcn-amd-amdhsa-unknown-gfx906] : [Target: hip-amdgcn-amd-amdhsa-unknown-gfx906]
31+
// HIPOpenMPCOMPATIBILITY: Compatible: Target IDs are compatible [CodeObject: openmp-amdgcn-amd-amdhsa-unknown-gfx908] : [Target: hipv4-amdgcn-amd-amdhsa-unknown-gfx908]
3232

3333
// Some code so that we can create a binary out of this file.
3434
int A = 0;

clang/test/Driver/clang-offload-bundler-standardize.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,18 @@
1616
// Check code object compatibility for archive unbundling
1717
//
1818
// Create an object bundle with and without env fields
19-
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,hip-amdgcn-amd-amdhsa-gfx906,hip-amdgcn-amd-amdhsa-gfx908 -input=%t.o -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.no.env
20-
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple-,hip-amdgcn-amd-amdhsa--gfx906,hip-amdgcn-amd-amdhsa--gfx908 -input=%t.o -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.env
19+
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,hip-amdgcn-amd-amdhsa--gfx906,hip-amdgcn-amd-amdhsa--gfx908 -input=%t.o -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.no.env
2120

2221

2322
// Unbundle bundle.no.env while providing targets with env
2423
// RUN: clang-offload-bundler -unbundle -type=o -targets=hip-amdgcn-amd-amdhsa--gfx906,hip-amdgcn-amd-amdhsa--gfx908 -input=%t.bundle.no.env -output=%t-hip-amdgcn-amd-amdhsa--gfx906.bc -output=%t-hip-amdgcn-amd-amdhsa--gfx908.bc -debug-only=CodeObjectCompatibility 2>&1 | FileCheck %s -check-prefix=BUNDLE-NO-ENV
25-
// BUNDLE-NO-ENV: Compatible: Exact match: [CodeObject: hip-amdgcn-amd-amdhsa--gfx906] : [Target: hip-amdgcn-amd-amdhsa--gfx906]
26-
// BUNDLE-NO-ENV: Compatible: Exact match: [CodeObject: hip-amdgcn-amd-amdhsa--gfx908] : [Target: hip-amdgcn-amd-amdhsa--gfx908]
24+
// BUNDLE-NO-ENV: Compatible: Exact match: [CodeObject: hip-amdgcn-amd-amdhsa-unknown-gfx906] : [Target: hip-amdgcn-amd-amdhsa-unknown-gfx906]
25+
// BUNDLE-NO-ENV: Compatible: Exact match: [CodeObject: hip-amdgcn-amd-amdhsa-unknown-gfx908] : [Target: hip-amdgcn-amd-amdhsa-unknown-gfx908]
2726

2827
// Unbundle bundle.env while providing targets with no env
29-
// RUN: clang-offload-bundler -unbundle -type=o -targets=hip-amdgcn-amd-amdhsa-gfx906,hip-amdgcn-amd-amdhsa-gfx908 -input=%t.bundle.env -output=%t-hip-amdgcn-amd-amdhsa-gfx906.bc -output=%t-hip-amdgcn-amd-amdhsa-gfx908.bc -debug-only=CodeObjectCompatibility 2>&1 | FileCheck %s -check-prefix=BUNDLE-ENV
30-
// BUNDLE-ENV: Compatible: Exact match: [CodeObject: hip-amdgcn-amd-amdhsa--gfx906] : [Target: hip-amdgcn-amd-amdhsa--gfx906]
31-
// BUNDLE-ENV: Compatible: Exact match: [CodeObject: hip-amdgcn-amd-amdhsa--gfx908] : [Target: hip-amdgcn-amd-amdhsa--gfx908]
28+
// RUN: clang-offload-bundler -unbundle -type=o -targets=hip-amdgcn-amd-amdhsa--gfx906,hip-amdgcn-amd-amdhsa--gfx908 -input=%t.bundle.env -output=%t-hip-amdgcn-amd-amdhsa--gfx906.bc -output=%t-hip-amdgcn-amd-amdhsa--gfx908.bc -debug-only=CodeObjectCompatibility 2>&1 | FileCheck %s -check-prefix=BUNDLE-ENV
29+
// BUNDLE-ENV: Compatible: Exact match: [CodeObject: hip-amdgcn-amd-amdhsa-unknown-gfx906] : [Target: hip-amdgcn-amd-amdhsa-unknown-gfx906]
30+
// BUNDLE-ENV: Compatible: Exact match: [CodeObject: hip-amdgcn-amd-amdhsa-unknown-gfx908] : [Target: hip-amdgcn-amd-amdhsa-unknown-gfx908]
3231

3332
// Some code so that we can create a binary out of this file.
3433
int A = 0;

clang/test/Driver/clang-offload-bundler-zstd.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@
3838
// CHECK: Decompression method: zstd
3939
// CHECK: Hashes match: Yes
4040
// NOHOST-NOT: host-
41-
// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx900
42-
// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx906
41+
// NOHOST-DAG: hip-amdgcn-amd-amdhsa-unknown-gfx900
42+
// NOHOST-DAG: hip-amdgcn-amd-amdhsa-unknown-gfx906
4343
//
4444

4545
// Check -compression-level= option
@@ -77,10 +77,10 @@
7777
// RUN: -output=%t.hip_900.a -output=%t.hip_906.a -input=%t.hip_archive.a
7878
// RUN: llvm-ar t %t.hip_900.a | FileCheck -check-prefix=HIP-AR-900 %s
7979
// RUN: llvm-ar t %t.hip_906.a | FileCheck -check-prefix=HIP-AR-906 %s
80-
// HIP-AR-900-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa--gfx900
81-
// HIP-AR-900-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa--gfx900
82-
// HIP-AR-906-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa--gfx906
83-
// HIP-AR-906-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa--gfx906
80+
// HIP-AR-900-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa-unknown-gfx900
81+
// HIP-AR-900-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa-unknown-gfx900
82+
// HIP-AR-906-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa-unknown-gfx906
83+
// HIP-AR-906-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa-unknown-gfx906
8484

8585
// Some code so that we can create a binary out of this file.
8686
int A = 0;

clang/test/Driver/clang-offload-bundler.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@
116116
// RUN: not clang-offload-bundler -type=i -targets=host-powerpc64le-ibm-linux-gnu,openmp-powerpc64le-ibm-linux-gnu,xpenmp-x86_xx-pc-linux-gnu -input=%t.i -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR8B
117117
// CK-ERR8B: error: invalid target 'xpenmp-x86_xx-pc-linux-gnu', unknown offloading kind 'xpenmp', unknown target triple 'x86_xx-pc-linux-gnu'
118118

119-
// RUN: not clang-offload-bundler -type=i -targets=openmp-powerpc64le-linux,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -input=%t.i -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR9A
119+
// RUN: not clang-offload-bundler -type=i -targets=openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -input=%t.i -input=%t.tgt1 -output=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR9A
120120
// CK-ERR9A: error: expecting exactly one host target but got 0
121121

122122
// RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,host-%itanium_abi_triple,openmp-x86_64-pc-linux-gnu -input=%t.i -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR9B
@@ -364,15 +364,15 @@
364364
// RUN: not clang-offload-bundler -type=bc -input=%t.hip.bundle.bc -output=%t.tmp.bc -output=%t.tmp2.bc -unbundle \
365365
// RUN: -targets=hip-amdgcn-amd-amdhsa--gfx906,hip-amdgcn-amd-amdhsa--gfx900 \
366366
// RUN: 2>&1 | FileCheck -check-prefix=MISS1 %s
367-
// MISS1: error: Can't find bundles for hip-amdgcn-amd-amdhsa--gfx906
367+
// MISS1: error: Can't find bundles for hip-amdgcn-amd-amdhsa-unknown-gfx906
368368
// RUN: not clang-offload-bundler -type=bc -input=%t.hip.bundle.bc -output=%t.tmp.bc -output=%t.tmp2.bc -unbundle \
369369
// RUN: -targets=hip-amdgcn-amd-amdhsa--gfx906,hip-amdgcn-amd-amdhsa--gfx803 \
370370
// RUN: 2>&1 | FileCheck -check-prefix=MISS2 %s
371-
// MISS2: error: Can't find bundles for hip-amdgcn-amd-amdhsa--gfx803 and hip-amdgcn-amd-amdhsa--gfx906
371+
// MISS2: error: Can't find bundles for hip-amdgcn-amd-amdhsa-unknown-gfx803 and hip-amdgcn-amd-amdhsa-unknown-gfx906
372372
// RUN: not clang-offload-bundler -type=bc -input=%t.hip.bundle.bc -output=%t.tmp.bc -output=%t.tmp2.bc -output=%t.tmp3.bc -unbundle \
373373
// RUN: -targets=hip-amdgcn-amd-amdhsa--gfx906,hip-amdgcn-amd-amdhsa--gfx803,hip-amdgcn-amd-amdhsa--gfx1010 \
374374
// RUN: 2>&1 | FileCheck -check-prefix=MISS3 %s
375-
// MISS3: error: Can't find bundles for hip-amdgcn-amd-amdhsa--gfx1010, hip-amdgcn-amd-amdhsa--gfx803, and hip-amdgcn-amd-amdhsa--gfx906
375+
// MISS3: error: Can't find bundles for hip-amdgcn-amd-amdhsa-unknown-gfx1010, hip-amdgcn-amd-amdhsa-unknown-gfx803, and hip-amdgcn-amd-amdhsa-unknown-gfx906
376376

377377
//
378378
// Check error due to duplicate targets
@@ -422,10 +422,10 @@
422422
// RUN: -output=%T/hip_900.a -output=%T/hip_906.a -input=%T/hip_archive.a
423423
// RUN: llvm-ar t %T/hip_900.a | FileCheck -check-prefix=HIP-AR-900 %s
424424
// RUN: llvm-ar t %T/hip_906.a | FileCheck -check-prefix=HIP-AR-906 %s
425-
// HIP-AR-900-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa--gfx900
426-
// HIP-AR-900-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa--gfx900
427-
// HIP-AR-906-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa--gfx906
428-
// HIP-AR-906-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa--gfx906
425+
// HIP-AR-900-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa-unknown-gfx900
426+
// HIP-AR-900-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa-unknown-gfx900
427+
// HIP-AR-906-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa-unknown-gfx906
428+
// HIP-AR-906-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa-unknown-gfx906
429429

430430
//
431431
// Check unbundling archive for host target
@@ -469,8 +469,8 @@
469469
// RUN: diff %t.tgt2 %t.res.tgt2
470470
//
471471
// NOHOST-NOT: host-
472-
// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx900
473-
// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx906
472+
// NOHOST-DAG: hip-amdgcn-amd-amdhsa-unknown-gfx900
473+
// NOHOST-DAG: hip-amdgcn-amd-amdhsa-unknown-gfx906
474474

475475
//
476476
// Check bundling ID compatibility for HIP.

llvm/utils/lit/lit/llvm/config.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,14 @@ def get_clang_has_lsan(self, clang, triple):
349349

350350
return False
351351

352+
# Normalize 3-field target triple to 4-field triple with "unknown" as environment
353+
def normalize_triple(self, triple):
354+
compoments = triple.split("-", maxsplit=3)
355+
if len(compoments) == 4:
356+
return triple
357+
assert len(compoments) == 3
358+
return triple + "-unknown"
359+
352360
def make_itanium_abi_triple(self, triple):
353361
m = re.match(r"(\w+)-(\w+)-(\w+)", triple)
354362
if not m:
@@ -659,7 +667,9 @@ def use_clang(
659667
self.config.substitutions.append(
660668
(
661669
"%itanium_abi_triple",
662-
self.make_itanium_abi_triple(self.config.target_triple),
670+
self.normalize_triple(
671+
self.make_itanium_abi_triple(self.config.target_triple)
672+
),
663673
)
664674
)
665675
self.config.substitutions.append(

0 commit comments

Comments
 (0)