summaryrefslogtreecommitdiff
path: root/source/compiler-core/slang-artifact-desc-util.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2022-08-09 11:23:40 -0400
committerGitHub <noreply@github.com>2022-08-09 11:23:40 -0400
commit9df7fcb023bd5a22f35ecd609b7a50cc6634976c (patch)
tree69692c36e664eafa2a37b5fa13ca7142f62b1844 /source/compiler-core/slang-artifact-desc-util.cpp
parentc0733be56dc24ef0eb67b26fe0c49d3419e75773 (diff)
Artifact split interface and implementation (#2349)
* #include an absolute path didn't work - because paths were taken to always be relative. * WIP with hierarchical enums. * Some small fixes and improvements around artifact desc related types. * Improvements around hierarchical enum. * Fixes to get Artifact types refactor to be able to execute tests. * Attempt to better categorize PTX. * Work around for potentially unused function warning. * Typo fix. * Simplify Artifact header. * Small improvements around Artifact kind/payload/style. * Added IDestroyable/ICastable * Add IArtifactList. * First impl of IArtifactUtil. * Use the ICastable interface for IArtifactRepresentation. * Added IArtifactRepresentation & IArtifactAssociated. * Add SLANG_OVERRIDE to avoid gcc/clang warning. * Fix calling convention issue on win32. * Fix missing SLANG_OVERRIDE. * First attempt at file abstraction around Artifact. * Added creation of lock file. * Move functionality for determining file paths to the IArtifactUtil. Add casting to ICastable. * Added some casting/finding mechanisms. * Simplify IArtifact interface, and use Items for file reps. * Fix problem with libraries on DXIL. * Split out ArtifactRepresentation. * Move ArtifactDesc functionality to ArtifactDescUtil. ArtifactInfoUtil becomes ArtifactDescUtil. * Split implementations from the interfaces for Artifact. * Use TypeTextUtil for target name outputting. * Add artifact impls.
Diffstat (limited to 'source/compiler-core/slang-artifact-desc-util.cpp')
-rw-r--r--source/compiler-core/slang-artifact-desc-util.cpp689
1 files changed, 689 insertions, 0 deletions
diff --git a/source/compiler-core/slang-artifact-desc-util.cpp b/source/compiler-core/slang-artifact-desc-util.cpp
new file mode 100644
index 000000000..e382ca08c
--- /dev/null
+++ b/source/compiler-core/slang-artifact-desc-util.cpp
@@ -0,0 +1,689 @@
+// slang-artifact-desc-util.cpp
+#include "slang-artifact-desc-util.h"
+
+#include "slang-artifact-representation.h"
+
+#include "../core/slang-type-text-util.h"
+#include "../core/slang-io.h"
+
+namespace Slang {
+
+namespace { // anonymous
+
+struct HierarchicalEnumEntry
+{
+ Index value;
+ Index parent;
+ const char* name;
+};
+
+static bool _isHierarchicalEnumOk(ConstArrayView<HierarchicalEnumEntry> entries, Count countOf)
+{
+ // All values should be set
+ if (entries.getCount() != countOf)
+ {
+ return false;
+ }
+
+ List<uint8_t> isUsed;
+ isUsed.setCount(countOf);
+ ::memset(isUsed.getBuffer(), 0, countOf);
+
+ for (const auto& entry : entries)
+ {
+ const auto value = entry.value;
+ // Must be in range
+ if (value < 0 || value >= countOf)
+ {
+ return false;
+ }
+
+ if (isUsed[value] != 0)
+ {
+ return false;
+ }
+ // Mark as used
+ isUsed[value]++;
+ }
+
+ // There can't be any gaps
+ for (auto v : isUsed)
+ {
+ if (v == 0)
+ {
+ return false;
+ }
+ }
+
+ // Okay, looks reasonable..
+ return true;
+}
+
+template <typename T>
+struct HierarchicalEnumTable
+{
+ HierarchicalEnumTable(ConstArrayView<HierarchicalEnumEntry> entries)
+ {
+ // Remove warnings around this not being used.
+ {
+ const auto unused = _isHierarchicalEnumOk;
+ SLANG_UNUSED(unused);
+ }
+
+ SLANG_COMPILE_TIME_ASSERT(Index(T::Invalid) < Index(T::Base));
+ SLANG_ASSERT(entries.getCount() == Count(T::CountOf));
+
+ SLANG_ASSERT(_isHierarchicalEnumOk(entries, Count(T::CountOf)));
+
+ ::memset(&m_parents, 0, sizeof(m_parents));
+
+ for (const auto& entry : entries)
+ {
+ const auto value = entry.value;
+ m_parents[value] = T(entry.parent);
+ m_names[value] = UnownedStringSlice(entry.name);
+ }
+
+ // TODO(JS): NOTE! If we wanted to use parent to indicate if a value was *invalid*
+ // we would want the Parent of Base to be Base.
+ //
+ // Base parent should be invalid
+ SLANG_ASSERT(getParent(T::Base) == T::Invalid);
+ // Invalids parent should be invalid
+ SLANG_ASSERT(getParent(T::Invalid) == T::Invalid);
+ }
+
+ T getParent(T kind) const
+ {
+ return (kind >= T::CountOf) ?
+ T::Invalid :
+ m_parents[Index(kind)];
+ }
+ UnownedStringSlice getName(T kind) const
+ {
+ return (kind >= T::CountOf) ?
+ UnownedStringSlice() :
+ m_names[Index(kind)];
+ }
+
+ bool isDerivedFrom(T type, T base) const
+ {
+ if (Index(type) >= Index(T::CountOf))
+ {
+ return false;
+ }
+
+ do
+ {
+ if (type == base)
+ {
+ return true;
+ }
+ type = m_parents[Index(type)];
+ } while (Index(type) > Index(T::Base));
+
+ return false;
+ }
+
+protected:
+ T m_parents[Count(T::CountOf)];
+ UnownedStringSlice m_names[Count(T::CountOf)];
+};
+
+} // anonymous
+
+// Macro utils to create "enum hierarchy" tables
+
+#define SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_ENTRY_MACRO) \
+static ConstArrayView<HierarchicalEnumEntry> _getEntries##ENUM_TYPE() \
+{ \
+ static const HierarchicalEnumEntry values[] = { ENUM_TYPE_MACRO(ENUM_ENTRY_MACRO) }; \
+ return makeConstArrayView(values); \
+}
+
+#define SLANG_HIERARCHICAL_ENUM(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \
+SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \
+\
+static const HierarchicalEnumTable<ENUM_TYPE> g_table##ENUM_TYPE(_getEntries##ENUM_TYPE()); \
+\
+ENUM_TYPE getParent(ENUM_TYPE kind) { return g_table##ENUM_TYPE.getParent(kind); } \
+UnownedStringSlice getName(ENUM_TYPE kind) { return g_table##ENUM_TYPE.getName(kind); } \
+bool isDerivedFrom(ENUM_TYPE kind, ENUM_TYPE base) { return g_table##ENUM_TYPE.isDerivedFrom(kind, base); }
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactKind !!!!!!!!!!!!!!!!!!!!!!! */
+
+#define SLANG_ARTIFACT_KIND(x) \
+ x(Invalid, Invalid) \
+ x(Base, Invalid) \
+ x(None, Base) \
+ x(Unknown, Base) \
+ x(Container, Base) \
+ x(Zip, Container) \
+ x(Riff, Container) \
+ x(Text, Base) \
+ x(HumanText, Text) \
+ x(Source, Text) \
+ x(Assembly, Text) \
+ x(BinaryLike, Base) \
+ x(ObjectCode, BinaryLike) \
+ x(Library, BinaryLike) \
+ x(Executable, BinaryLike) \
+ x(SharedLibrary, BinaryLike) \
+ x(HostCallable, BinaryLike) \
+ \
+ x(DebugInfo, Base) \
+ x(Diagnostics, Base)
+
+#define SLANG_ARTIFACT_KIND_ENTRY(TYPE, PARENT) { Index(ArtifactKind::TYPE), Index(ArtifactKind::PARENT), #TYPE },
+
+SLANG_HIERARCHICAL_ENUM(ArtifactKind, SLANG_ARTIFACT_KIND, SLANG_ARTIFACT_KIND_ENTRY)
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactPayload !!!!!!!!!!!!!!!!!!!!!!! */
+
+#define SLANG_ARTIFACT_PAYLOAD(x) \
+ x(Invalid, Invalid) \
+ x(Base, Invalid) \
+ x(None, Base) \
+ x(Unknown, Base) \
+ x(Source, Base) \
+ x(C, Source) \
+ x(Cpp, Source) \
+ x(HLSL, Source) \
+ x(GLSL, Source) \
+ x(CUDA, Source) \
+ x(Metal, Source) \
+ x(Slang, Source) \
+ x(KernelLike, Base) \
+ x(DXIL, KernelLike) \
+ x(DXBC, KernelLike) \
+ x(SPIRV, KernelLike) \
+ x(PTX, KernelLike) \
+ x(CuBin, KernelLike) \
+ x(MetalAIR, KernelLike) \
+ x(CPULike, Base) \
+ x(UnknownCPU, CPULike) \
+ x(X86, CPULike) \
+ x(X86_64, CPULike) \
+ x(Aarch, CPULike) \
+ x(Aarch64, CPULike) \
+ x(HostCPU, CPULike) \
+ x(UniversalCPU, CPULike) \
+ x(GeneralIR, Base) \
+ x(SlangIR, GeneralIR) \
+ x(LLVMIR, GeneralIR) \
+ x(AST, Base) \
+ x(SlangAST, AST)
+
+#define SLANG_ARTIFACT_PAYLOAD_ENTRY(TYPE, PARENT) { Index(ArtifactPayload::TYPE), Index(ArtifactPayload::PARENT), #TYPE },
+
+SLANG_HIERARCHICAL_ENUM(ArtifactPayload, SLANG_ARTIFACT_PAYLOAD, SLANG_ARTIFACT_PAYLOAD_ENTRY)
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactStyle !!!!!!!!!!!!!!!!!!!!!!! */
+
+#define SLANG_ARTIFACT_STYLE(x) \
+ x(Invalid, Invalid) \
+ x(Base, Invalid) \
+ x(Unknown, Base) \
+ x(Kernel, Base) \
+ x(Host, Base)
+
+#define SLANG_ARTIFACT_STYLE_ENTRY(TYPE, PARENT) { Index(ArtifactStyle::TYPE), Index(ArtifactStyle::PARENT), #TYPE },
+
+SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYLE_ENTRY)
+
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDescUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+/* static */ArtifactDesc ArtifactDescUtil::makeDescFromCompileTarget(SlangCompileTarget target)
+{
+ switch (target)
+ {
+ case SLANG_TARGET_UNKNOWN: return Desc::make(Kind::Unknown, Payload::None, Style::Unknown, 0);
+ case SLANG_TARGET_NONE: return Desc::make(Kind::None, Payload::None, Style::Unknown, 0);
+ case SLANG_GLSL_VULKAN:
+ case SLANG_GLSL_VULKAN_ONE_DESC:
+ case SLANG_GLSL:
+ {
+ // For the moment we Desc::make all just map to GLSL, but we could use flags
+ // or some other mechanism to distinguish the types
+ return Desc::make(Kind::Source, Payload::GLSL, Style::Kernel, 0);
+ }
+ case SLANG_HLSL: return Desc::make(Kind::Source, Payload::HLSL, Style::Kernel, 0);
+ case SLANG_SPIRV: return Desc::make(Kind::Executable, Payload::SPIRV, Style::Kernel, 0);
+ case SLANG_SPIRV_ASM: return Desc::make(Kind::Assembly, Payload::SPIRV, Style::Kernel, 0);
+ case SLANG_DXBC: return Desc::make(Kind::Executable, Payload::DXBC, Style::Kernel, 0);
+ case SLANG_DXBC_ASM: return Desc::make(Kind::Assembly, Payload::DXBC, Style::Kernel, 0);
+ case SLANG_DXIL: return Desc::make(Kind::Executable, Payload::DXIL, Style::Kernel, 0);
+ case SLANG_DXIL_ASM: return Desc::make(Kind::Assembly, Payload::DXIL, Style::Kernel, 0);
+ case SLANG_C_SOURCE: return Desc::make(Kind::Source, Payload::C, Style::Kernel, 0);
+ case SLANG_CPP_SOURCE: return Desc::make(Kind::Source, Payload::Cpp, Style::Kernel, 0);
+ case SLANG_HOST_CPP_SOURCE: return Desc::make(Kind::Source, Payload::Cpp, Style::Host, 0);
+ case SLANG_HOST_EXECUTABLE: return Desc::make(Kind::Executable, Payload::HostCPU, Style::Host, 0);
+ case SLANG_SHADER_SHARED_LIBRARY: return Desc::make(Kind::SharedLibrary, Payload::HostCPU, Style::Kernel, 0);
+ case SLANG_SHADER_HOST_CALLABLE: return Desc::make(Kind::HostCallable, Payload::HostCPU, Style::Kernel, 0);
+ case SLANG_CUDA_SOURCE: return Desc::make(Kind::Source, Payload::CUDA, Style::Kernel, 0);
+ // TODO(JS):
+ // Not entirely clear how best to represent PTX here. We could mark as 'Assembly'. Saying it is
+ // 'Executable' implies it is Binary (which PTX isn't). Executable also implies 'complete for executation',
+ // irrespective of it being text.
+ case SLANG_PTX: return Desc::make(Kind::Executable, Payload::PTX, Style::Kernel, 0);
+ case SLANG_OBJECT_CODE: return Desc::make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0);
+ case SLANG_HOST_HOST_CALLABLE: return Desc::make(Kind::HostCallable, Payload::HostCPU, Style::Host, 0);
+ default: break;
+ }
+
+ SLANG_UNEXPECTED("Unhandled type");
+}
+
+namespace { // anonymous
+struct KindExtension
+{
+ ArtifactKind kind;
+ UnownedStringSlice ext;
+};
+} // anonymous
+
+#define SLANG_KIND_EXTENSION(kind, ext) \
+ { ArtifactKind::kind, toSlice(ext) },
+
+static const KindExtension g_cpuKindExts[] =
+{
+#if SLANG_WINDOWS_FAMILY
+ SLANG_KIND_EXTENSION(Library, "lib")
+ SLANG_KIND_EXTENSION(ObjectCode, "obj")
+ SLANG_KIND_EXTENSION(Executable, "exe")
+ SLANG_KIND_EXTENSION(SharedLibrary, "dll")
+#else
+ SLANG_KIND_EXTENSION(Library, "a")
+ SLANG_KIND_EXTENSION(ObjectCode, "o")
+ SLANG_KIND_EXTENSION(Executable, "")
+
+#if __CYGWIN__
+ SLANG_KIND_EXTENSION(SharedLibrary, "dll")
+#elif SLANG_APPLE_FAMILY
+ SLANG_KIND_EXTENSION(SharedLibrary, "dylib")
+#else
+ SLANG_KIND_EXTENSION(SharedLibrary, "so")
+#endif
+
+#endif
+};
+
+
+/* static */ bool ArtifactDescUtil::isCpuBinary(const ArtifactDesc& desc)
+{
+ return isDerivedFrom(desc.kind, ArtifactKind::BinaryLike) && isDerivedFrom(desc.payload, ArtifactPayload::CPULike);
+}
+
+/* static */bool ArtifactDescUtil::isText(const ArtifactDesc& desc)
+{
+ // If it's derived from text...
+ if (isDerivedFrom(desc.kind, ArtifactKind::Text))
+ {
+ return true;
+ }
+
+ // Special case PTX...
+ if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike))
+ {
+ return desc.payload == ArtifactPayload::PTX;
+ }
+
+ // Not text
+ return false;
+}
+
+/* static */bool ArtifactDescUtil::isGpuUsable(const ArtifactDesc& desc)
+{
+ if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike))
+ {
+ return isDerivedFrom(desc.payload, ArtifactPayload::KernelLike);
+ }
+
+ // PTX is a kind of special case, it's an 'assembly' (low level text represention) that can be passed
+ // to CUDA runtime
+ return desc.kind == ArtifactKind::Assembly && desc.payload == ArtifactPayload::PTX;
+}
+
+/* static */bool ArtifactDescUtil::isKindBinaryLinkable(Kind kind)
+{
+ switch (kind)
+ {
+ case Kind::Library:
+ case Kind::ObjectCode:
+ {
+ return true;
+ }
+ default: break;
+ }
+ return false;
+}
+
+/* static */bool ArtifactDescUtil::isLinkable(const ArtifactDesc& desc)
+{
+ if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike))
+ {
+ if (isDerivedFrom(desc.payload, ArtifactPayload::KernelLike))
+ {
+ // It seems as if DXBC is potentially linkable from
+ // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-keywords#export
+
+ // We can't *actually* link PTX or SPIR-V currently but it is in principal possible
+ // so let's say we accept for now
+
+ return true;
+ }
+ else if (isDerivedFrom(desc.payload, ArtifactPayload::CPULike))
+ {
+ // If kind is exe or shared library, linking will arguably not work
+ if (desc.kind == ArtifactKind::SharedLibrary ||
+ desc.kind == ArtifactKind::Executable)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ else if (isDerivedFrom(desc.payload, ArtifactPayload::GeneralIR))
+ {
+ // We'll *assume* IR is linkable
+ return true;
+ }
+ }
+ return false;
+}
+
+/* static */bool ArtifactDescUtil::isCpuLikeTarget(const ArtifactDesc& desc)
+{
+ if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike))
+ {
+ return isDerivedFrom(desc.payload, ArtifactPayload::CPULike);
+ }
+ else if (isDerivedFrom(desc.kind, ArtifactKind::Source))
+ {
+ // We'll assume C/C++ are targetting CPU, although that is perhaps somewhat arguable.
+ return desc.payload == Payload::C || desc.payload == Payload::Cpp;
+ }
+
+ return false;
+}
+
+/* static */ArtifactDesc ArtifactDescUtil::getDescFromExtension(const UnownedStringSlice& slice)
+{
+ if (slice == "slang-module" ||
+ slice == "slang-lib")
+ {
+ return ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::SlangIR);
+ }
+
+ // Metal
+ // https://developer.apple.com/documentation/metal/shader_libraries/building_a_library_with_metal_s_command-line_tools
+ if (slice == toSlice("air"))
+ {
+ return ArtifactDesc::make(ArtifactKind::ObjectCode, ArtifactPayload::MetalAIR);
+ }
+ else if (slice == toSlice("metallib") || slice == toSlice("metalar"))
+ {
+ return ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::MetalAIR);
+ }
+
+ if (slice == toSlice("zip"))
+ {
+ return ArtifactDesc::make(ArtifactKind::Zip, ArtifactPayload::Unknown);
+ }
+ else if (slice == toSlice("riff"))
+ {
+ return ArtifactDesc::make(ArtifactKind::Riff, ArtifactPayload::Unknown);
+ }
+
+ if (slice == toSlice("asm"))
+ {
+ // We'll assume asm means current CPU assembler..
+ return ArtifactDesc::make(ArtifactKind::Assembly, ArtifactPayload::HostCPU);
+ }
+
+ for (const auto& kindExt : g_cpuKindExts)
+ {
+ if (slice == kindExt.ext)
+ {
+ // We'll assume it's for the host CPU for now..
+ return ArtifactDesc::make(kindExt.kind, Payload::HostCPU);
+ }
+ }
+
+ const auto target = TypeTextUtil::findCompileTargetFromExtension(slice);
+
+ return makeDescFromCompileTarget(target);
+}
+
+/* static */ArtifactDesc ArtifactDescUtil::getDescFromPath(const UnownedStringSlice& slice)
+{
+ auto extension = Path::getPathExt(slice);
+ return getDescFromExtension(extension);
+}
+
+/* static*/ UnownedStringSlice ArtifactDescUtil::getCpuExtensionForKind(Kind kind)
+{
+ for (const auto& kindExt : g_cpuKindExts)
+ {
+ if (kind == kindExt.kind)
+ {
+ return kindExt.ext;
+ }
+ }
+ return UnownedStringSlice();
+}
+
+UnownedStringSlice ArtifactDescUtil::getAssemblyExtensionForPayload(ArtifactPayload payload)
+{
+ switch (payload)
+ {
+ case ArtifactPayload::DXIL: return toSlice("dxil-asm");
+ case ArtifactPayload::DXBC: return toSlice("dxbc-asm");
+ case ArtifactPayload::SPIRV: return toSlice("spv-asm");
+ case ArtifactPayload::PTX: return toSlice("ptx");
+
+ // TODO(JS):
+ // Not sure what to do for metal - does it have an assembly name?
+
+ default: break;
+ }
+
+ // We'll just use asm for all CPU assembly type
+ if (isDerivedFrom(payload, ArtifactPayload::CPULike))
+ {
+ return toSlice("asm");
+ }
+
+ if (isDerivedFrom(payload, ArtifactPayload::GeneralIR))
+ {
+ switch (payload)
+ {
+ case ArtifactPayload::SlangIR: return toSlice("slang-ir-asm");
+ case ArtifactPayload::LLVMIR: return toSlice("llvm-ir-asm");
+ break;
+ }
+ }
+
+ return UnownedStringSlice();
+}
+
+UnownedStringSlice ArtifactDescUtil::getDefaultExtension(const ArtifactDesc& desc)
+{
+ switch (desc.kind)
+ {
+ case ArtifactKind::Zip: return toSlice("zip");
+ case ArtifactKind::Riff: return toSlice("riff");
+ case ArtifactKind::Assembly:
+ {
+ return getAssemblyExtensionForPayload(desc.payload);
+ }
+ case ArtifactKind::Source:
+ {
+ switch (desc.payload)
+ {
+ case Payload::HLSL: return toSlice("hlsl");
+ case Payload::GLSL: return toSlice("glsl");
+
+ case Payload::Cpp: return toSlice("cpp");
+ case Payload::C: return toSlice("c");
+
+ case Payload::Metal: return toSlice("metal");
+
+ case Payload::CUDA: return toSlice("cu");
+
+ case Payload::Slang: return toSlice("slang");
+ default: break;
+ }
+ }
+ default: break;
+ }
+
+ if (ArtifactDescUtil::isCpuLikeTarget(desc))
+ {
+ return getCpuExtensionForKind(desc.kind);
+ }
+
+ if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike))
+ {
+ switch (desc.payload)
+ {
+ case Payload::None: return UnownedStringSlice();
+ case Payload::Unknown: return toSlice("unknown");
+
+ case Payload::DXIL: return toSlice("dxil");
+ case Payload::DXBC: return toSlice("dxbc");
+ case Payload::SPIRV: return toSlice("spv");
+
+ case Payload::PTX: return toSlice("ptx");
+
+ case Payload::LLVMIR: return toSlice("llvm-ir");
+
+ case Payload::SlangIR:
+ {
+ return (desc.kind == ArtifactKind::Library) ? toSlice("slang-module") : toSlice("slang-ir");
+ }
+ case Payload::MetalAIR:
+ {
+ // https://developer.apple.com/documentation/metal/shader_libraries/building_a_library_with_metal_s_command-line_tools
+ return (desc.kind == ArtifactKind::Library) ? toSlice("metallib") : toSlice("air");
+ }
+ default: break;
+ }
+ }
+
+ return UnownedStringSlice();
+}
+
+/* static */String ArtifactDescUtil::getBaseNameFromPath(const ArtifactDesc& desc, const UnownedStringSlice& path)
+{
+ String name = Path::getFileName(path);
+
+ const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY;
+ if (isSharedLibraryPrefixPlatform)
+ {
+ // Strip lib prefix
+ if (isCpuBinary(desc) &&
+ (desc.kind == ArtifactKind::Library ||
+ desc.kind == ArtifactKind::SharedLibrary))
+ {
+ // If it starts with lib strip it
+ if (name.startsWith("lib"))
+ {
+ const String stripLib = name.getUnownedSlice().tail(3);
+ name = stripLib;
+ }
+ }
+ }
+
+ // Strip any extension
+ {
+ auto descExt = getDefaultExtension(desc);
+ // Strip the extension if it's a match
+ if (descExt.getLength() &&
+ Path::getPathExt(name) == descExt)
+ {
+ name = Path::getFileNameWithoutExt(name);
+ }
+ }
+
+ return name;
+}
+
+/* static */String ArtifactDescUtil::getBaseName(const ArtifactDesc& desc, IFileArtifactRepresentation* fileRep)
+{
+ UnownedStringSlice path(fileRep->getPath());
+ return getBaseNameFromPath(desc, path);
+}
+
+/* static */String ArtifactDescUtil::getBaseName(IArtifact* artifact)
+{
+ if (auto fileRep = findItem<IFileArtifactRepresentation>(artifact))
+ {
+ return getBaseName(artifact->getDesc(), fileRep);
+ }
+ // Else use the name
+ return artifact->getName();
+}
+
+/* static */String ArtifactDescUtil::getParentPath(IFileArtifactRepresentation* fileRep)
+{
+ UnownedStringSlice path(fileRep->getPath());
+ return Path::getParentDirectory(path);
+}
+
+/* static */String ArtifactDescUtil::getParentPath(IArtifact* artifact)
+{
+ if (auto fileRep = findItem<IFileArtifactRepresentation>(artifact))
+ {
+ return getParentPath(fileRep);
+ }
+ return String();
+}
+
+/* static */SlangResult ArtifactDescUtil::calcPathForDesc(const ArtifactDesc& desc, const UnownedStringSlice& basePath, StringBuilder& outPath)
+{
+ outPath.Clear();
+
+ UnownedStringSlice baseName;
+
+ // Append the directory
+ Index pos = Path::findLastSeparatorIndex(basePath);
+ if (pos >= 0)
+ {
+ outPath.append(basePath.head(pos));
+ outPath.append(Path::kPathDelimiter);
+
+ baseName = basePath.tail(pos + 1);
+ }
+
+ if (baseName.getLength() == 0)
+ {
+ baseName = toSlice("unknown");
+ }
+
+ if (isCpuBinary(desc) &&
+ (desc.kind == ArtifactKind::SharedLibrary ||
+ desc.kind == ArtifactKind::Library))
+ {
+ const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY;
+ if (isSharedLibraryPrefixPlatform)
+ {
+ outPath << "lib";
+ outPath << baseName;
+ }
+ }
+
+ // If there is an extension append it
+ const UnownedStringSlice ext = getDefaultExtension(desc);
+
+ if (ext.getLength())
+ {
+ outPath.appendChar('.');
+ outPath.append(ext);
+ }
+
+ return SLANG_OK;
+}
+
+} // namespace Slang