// slang-artifact.cpp #include "slang-artifact.h" #include "slang-artifact-info.h" #include "../core/slang-type-text-util.h" #include "../core/slang-io.h" namespace Slang { /* static */ArtifactDesc ArtifactDesc::makeFromCompileTarget(SlangCompileTarget target) { switch (target) { case SLANG_TARGET_UNKNOWN: return make(Kind::Unknown, Payload::None, Style::Unknown, 0); case SLANG_TARGET_NONE: return 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 make all just map to GLSL, but we could use flags // or some other mechanism to distinguish the types return make(Kind::Text, Payload::GLSL, Style::Kernel, 0); } case SLANG_HLSL: return make(Kind::Text, Payload::HLSL, Style::Kernel, 0); case SLANG_SPIRV: return make(Kind::Executable, Payload::SPIRV, Style::Kernel, 0); case SLANG_SPIRV_ASM: return make(Kind::Text, Payload::SPIRVAssembly, Style::Kernel, 0); case SLANG_DXBC: return make(Kind::Executable, Payload::DXBC, Style::Kernel, 0); case SLANG_DXBC_ASM: return make(Kind::Text, Payload::DXBCAssembly, Style::Kernel, 0); case SLANG_DXIL: return make(Kind::Executable, Payload::DXIL, Style::Kernel, 0); case SLANG_DXIL_ASM: return make(Kind::Text, Payload::DXILAssembly, Style::Kernel, 0); case SLANG_C_SOURCE: return make(Kind::Text, Payload::C, Style::Kernel, 0); case SLANG_CPP_SOURCE: return make(Kind::Text, Payload::CPP, Style::Kernel, 0); case SLANG_HOST_CPP_SOURCE: return make(Kind::Text, Payload::CPP, Style::Host, 0); case SLANG_HOST_EXECUTABLE: return make(Kind::Executable, Payload::HostCPU, Style::Host, 0); case SLANG_SHADER_SHARED_LIBRARY: return make(Kind::SharedLibrary, Payload::HostCPU, Style::Kernel, 0); case SLANG_SHADER_HOST_CALLABLE: return make(Kind::Callable, Payload::HostCPU, Style::Kernel, 0); case SLANG_CUDA_SOURCE: return make(Kind::Text, Payload::CUDA, Style::Kernel, 0); case SLANG_PTX: return make(Kind::Executable, Payload::PTX, Style::Kernel, 0); case SLANG_OBJECT_CODE: return make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0); default: break; } SLANG_UNEXPECTED("Unhandled type"); } /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Artifact !!!!!!!!!!!!!!!!!!!!!!!!!!! */ Artifact::~Artifact() { if (m_pathType == PathType::Temporary) { File::remove(m_path); } for (const auto& entry : m_entries) { // Release the associated data switch (entry.type) { case Entry::Type::ObjectInstance: { entry.object->releaseReference(); break; } case Entry::Type::InterfaceInstance: { entry.intf->release(); break; } default: break; } } } Index Artifact::indexOf(Entry::Type type) const { return m_entries.findFirstIndex([&](const Entry& entry) -> bool { return entry.type == type; }); } void Artifact::add(Entry::Style style, RefObject* obj) { SLANG_ASSERT(obj); Entry entry; entry.type = Entry::Type::ObjectInstance; entry.style = style; entry.object = obj; obj->addReference(); m_entries.add(entry); } void Artifact::add(Entry::Style style, ISlangUnknown* intf) { // Can't be nullptr SLANG_ASSERT(intf); Entry entry; entry.type = Entry::Type::InterfaceInstance; entry.style = style; intf->addRef(); entry.intf = intf; m_entries.add(entry); } bool Artifact::exists() const { // If we have a blob it exists if (m_blob) { return true; } // If we have an associated entry that represents the artifact it exists for (const auto& entry : m_entries) { if (entry.style == Entry::Style::Artifact) { // There is a representation that 'is' the artifact return true; } } // If we don't have a path then it can't exist if (m_pathType == PathType::None) { return false; } // If the file exists we assume it exists return File::exists(m_path); } ISlangUnknown* Artifact::findInterfaceInstance(const Guid& guid) { for (const auto& entry : m_entries) { if (entry.type == Entry::Type::InterfaceInstance) { ISlangUnknown* intf = nullptr; if (SLANG_SUCCEEDED(entry.intf->queryInterface(guid, (void**)&intf)) && intf) { // NOTE! This assumes we *DONT* need to ref count to keep an interface in scope // (as strict COM requires so as to allow on demand interfaces). intf->release(); return intf; } } } return nullptr; } /* static */String Artifact::getBaseNameFromPath(Desc& desc, const UnownedStringSlice& path) { String name = Path::getFileName(path); const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY; if (isSharedLibraryPrefixPlatform) { // Strip lib prefix if (ArtifactInfoUtil::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 = ArtifactInfoUtil::getDefaultExtension(desc); // Strip the extension if it's a match if (descExt.getLength() && Path::getPathExt(name) == descExt) { name = Path::getFileNameWithoutExt(name); } } return name; } String Artifact::getBaseName() { if (m_pathType != PathType::None) { return getBaseNameFromPath(m_desc, m_path.getUnownedSlice()); } return m_name; } String Artifact::getParentPath() { if (m_pathType != PathType::None && m_path.getLength()) { return Path::getParentDirectory(m_path); } return String(); } SlangResult Artifact::requireFileLike(Keep keep) { // If there is no path set and no blob we still need a name. // If the artifact is a library we can assume it's a system level library, // or it can be found by appropriate search paths. if (m_pathType == PathType::None && m_blob == nullptr && (m_desc.kind == ArtifactKind::Library || m_desc.kind == ArtifactKind::SharedLibrary)) { if (m_name.getLength() > 0) { return SLANG_OK; } // TODO(JS): If we could serialize, we could turn some other representation into a file, and therefore // a name, but currently that's not supported return SLANG_E_NOT_FOUND; } // Will turn into a file if necessary SLANG_RETURN_ON_FAIL(requireFile(keep)); return SLANG_OK; } SlangResult Artifact::requireFile(Keep keep) { if (m_pathType != PathType::None) { return SLANG_OK; } ComPtr blob; // Get the contents as a blob. If we can't do that, then we can't write anything... SLANG_RETURN_ON_FAIL(loadBlob(getIntermediateKeep(keep), blob)); // If we have a name, make the generated name based on that name // Else just use 'slang-generated' the basis UnownedStringSlice nameBase; if (m_name.getLength() > 0) { nameBase = m_name.getUnownedSlice(); } else { nameBase = UnownedStringSlice::fromLiteral("slang-generated"); } // TODO(JS): NOTE! This isn't strictly correct, as the generated filename is not guarenteed to be unique // if we change it with an extension (or prefix). // This doesn't change the previous behavior though. String path; SLANG_RETURN_ON_FAIL(File::generateTemporary(nameBase, path)); if (ArtifactInfoUtil::isCpuBinary(m_desc) && (m_desc.kind == ArtifactKind::SharedLibrary || m_desc.kind == ArtifactKind::Library)) { const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY; if (isSharedLibraryPrefixPlatform) { StringBuilder buf; buf << "lib"; buf << Path::getFileName(path); auto parentDir = Path::getParentDirectory(path); if (parentDir.getLength()) { // Combine the name with path if their is a parent path = Path::combine(parentDir, buf); } else { // Just use the name as is path = buf; } } } // If there is an extension append it const UnownedStringSlice ext = ArtifactInfoUtil::getDefaultExtension(m_desc); if (ext.getLength()) { path.appendChar('.'); path.append(ext); } SLANG_RETURN_ON_FAIL(File::writeAllBytes(path, blob->getBufferPointer(), blob->getBufferSize())); // Okay we can now add this as temporary path too setPath(PathType::Temporary, path); return SLANG_OK; } SlangResult Artifact::loadBlob(Keep keep, ComPtr& outBlob) { if (m_blob) { outBlob = m_blob; return SLANG_OK; } // TODO(JS): // Strictly speaking we could *potentially* convert some other representation into // a blob by serializing it, but we don't worry about any of that here if (m_pathType == PathType::None) { return SLANG_E_NOT_FOUND; } // Read into a blob ScopedAllocation alloc; SLANG_RETURN_ON_FAIL(File::readAllBytes(m_path, alloc)); // Create as a blob RefPtr blob = RawBlob::moveCreate(alloc); // Put in cache if (canKeep(keep)) { setBlob(blob); } outBlob = blob; return SLANG_OK; } } // namespace Slang