diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2022-09-01 09:35:18 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-01 09:35:18 -0400 |
| commit | cd8715a7760189c54b36c0c250efbe1db5b8635c (patch) | |
| tree | cd1b2e840e64cbdd9e9a383646f0e58a7f14ae97 /source/compiler-core | |
| parent | 5c2c2cfc9918bb43225159e67a851e196e17759a (diff) | |
Passing source to Downstream compilation as artifacts (#2382)
* #include an absolute path didn't work - because paths were taken to always be relative.
* Make DownstreamCompileOptions use POD types.
* CharSliceAllocator -> SliceAllocator
Added SliceConverter
CharSliceCaster -> SliceCaster
* First attempt at zero terminating around blobs.
* Fix clang warning.
* Add SlangTerminatedChars
Make Blob implementations support it.
Make most blobs 'terminated'.
* Fix bug setting up sourceFiles for CommandLineDownstreamCompiler.
* Traffic in TerminatedCharSlice for sourceFiles.
Use ArtifactDesc to generate temporary file names for source.
* Fix typo in testing for shared library/C++.
* Working with source being passed as artifacts to DownstreamCompiler.
* Use artifacts in SourceManager/SourceFile.
* Support infering extension from the original file extension.
Diffstat (limited to 'source/compiler-core')
24 files changed, 574 insertions, 219 deletions
diff --git a/source/compiler-core/slang-artifact-associated-impl.h b/source/compiler-core/slang-artifact-associated-impl.h index 321717a48..8506f1628 100644 --- a/source/compiler-core/slang-artifact-associated-impl.h +++ b/source/compiler-core/slang-artifact-associated-impl.h @@ -37,7 +37,7 @@ public: SLANG_NO_THROW virtual void SLANG_MCALL setResult(SlangResult res) SLANG_OVERRIDE { m_result = res; } SLANG_NO_THROW virtual void SLANG_MCALL setRaw(const CharSlice& slice) SLANG_OVERRIDE; SLANG_NO_THROW virtual void SLANG_MCALL appendRaw(const CharSlice& slice) SLANG_OVERRIDE; - SLANG_NO_THROW virtual TerminatedCharSlice SLANG_MCALL getRaw() SLANG_OVERRIDE { return SliceCaster::asTerminatedCharSlice(m_raw); } + SLANG_NO_THROW virtual TerminatedCharSlice SLANG_MCALL getRaw() SLANG_OVERRIDE { return SliceUtil::asTerminatedCharSlice(m_raw); } SLANG_NO_THROW virtual void SLANG_MCALL reset() SLANG_OVERRIDE; SLANG_NO_THROW virtual Count SLANG_MCALL getCountAtLeastSeverity(Diagnostic::Severity severity) SLANG_OVERRIDE; SLANG_NO_THROW virtual Count SLANG_MCALL getCountBySeverity(Diagnostic::Severity severity) SLANG_OVERRIDE; diff --git a/source/compiler-core/slang-artifact-desc-util.cpp b/source/compiler-core/slang-artifact-desc-util.cpp index cb5d401a9..7534e1265 100644 --- a/source/compiler-core/slang-artifact-desc-util.cpp +++ b/source/compiler-core/slang-artifact-desc-util.cpp @@ -443,12 +443,12 @@ static const KindExtension g_cpuKindExts[] = { switch (kind) { - case Kind::Library: - case Kind::ObjectCode: - { - return true; - } - default: break; + case Kind::Library: + case Kind::ObjectCode: + { + return true; + } + default: break; } return false; } @@ -587,9 +587,6 @@ static UnownedStringSlice _getPayloadExtension(ArtifactPayload payload) typedef ArtifactPayload Payload; switch (payload) { - /* Misc */ - case Payload::Unknown: return toSlice("unknown"); - /* Source types */ case Payload::HLSL: return toSlice("hlsl"); case Payload::GLSL: return toSlice("glsl"); @@ -685,8 +682,14 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S } case ArtifactKind::Source: { - out << _getPayloadExtension(desc.payload); - return SLANG_OK; + auto ext = _getPayloadExtension(desc.payload); + if (ext.begin() != nullptr) + { + out << ext; + return SLANG_OK; + } + // Don't know the extension for that + return SLANG_E_NOT_FOUND; } default: break; } @@ -695,16 +698,7 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S { return appendCpuExtensionForKind(desc.kind, out); } - else - { - auto slice = _getPayloadExtension(desc.payload); - if (slice.getLength()) - { - out << slice; - return SLANG_OK; - } - } - + return SLANG_E_NOT_FOUND; } @@ -752,6 +746,12 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S return getBaseNameFromPath(desc, path); } +/* static */SlangResult ArtifactDescUtil::hasDefinedNameForDesc(const ArtifactDesc& desc) +{ + StringBuilder buf; + return SLANG_SUCCEEDED(appendDefaultExtension(desc, buf)); +} + /* static */SlangResult ArtifactDescUtil::calcNameForDesc(const ArtifactDesc& desc, const UnownedStringSlice& inBaseName, StringBuilder& outName) { UnownedStringSlice baseName(inBaseName); @@ -779,10 +779,18 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S // If there is an extension append it StringBuilder ext; - if (SLANG_SUCCEEDED(appendDefaultExtension(desc, ext)) && ext.getLength() > 0) + if (SLANG_SUCCEEDED(appendDefaultExtension(desc, ext))) + { + if (ext.getLength()) + { + outName.appendChar('.'); + outName.append(ext); + } + } + else { - outName.appendChar('.'); - outName.append(ext); + // If we can't determine the type we can output with .unknown + outName.append(toSlice(".unknown")); } return SLANG_OK; diff --git a/source/compiler-core/slang-artifact-desc-util.h b/source/compiler-core/slang-artifact-desc-util.h index 6c6c158f8..b700fa465 100644 --- a/source/compiler-core/slang-artifact-desc-util.h +++ b/source/compiler-core/slang-artifact-desc-util.h @@ -81,6 +81,9 @@ struct ArtifactDescUtil /// Given a desc and a baseName works out the the output file name static SlangResult calcNameForDesc(const ArtifactDesc& desc, const UnownedStringSlice& baseName, StringBuilder& outName); + /// Returns true if there is a defined name extension/type for this desc + static SlangResult hasDefinedNameForDesc(const ArtifactDesc& desc); + /// Given a target returns the ArtifactDesc static ArtifactDesc makeDescForCompileTarget(SlangCompileTarget target); diff --git a/source/compiler-core/slang-artifact-diagnostic-util.cpp b/source/compiler-core/slang-artifact-diagnostic-util.cpp index 3a2c64dce..38e5c5fd8 100644 --- a/source/compiler-core/slang-artifact-diagnostic-util.cpp +++ b/source/compiler-core/slang-artifact-diagnostic-util.cpp @@ -127,7 +127,7 @@ namespace Slang { String text(in); diagnostic.severity = ArtifactDiagnostic::Severity::Info; - diagnostic.text = SliceCaster::asTerminatedCharSlice(text); + diagnostic.text = SliceUtil::asTerminatedCharSlice(text); diagnostics->add(diagnostic); } diff --git a/source/compiler-core/slang-artifact-handler-impl.cpp b/source/compiler-core/slang-artifact-handler-impl.cpp index c8e7bf247..94e6fb6f7 100644 --- a/source/compiler-core/slang-artifact-handler-impl.cpp +++ b/source/compiler-core/slang-artifact-handler-impl.cpp @@ -187,7 +187,7 @@ SlangResult DefaultArtifactHandler::getOrCreateFileRepresentation(IArtifact* art // Now we need the appropriate name for this item ComPtr<ISlangBlob> pathBlob; - SLANG_RETURN_ON_FAIL(helper->calcArtifactPath(artifact->getDesc(), lockFile->getPath(), pathBlob.writeRef())); + SLANG_RETURN_ON_FAIL(helper->calcArtifactPath(artifact, lockFile->getPath(), pathBlob.writeRef())); const auto path = StringUtil::getSlice(pathBlob); diff --git a/source/compiler-core/slang-artifact-helper.cpp b/source/compiler-core/slang-artifact-helper.cpp index d24d08909..27965b0cc 100644 --- a/source/compiler-core/slang-artifact-helper.cpp +++ b/source/compiler-core/slang-artifact-helper.cpp @@ -7,6 +7,8 @@ #include "slang-artifact-desc-util.h" #include "slang-artifact-util.h" +#include "../compiler-core/slang-slice-allocator.h" + #include "../core/slang-castable-list-impl.h" #include "../core/slang-castable-util.h" @@ -108,12 +110,21 @@ SlangResult DefaultArtifactHelper::createLockFile(const char* inNameBase, ISlang return SLANG_OK; } -SlangResult DefaultArtifactHelper::calcArtifactPath(const ArtifactDesc& desc, const char* inBasePath, ISlangBlob** outPath) +SlangResult DefaultArtifactHelper::calcArtifactDescPath(const ArtifactDesc& desc, const char* inBasePath, ISlangBlob** outPath) { UnownedStringSlice basePath(inBasePath); StringBuilder path; SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcPathForDesc(desc, basePath, path)); - *outPath = StringBlob::create(path).detach(); + *outPath = StringBlob::moveCreate(path).detach(); + return SLANG_OK; +} + +SlangResult DefaultArtifactHelper::calcArtifactPath(IArtifact* artifact, const char* inBasePath, ISlangBlob** outPath) +{ + UnownedStringSlice basePath(inBasePath); + StringBuilder path; + SLANG_RETURN_ON_FAIL(ArtifactUtil::calcPath(artifact, basePath, path)); + *outPath = StringBlob::moveCreate(path).detach(); return SLANG_OK; } @@ -140,4 +151,24 @@ SlangResult DefaultArtifactHelper::createCastableList(const Guid& guid, ICastabl return SLANG_E_NO_INTERFACE; } +SlangResult DefaultArtifactHelper::createFileArtifactRepresentation( + IFileArtifactRepresentation::Kind kind, const CharSlice& path, IFileArtifactRepresentation* lockFile, ISlangMutableFileSystem* fileSystem, IFileArtifactRepresentation** outRep) +{ + *outRep = FileArtifactRepresentation::create(kind, asStringSlice(path), lockFile, fileSystem).detach(); + return SLANG_OK; +} + + +SlangResult DefaultArtifactHelper::createFileArtifact(const ArtifactDesc& desc, const CharSlice& path, IArtifact** outArtifact) +{ + auto artifact = Artifact::create(desc); + + auto fileRep = new FileArtifactRepresentation(IFileArtifactRepresentation::Kind::Reference, asStringSlice(path), nullptr, nullptr); + + artifact->addRepresentation(fileRep); + + *outArtifact = artifact.detach(); + return SLANG_OK; +} + } // namespace Slang diff --git a/source/compiler-core/slang-artifact-helper.h b/source/compiler-core/slang-artifact-helper.h index 22c1b5c99..208c80bd5 100644 --- a/source/compiler-core/slang-artifact-helper.h +++ b/source/compiler-core/slang-artifact-helper.h @@ -44,7 +44,10 @@ class IArtifactHelper : public ICastable virtual SLANG_NO_THROW SlangResult SLANG_MCALL createLockFile(const char* nameBase, ISlangMutableFileSystem* fileSystem, IFileArtifactRepresentation** outLockFile) = 0; /// Given a desc and a basePath returns a suitable name - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactPath(const ArtifactDesc& desc, const char* basePath, ISlangBlob** outPath) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactDescPath(const ArtifactDesc& desc, const char* basePath, ISlangBlob** outPath) = 0; + + /// Given an artifact and a basePath returns a suitable name + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactPath(IArtifact* , const char* basePath, ISlangBlob** outPath) = 0; /// Given a compile target return the equivalent desc virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL makeDescForCompileTarget(SlangCompileTarget target) = 0; @@ -52,8 +55,15 @@ class IArtifactHelper : public ICastable /// Given an interface returns as a castable interface. This might just cast unk into ICastable, or wrap it such that it uses the castable interface virtual SLANG_NO_THROW void SLANG_MCALL getCastable(ISlangUnknown* unk, ICastable** outCastable) = 0; + /// Create a file rep + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createFileArtifactRepresentation( + IFileArtifactRepresentation::Kind kind, const CharSlice& path, IFileArtifactRepresentation* lockFile, ISlangMutableFileSystem* fileSystem, IFileArtifactRepresentation** outRep) = 0; + /// Create an empty ICastableList virtual SLANG_NO_THROW SlangResult SLANG_MCALL createCastableList(const Guid& guid, ICastableList** outList) = 0; + + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createFileArtifact(const ArtifactDesc& desc, const CharSlice& slice, IArtifact** outArtifact) = 0; }; class DefaultArtifactHelper : public IArtifactHelper @@ -85,7 +95,9 @@ public: virtual SLANG_NO_THROW SlangResult SLANG_MCALL createLockFile(const char* nameBase, ISlangMutableFileSystem* fileSystem, IFileArtifactRepresentation** outLockFile) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactPath(const ArtifactDesc& desc, const char* basePath, ISlangBlob** outPath) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactDescPath(const ArtifactDesc& desc, const char* basePath, ISlangBlob** outPath) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactPath(IArtifact*, const char* basePath, ISlangBlob** outPath) SLANG_OVERRIDE; virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL makeDescForCompileTarget(SlangCompileTarget target) SLANG_OVERRIDE; @@ -93,6 +105,11 @@ public: virtual SLANG_NO_THROW SlangResult SLANG_MCALL createCastableList(const Guid& guid, ICastableList** outList) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createFileArtifactRepresentation( + IFileArtifactRepresentation::Kind kind, const CharSlice& path, IFileArtifactRepresentation* lockFile, ISlangMutableFileSystem* fileSystem, IFileArtifactRepresentation** outRep) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createFileArtifact(const ArtifactDesc& desc, const CharSlice& slice, IArtifact** outArtifact) SLANG_OVERRIDE; + static IArtifactHelper* getSingleton() { return &g_singleton; } protected: diff --git a/source/compiler-core/slang-artifact-util.cpp b/source/compiler-core/slang-artifact-util.cpp index 20a729cfa..047e87db0 100644 --- a/source/compiler-core/slang-artifact-util.cpp +++ b/source/compiler-core/slang-artifact-util.cpp @@ -120,4 +120,143 @@ namespace Slang { return String(); } +/* static */IFileArtifactRepresentation* ArtifactUtil::findFileSystemTemporaryFile(IArtifact* artifact) +{ + if (auto fileRep = findFileSystemFile(artifact)) + { + return fileRep->getLockFile() ? fileRep : nullptr; + } + return nullptr; +} + +/* static */IFileArtifactRepresentation* ArtifactUtil::findFileSystemFile(IArtifact* artifact) +{ + for (auto rep : artifact->getRepresentations()) + { + if (auto fileSystemRep = as<IFileArtifactRepresentation>(rep)) + { + if (fileSystemRep->getFileSystem() == nullptr) + { + return fileSystemRep; + } + } + } + return nullptr; +} + +/* static */IFileArtifactRepresentation* ArtifactUtil::findFileSystemPrimaryFile(IArtifact* artifact) +{ + for (auto rep : artifact->getRepresentations()) + { + if (auto fileRep = as<IFileArtifactRepresentation>(rep)) + { + // If it has a file system it's not on OS + // If it has a lock file it can be assumed to be temporary + if (fileRep->getFileSystem() != nullptr || + fileRep->getLockFile()) + { + continue; + } + + // If it's a file that is persistant it will just be a reference to a pre-existing file + const auto kind = fileRep->getKind(); + if (kind != IFileArtifactRepresentation::Kind::Reference) + { + continue; + } + + return fileRep; + } + } + return nullptr; +} + +UnownedStringSlice ArtifactUtil::findPath(IArtifact* artifact) +{ + // If a name is set we'll just use that + { + const char* name = artifact->getName(); + if (name && name[0] != 0) + { + return UnownedStringSlice(name); + } + } + + // Find the *first* file rep and use it's path. + // This may not be the file on the file system - but is probably the path/name the user most associated with the artifact + if (auto fileRep = findRepresentation<IFileArtifactRepresentation>(artifact)) + { + // If there isn't a lock file it is + if (fileRep->getLockFile() == nullptr) + { + return UnownedStringSlice(fileRep->getPath()); + } + } + + return UnownedStringSlice(); +} + +/* static */UnownedStringSlice ArtifactUtil::inferExtension(IArtifact* artifact) +{ + for (auto rep :artifact->getRepresentations()) + { + if (auto fileRep = as<IFileArtifactRepresentation>(rep)) + { + const char* path = fileRep->getPath(); + auto ext = Path::getPathExt(UnownedStringSlice(path)); + if (ext.getLength()) + { + return ext; + } + } + } + + // Okay lets see if the name has an extension + return Path::getPathExt(UnownedStringSlice(artifact->getName())); +} + +static SlangResult _calcInferred(IArtifact* artifact, const UnownedStringSlice& basePath, StringBuilder& outPath) +{ + auto ext = ArtifactUtil::inferExtension(artifact); + + // If no extension was determined by inferring, go with unknown + if (ext.begin() == nullptr) + { + ext = toSlice("unknown"); + } + + outPath.Clear(); + outPath.append(basePath); + if (ext.getLength()) + { + outPath.appendChar('.'); + outPath.append(ext); + } + return SLANG_OK; +} + +/* static */SlangResult ArtifactUtil::calcPath(IArtifact* artifact, const UnownedStringSlice& basePath, StringBuilder& outPath) +{ + if (ArtifactDescUtil::hasDefinedNameForDesc(artifact->getDesc())) + { + return ArtifactDescUtil::calcPathForDesc(artifact->getDesc(), basePath, outPath); + } + else + { + return _calcInferred(artifact, basePath, outPath); + } +} + +/* static */SlangResult ArtifactUtil::calcName(IArtifact* artifact, const UnownedStringSlice& baseName, StringBuilder& outName) +{ + if (ArtifactDescUtil::hasDefinedNameForDesc(artifact->getDesc())) + { + return ArtifactDescUtil::calcNameForDesc(artifact->getDesc(), baseName, outName); + } + else + { + return _calcInferred(artifact, baseName, outName); + } +} + } // namespace Slang diff --git a/source/compiler-core/slang-artifact-util.h b/source/compiler-core/slang-artifact-util.h index dc370b557..16687d6a9 100644 --- a/source/compiler-core/slang-artifact-util.h +++ b/source/compiler-core/slang-artifact-util.h @@ -37,6 +37,31 @@ struct ArtifactUtil static bool isSignificant(IArtifact* artifact, void* data = nullptr); /// Find a significant artifact static IArtifact* findSignificant(IArtifact* artifact); + + /// Returns the rep of the artifact that contains a temporary (identified by having a lock) on + /// the OS file system + static IFileArtifactRepresentation* findFileSystemTemporaryFile(IArtifact* artifact); + /// Returns true if the artifact contains a file on the OS file system + static IFileArtifactRepresentation* findFileSystemFile(IArtifact* artifact); + /// Returns the rep of a file system file which *isn't* temporary + static IFileArtifactRepresentation* findFileSystemPrimaryFile(IArtifact* artifact); + + /// Find the path/name associated with the artifact. + /// The path is *not* necessarily the path on the file system. The order of search is + /// * If the artifact has a name return that + /// * If the artifact has a IFileArtifactRepresentation (that isn't temporary) return it's path + /// * If not found return an empty slice + static UnownedStringSlice findPath(IArtifact* artifact); + + /// Sometimes we have artifacts that don't specify a payload type - perhaps because they can be interpretted in different ways + /// This function uses the associated name and file representations to infer a extension. If none is found returns an empty slice. + static UnownedStringSlice inferExtension(IArtifact* artifact); + + /// Given a desc and a basePath returns a suitable path for a entity of specified desc + static SlangResult calcPath(IArtifact* artifact, const UnownedStringSlice& basePath, StringBuilder& outPath); + + /// Given a desc and a baseName works out the the output file name + static SlangResult calcName(IArtifact* artifact, const UnownedStringSlice& baseName, StringBuilder& outName); }; } // namespace Slang diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index f134d77f5..f665757bb 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -66,35 +66,6 @@ void* DownstreamCompilerBase::getObject(const Guid& guid) /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompiler !!!!!!!!!!!!!!!!!!!!!!*/ -static bool _isContentsInFile(const DownstreamCompileOptions& options) -{ - if (options.sourceContentsPath.count <= 0) - { - return false; - } - - // We can see if we can load it - if (File::exists(asStringSlice(options.sourceContentsPath))) - { - // Here we look for the file on the regular file system (as opposed to using the - // ISlangFileSystem. This is unfortunate but necessary - because when we call out - // to the compiler all it is able to (currently) see are files on the file system. - // - // Note that it could be coincidence that the filesystem has a file that's identical in - // contents/name. That being the case though, any includes wouldn't work for a generated - // file either from some specialized ISlangFileSystem, so this is probably as good as it gets - // until we can integrate directly to a C/C++ compiler through say a shared library where we can control - // file system access. - String readContents; - - if (SLANG_SUCCEEDED(File::readAllText(asStringSlice(options.sourceContentsPath), readContents))) - { - return asStringSlice(options.sourceContents) == readContents.getUnownedSlice(); - } - } - return false; -} - SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptions, IArtifact** outArtifact) { // Copy the command line options @@ -114,67 +85,26 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio ComPtr<IFileArtifactRepresentation> lockFile; // The allocator can be used for items that are not kept in scope by the options - SliceAllocator allocator; - - // We may need to produce a new list of source files, use this list to hold them. - List<TerminatedCharSlice> sourceFiles; - - // Copy over all of the source files that are explicitly set, to sourceFiles which well use - // to hold the actual list of sourceFiles required. - sourceFiles.addRange(inOptions.sourceFiles.begin(), inOptions.sourceFiles.count); + String modulePath; - if (options.modulePath.count == 0 || options.sourceContents.count != 0) + // If no module path is set we will need to generate one + if (options.modulePath.count == 0) { - String modulePath = asString(options.modulePath); + // We could use the path to the source, or use the source name/paths as defined on the artifact + // For now we just go with a lock file based on "slang-generated". + SLANG_RETURN_ON_FAIL(helper->createLockFile("slang-generated", nullptr, lockFile.writeRef())); - // If there is no module path, generate one. - if (modulePath.getLength() == 0) - { - SLANG_RETURN_ON_FAIL(helper->createLockFile("slang-generated", nullptr, lockFile.writeRef())); + auto lockArtifact = Artifact::create(ArtifactDesc::make(ArtifactKind::Base, ArtifactPayload::Lock, ArtifactStyle::None)); + lockArtifact->addRepresentation(lockFile); - auto lockArtifact = Artifact::create(ArtifactDesc::make(ArtifactKind::Base, ArtifactPayload::Lock, ArtifactStyle::None)); - lockArtifact->addRepresentation(lockFile); + artifactList->add(lockArtifact); - artifactList->add(lockArtifact); + // Add the source files such that they can exist + modulePath = lockFile->getPath(); - modulePath = lockFile->getPath(); - options.modulePath = allocator.allocate(modulePath); - } - - if (_isContentsInFile(options)) - { - sourceFiles.add(options.sourceContentsPath); - } - else - { - // Work out the ArtifactDesc for the source language - const auto sourceDesc = ArtifactDescUtil::makeDescForSourceLanguage(options.sourceLanguage); - - // Work out the name for the source - StringBuilder compileSourcePath; - SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcPathForDesc(sourceDesc, (modulePath + "-src").getUnownedSlice(), compileSourcePath)); - - // Write it out - SLANG_RETURN_ON_FAIL(File::writeAllText(compileSourcePath, asStringSlice(options.sourceContents))); - - // Create the reference to the file - auto fileRep = FileArtifactRepresentation::create(IFileArtifactRepresentation::Kind::Owned, compileSourcePath.getUnownedSlice(), lockFile, nullptr); - auto fileArtifact = ArtifactUtil::createArtifact(ArtifactDescUtil::makeDescForSourceLanguage(options.sourceLanguage)); - fileArtifact->addRepresentation(fileRep); - - artifactList->add(fileArtifact); - - // Add it as a source file - sourceFiles.add(allocator.allocate(compileSourcePath)); - } - - // There is no source contents - options.sourceContents = TerminatedCharSlice(); - options.sourceContentsPath = TerminatedCharSlice(); + options.modulePath = SliceUtil::asTerminatedCharSlice(modulePath); } - options.sourceFiles = SliceCaster::asSlice(sourceFiles); - // Append command line args to the end of cmdLine using the target specific function for the specified options SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); @@ -255,6 +185,15 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio } } + // Add all of the source artifacts, that are temporary on the file system, such that they can stay in scope for debugging + for (auto sourceArtifact : options.sourceArtifacts) + { + if (ArtifactUtil::findFileSystemTemporaryFile(sourceArtifact) && sourceArtifact->exists()) + { + artifactList->add(sourceArtifact); + } + } + // Create the result artifact auto artifact = ArtifactUtil::createArtifact(targetDesc); diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h index 9fea5cb05..a9ef56221 100644 --- a/source/compiler-core/slang-downstream-compiler.h +++ b/source/compiler-core/slang-downstream-compiler.h @@ -123,14 +123,8 @@ struct DownstreamCompileOptions Slice<Define> defines; - /// The contents of the source to compile. This can be empty is sourceFiles is set. - /// If the compiler is a commandLine file this source will be written to a temporary file. - TerminatedCharSlice sourceContents; - /// 'Path' that the contents originated from. NOTE! This is for reporting only and doesn't have to exist on file system - TerminatedCharSlice sourceContentsPath; - - /// The names/paths of source to compile. This can be empty if sourceContents is set. - Slice<TerminatedCharSlice> sourceFiles; + /// The source artifacts + Slice<IArtifact*> sourceArtifacts; Slice<TerminatedCharSlice> includePaths; Slice<TerminatedCharSlice> libraryPaths; diff --git a/source/compiler-core/slang-downstream-dep1.cpp b/source/compiler-core/slang-downstream-dep1.cpp index ac66b4502..c62fc77fc 100644 --- a/source/compiler-core/slang-downstream-dep1.cpp +++ b/source/compiler-core/slang-downstream-dep1.cpp @@ -6,6 +6,7 @@ #include "slang-artifact-desc-util.h" #include "../core/slang-castable-util.h" +#include "../core/slang-string-util.h" #include "slang-slice-allocator.h" @@ -97,6 +98,14 @@ DownstreamCompilerAdapter_Dep1::DownstreamCompilerAdapter_Dep1(DownstreamCompile } SlangResult DownstreamCompilerAdapter_Dep1::compile(const CompileOptions& inOptions, IArtifact** outArtifact) { + // Currently this only for llvm, so we'll just ignore other scenarios + if (inOptions.sourceArtifacts.count != 1) + { + return SLANG_FAIL; + } + + IArtifact* sourceArtifact = inOptions.sourceArtifacts[0]; + typedef DownstreamCompileOptions_Dep1::SomeEnum SomeEnum; // Convert to the Deps1 compile options @@ -126,15 +135,16 @@ SlangResult DownstreamCompilerAdapter_Dep1::compile(const CompileOptions& inOpti options.defines.add(dst); } - options.sourceContents = asStringSlice(inOptions.sourceContents); - options.sourceContentsPath = asStringSlice(inOptions.sourceContentsPath); - - options.sourceFiles = SliceConverter::toList(inOptions.sourceFiles); + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::Yes, blob.writeRef())); + + options.sourceContents = StringUtil::getString(blob); + options.sourceContentsPath = ArtifactUtil::findPath(sourceArtifact); - options.includePaths = SliceConverter::toList(inOptions.includePaths); - options.libraryPaths = SliceConverter::toList(inOptions.libraryPaths); + options.includePaths = SliceUtil::toList(inOptions.includePaths); + options.libraryPaths = SliceUtil::toList(inOptions.libraryPaths); - options.libraries = SliceConverter::toComPtrList(inOptions.libraries); + options.libraries = SliceUtil::toComPtrList(inOptions.libraries); for (auto& src : inOptions.requiredCapabilityVersions) { @@ -155,7 +165,7 @@ SlangResult DownstreamCompilerAdapter_Dep1::compile(const CompileOptions& inOpti options.stage = inOptions.stage; - options.compilerSpecificArguments = SliceConverter::toList(inOptions.compilerSpecificArguments); + options.compilerSpecificArguments = SliceUtil::toList(inOptions.compilerSpecificArguments); options.fileSystemExt = inOptions.fileSystemExt; options.sourceManager = inOptions.sourceManager; @@ -163,8 +173,6 @@ SlangResult DownstreamCompilerAdapter_Dep1::compile(const CompileOptions& inOpti RefPtr<DownstreamCompileResult_Dep1> result; SLANG_RETURN_ON_FAIL(m_dep->compile(options, result)); - typedef SliceCaster Caster; - ComPtr<IArtifact> artifact = ArtifactUtil::createArtifactForCompileTarget(options.targetType); // Convert the diagnostics @@ -173,7 +181,7 @@ SlangResult DownstreamCompilerAdapter_Dep1::compile(const CompileOptions& inOpti const DownstreamDiagnostics_Dep1* srcDiagnostics = &result->getDiagnostics(); dstDiagnostics->setResult(srcDiagnostics->result); - dstDiagnostics->setRaw(Caster::asCharSlice(srcDiagnostics->rawDiagnostics)); + dstDiagnostics->setRaw(SliceUtil::asCharSlice(srcDiagnostics->rawDiagnostics)); for (const auto& srcDiagnostic : srcDiagnostics->diagnostics) { @@ -182,11 +190,14 @@ SlangResult DownstreamCompilerAdapter_Dep1::compile(const CompileOptions& inOpti dstDiagnostic.severity = ArtifactDiagnostic::Severity(srcDiagnostic.severity); dstDiagnostic.stage = ArtifactDiagnostic::Stage(srcDiagnostic.stage); - dstDiagnostic.code = Caster::asTerminatedCharSlice(srcDiagnostic.code); - dstDiagnostic.text = Caster::asTerminatedCharSlice(srcDiagnostic.text); - dstDiagnostic.filePath = Caster::asTerminatedCharSlice(srcDiagnostic.filePath); + dstDiagnostic.code = SliceUtil::asTerminatedCharSlice(srcDiagnostic.code); + dstDiagnostic.text = SliceUtil::asTerminatedCharSlice(srcDiagnostic.text); + dstDiagnostic.filePath = SliceUtil::asTerminatedCharSlice(srcDiagnostic.filePath); dstDiagnostic.location.line = srcDiagnostic.fileLine; + + // Add the diagnostic + dstDiagnostics->add(dstDiagnostic); } artifact->addAssociated(dstDiagnostics); diff --git a/source/compiler-core/slang-dxc-compiler.cpp b/source/compiler-core/slang-dxc-compiler.cpp index 6aa065afd..03ad868a8 100644 --- a/source/compiler-core/slang-dxc-compiler.cpp +++ b/source/compiler-core/slang-dxc-compiler.cpp @@ -278,12 +278,14 @@ static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, IArtif SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, IArtifact** outArtifact) { - // This compiler doesn't read files, they should be read externally and stored in sourceContents/sourceContentsPath - if (options.sourceFiles.count > 0) + // This compiler can only deal with a single artifact + if (options.sourceArtifacts.count != 1) { return SLANG_FAIL; } + IArtifact* sourceArtifact = options.sourceArtifacts[0]; + if (options.sourceLanguage != SLANG_SOURCE_LANGUAGE_HLSL || options.targetType != SLANG_DXIL) { SLANG_ASSERT(!"Can only compile HLSL to DXIL"); @@ -311,13 +313,14 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, IArtif ComPtr<IDxcLibrary> dxcLibrary; SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcLibrary, __uuidof(dxcLibrary), (LPVOID*)dxcLibrary.writeRef())); - const auto& hlslSource = options.sourceContents; + ComPtr<ISlangBlob> sourceBlob; + SLANG_RETURN_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::Yes, sourceBlob.writeRef())); // Create blob from the string ComPtr<IDxcBlobEncoding> dxcSourceBlob; SLANG_RETURN_ON_FAIL(dxcLibrary->CreateBlobWithEncodingFromPinned( - (LPBYTE)hlslSource.data, - (UINT32)hlslSource.count, + (LPBYTE)sourceBlob->getBufferPointer(), + (UINT32)sourceBlob->getBufferSize(), 0, dxcSourceBlob.writeRef())); @@ -432,13 +435,14 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, IArtif searchDirectories.searchDirectories.add(asString(includePath)); } - OSString sourcePath = asString(options.sourceContentsPath).toWString(); + String sourcePath = ArtifactUtil::findPath(sourceArtifact); + OSString wideSourcePath = sourcePath.toWString(); DxcIncludeHandler includeHandler(&searchDirectories, options.fileSystemExt, options.sourceManager); ComPtr<IDxcOperationResult> dxcResult; SLANG_RETURN_ON_FAIL(dxcCompiler->Compile(dxcSourceBlob, - sourcePath.begin(), + wideSourcePath.begin(), wideEntryPointName.begin(), wideProfileName.begin(), args.getBuffer(), @@ -480,9 +484,9 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, IArtif { name = Path::getFileNameWithoutExt(asString(options.modulePath)); } - else if (options.sourceContentsPath.count) + else if (sourcePath.getLength()) { - name = Path::getFileNameWithoutExt(asString(options.sourceContentsPath)); + name = Path::getFileNameWithoutExt(sourcePath); } // Add the blob with name diff --git a/source/compiler-core/slang-fxc-compiler.cpp b/source/compiler-core/slang-fxc-compiler.cpp index 03eaa8e34..1706f0fb0 100644 --- a/source/compiler-core/slang-fxc-compiler.cpp +++ b/source/compiler-core/slang-fxc-compiler.cpp @@ -182,12 +182,14 @@ static SlangResult _parseDiagnosticLine(SliceAllocator& allocator, const Unowned SlangResult FXCDownstreamCompiler::compile(const CompileOptions& options, IArtifact** outArtifact) { - // This compiler doesn't read files, they should be read externally and stored in sourceContents/sourceContentsPath - if (options.sourceFiles.count > 0) + // This compiler can only deal with a single source artifact + if (options.sourceArtifacts.count != 1) { return SLANG_FAIL; } + IArtifact* sourceArtifact = options.sourceArtifacts[0]; + if (options.sourceLanguage != SLANG_SOURCE_LANGUAGE_HLSL || options.targetType != SLANG_DXBC) { SLANG_ASSERT(!"Can only compile HLSL to DXBC"); @@ -207,15 +209,18 @@ SlangResult FXCDownstreamCompiler::compile(const CompileOptions& options, IArtif searchDirectories.searchDirectories.add(asString(includePath)); } + const auto sourcePath = ArtifactUtil::findPath(sourceArtifact); + // Use the default fileSystemExt is not set ID3DInclude* includeHandler = nullptr; FxcIncludeHandler fxcIncludeHandlerStorage(&searchDirectories, options.fileSystemExt, options.sourceManager); if (options.fileSystemExt) { - if (options.sourceContentsPath.count > 0) + + if (sourcePath.getLength() > 0) { - fxcIncludeHandlerStorage.m_rootPathInfo = PathInfo::makePath(asString(options.sourceContentsPath)); + fxcIncludeHandlerStorage.m_rootPathInfo = PathInfo::makePath(sourcePath); } includeHandler = &fxcIncludeHandlerStorage; } @@ -274,12 +279,15 @@ SlangResult FXCDownstreamCompiler::compile(const CompileOptions& options, IArtif break; } + ComPtr<ISlangBlob> sourceBlob; + SLANG_RETURN_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::Yes, sourceBlob.writeRef())); + ComPtr<ID3DBlob> codeBlob; ComPtr<ID3DBlob> diagnosticsBlob; HRESULT hr = m_compile( - options.sourceContents.begin(), - options.sourceContents.count, - options.sourceContentsPath, + sourceBlob->getBufferPointer(), + sourceBlob->getBufferSize(), + String(sourcePath).getBuffer(), dxMacros, includeHandler, options.entryPointName, diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index 7bbde64c4..8851477d7 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -356,7 +356,7 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS SliceAllocator allocator; diagnostics->reset(); - diagnostics->setRaw(SliceCaster::asCharSlice(exeRes.standardError)); + diagnostics->setRaw(SliceUtil::asCharSlice(exeRes.standardError)); // We hold in workDiagnostics so as it is more convenient to append to the last with a continuation // also means we don't hold the allocations of building up continuations, just the results when finally allocated at the end @@ -456,7 +456,6 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS /* static */SlangResult GCCDownstreamCompilerUtil::calcArgs(const CompileOptions& options, CommandLine& cmdLine) { - SLANG_ASSERT(options.sourceContents.count == 0); SLANG_ASSERT(options.modulePath.count); PlatformKind platformKind = (options.platform == PlatformKind::Unknown) ? PlatformUtil::getPlatformKind() : options.platform; @@ -613,10 +612,15 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS } } - // Files to compile - for (const auto& sourceFile : options.sourceFiles) + // Files to compile, need to be on the file system. + for (IArtifact* sourceArtifact : options.sourceArtifacts) { - cmdLine.addArg(asString(sourceFile)); + ComPtr<IFileArtifactRepresentation> fileRep; + + // TODO(JS): + // Do we want to keep the file on the file system? It's probably reasonable to do so. + SLANG_RETURN_ON_FAIL(sourceArtifact->requireFile(ArtifactKeep::Yes, nullptr, fileRep.writeRef())); + cmdLine.addArg(fileRep->getPath()); } // Add the library paths diff --git a/source/compiler-core/slang-glslang-compiler.cpp b/source/compiler-core/slang-glslang-compiler.cpp index a896e4278..d6ae59690 100644 --- a/source/compiler-core/slang-glslang-compiler.cpp +++ b/source/compiler-core/slang-glslang-compiler.cpp @@ -127,12 +127,14 @@ static SlangResult _parseDiagnosticLine(SliceAllocator& allocator, const Unowned SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& options, IArtifact** outArtifact) { - // This compiler doesn't read files, they should be read externally and stored in sourceContents/sourceContentsPath - if (options.sourceFiles.count > 0) + // This compiler can only handle a single artifact + if (options.sourceArtifacts.count != 1) { return SLANG_FAIL; } + IArtifact* sourceArtifact = options.sourceArtifacts[0]; + if (options.sourceLanguage != SLANG_SOURCE_LANGUAGE_GLSL || options.targetType != SLANG_SPIRV) { SLANG_ASSERT(!"Can only compile GLSL to SPIR-V"); @@ -150,18 +152,23 @@ SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& options, IA ((List<uint8_t>*)userData)->addRange((uint8_t*)data, size); }; - + ComPtr<ISlangBlob> sourceBlob; + SLANG_RETURN_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::Yes, sourceBlob.writeRef())); + + String sourcePath = ArtifactUtil::findPath(sourceArtifact); + glslang_CompileRequest_1_1 request; memset(&request, 0, sizeof(request)); request.sizeInBytes = sizeof(request); request.action = GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV; - request.sourcePath = options.sourceContentsPath; + request.sourcePath = sourcePath.getBuffer(); request.slangStage = options.stage; - request.inputBegin = options.sourceContents.begin(); - request.inputEnd = options.sourceContents.end(); + const char* inputBegin = (const char*)sourceBlob->getBufferPointer(); + request.inputBegin = inputBegin; + request.inputEnd = inputBegin + sourceBlob->getBufferSize(); // Find the SPIR-V version if set SemanticVersion spirvVersion; @@ -201,7 +208,7 @@ SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& options, IA if (SLANG_FAILED(invokeResult)) { - diagnostics->setRaw(SliceCaster::asCharSlice(diagnosticOutput)); + diagnostics->setRaw(SliceUtil::asCharSlice(diagnosticOutput)); SliceAllocator allocator; diff --git a/source/compiler-core/slang-include-system.cpp b/source/compiler-core/slang-include-system.cpp index 891d376f6..455ecde2b 100644 --- a/source/compiler-core/slang-include-system.cpp +++ b/source/compiler-core/slang-include-system.cpp @@ -4,9 +4,22 @@ #include "../core/slang-io.h" #include "../core/slang-string-util.h" +#include "../core/slang-file-system.h" + +#include "slang-slice-allocator.h" +#include "slang-artifact-impl.h" +#include "slang-artifact-representation-impl.h" + namespace Slang { +IncludeSystem::IncludeSystem(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager) : + m_searchDirectories(searchDirectories), + m_fileSystemExt(fileSystemExt), + m_sourceManager(sourceManager) +{ +} + SlangResult IncludeSystem::findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& outPathInfo) { String combinedPath; @@ -119,6 +132,8 @@ SlangResult IncludeSystem::loadFile(const PathInfo& pathInfo, ComPtr<ISlangBlob> sourceFile = m_sourceManager->createSourceFileWithBlob(pathInfo, foundSourceBlob); m_sourceManager->addSourceFile(pathInfo.uniqueIdentity, sourceFile); + sourceFile->maybeAddArtifact(m_fileSystemExt); + outBlob = foundSourceBlob; return SLANG_OK; } @@ -137,6 +152,8 @@ SlangResult IncludeSystem::loadFile(const PathInfo& pathInfo, ComPtr<ISlangBlob> } sourceFile->setContents(foundSourceBlob); + sourceFile->maybeAddArtifact(m_fileSystemExt); + outBlob = foundSourceBlob; return SLANG_OK; } diff --git a/source/compiler-core/slang-include-system.h b/source/compiler-core/slang-include-system.h index 1fc8eac6e..108c4901b 100644 --- a/source/compiler-core/slang-include-system.h +++ b/source/compiler-core/slang-include-system.h @@ -33,13 +33,6 @@ struct SearchDirectoryList /* A helper class that builds basic include handling on top of searchDirectories/fileSystemExt and optionally a sourceManager */ struct IncludeSystem { - IncludeSystem(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager = nullptr) : - m_searchDirectories(searchDirectories), - m_fileSystemExt(fileSystemExt), - m_sourceManager(sourceManager) - { - } - SlangResult findFile(const String& pathToInclude, const String& pathIncludedFrom, PathInfo& outPathInfo); SlangResult findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& outPathInfo); String simplifyPath(const String& path); @@ -51,6 +44,9 @@ struct IncludeSystem ISlangFileSystemExt* getFileSystem() const { return m_fileSystemExt; } SourceManager* getSourceManager() const { return m_sourceManager; } + /// Ctor + IncludeSystem(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager = nullptr); + protected: SearchDirectoryList* m_searchDirectories; diff --git a/source/compiler-core/slang-nvrtc-compiler.cpp b/source/compiler-core/slang-nvrtc-compiler.cpp index 2c01dc633..1a112d67f 100644 --- a/source/compiler-core/slang-nvrtc-compiler.cpp +++ b/source/compiler-core/slang-nvrtc-compiler.cpp @@ -645,12 +645,14 @@ SlangResult NVRTCDownstreamCompiler::_maybeAddHalfSupport(const DownstreamCompil SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& options, IArtifact** outArtifact) { - // This compiler doesn't read files, they should be read externally and stored in sourceContents/sourceContentsPath - if (options.sourceFiles.count > 0) + // This compiler can only deal with a single artifact + if (options.sourceArtifacts.count != 1) { return SLANG_FAIL; } + IArtifact* sourceArtifact = options.sourceArtifacts[0]; + CommandLine cmdLine; switch (options.debugInfoType) @@ -819,9 +821,17 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& opt SLANG_ASSERT(headers.getCount() == headerIncludeNames.getCount()); + ComPtr<ISlangBlob> sourceBlob; + SLANG_RETURN_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::Yes, sourceBlob.writeRef())); + + auto sourcePath = ArtifactUtil::findPath(sourceArtifact); + + StringBuilder storage; + auto sourceContents = SliceUtil::toTerminatedCharSlice(storage, sourceBlob); + nvrtcProgram program = nullptr; - nvrtcResult res = m_nvrtcCreateProgram(&program, options.sourceContents, options.sourceContentsPath, - (int) headers.getCount(), + nvrtcResult res = m_nvrtcCreateProgram(&program, sourceContents, String(sourcePath).getBuffer(), + (int)headers.getCount(), headers.getBuffer(), headerIncludeNames.getBuffer()); if (res != NVRTC_SUCCESS) @@ -860,7 +870,7 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& opt SLANG_NVRTC_RETURN_ON_FAIL(m_nvrtcGetProgramLog(program, dst)); rawDiagnostics.appendInPlace(dst, Index(logSize)); - diagnostics->setRaw(SliceCaster::asCharSlice(rawDiagnostics)); + diagnostics->setRaw(SliceUtil::asCharSlice(rawDiagnostics)); } SliceAllocator allocator; diff --git a/source/compiler-core/slang-slice-allocator.cpp b/source/compiler-core/slang-slice-allocator.cpp index 9985f6b19..9a0620ced 100644 --- a/source/compiler-core/slang-slice-allocator.cpp +++ b/source/compiler-core/slang-slice-allocator.cpp @@ -5,9 +5,9 @@ namespace Slang { -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SliceConverter !!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SliceUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */ List<String> SliceConverter::toList(const Slice<TerminatedCharSlice>& in) +/* static */ List<String> SliceUtil::toList(const Slice<TerminatedCharSlice>& in) { List<String> list; const auto count = in.count; @@ -20,20 +20,21 @@ namespace Slang { return list; } -/* static */TerminatedCharSlice SliceConverter::toTerminatedCharSlice(SliceAllocator& allocator, ISlangBlob* blob) +/* static */const char* SliceUtil::getTerminated(ISlangBlob* blob, TerminatedCharSlice& outSlice) { const auto size = blob->getBufferSize(); - if (size == 0) { - return TerminatedCharSlice(); + outSlice = TerminatedCharSlice(); + return outSlice.begin(); } // If there is a 0 at the end byte, we are zero terminated const char* chars = (const char*)blob->getBufferPointer(); if (chars[size - 1] == 0) { - return TerminatedCharSlice(chars, Count(size - 1)); + outSlice = TerminatedCharSlice(chars, Count(size - 1)); + return chars; } // See if it has a castable interface @@ -42,15 +43,44 @@ namespace Slang { { if (castable->castAs(SlangTerminatedChars::getTypeGuid())) { - return TerminatedCharSlice(chars, Count(size)); + outSlice = TerminatedCharSlice(chars, Count(size)); + return chars; } } + return nullptr; +} + +/* static */TerminatedCharSlice SliceUtil::toTerminatedCharSlice(SliceAllocator& allocator, ISlangBlob* blob) +{ + TerminatedCharSlice slice; + if (SliceUtil::getTerminated(blob, slice)) + { + return slice; + } + const auto size = blob->getBufferSize(); // We are out of options, we just have to allocate with zero termination which allocateString does - auto dst = allocator.getArena().allocateString(chars, Count(size)); + auto dst = allocator.getArena().allocateString((const char*)blob->getBufferPointer(), Count(size)); return TerminatedCharSlice(dst, Count(size)); } +/* static */TerminatedCharSlice SliceUtil::toTerminatedCharSlice(StringBuilder& storage, ISlangBlob* blob) +{ + TerminatedCharSlice slice; + if (SliceUtil::getTerminated(blob, slice)) + { + return slice; + } + + const auto size = blob->getBufferSize(); + auto chars = (const char*)blob->getBufferPointer(); + + storage.Clear(); + storage.append(UnownedStringSlice(chars, size)); + + return TerminatedCharSlice(storage.getBuffer(), Count(size)); +} + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SliceAllocator !!!!!!!!!!!!!!!!!!!!!!!!!!! */ TerminatedCharSlice SliceAllocator::allocate(const char* in) diff --git a/source/compiler-core/slang-slice-allocator.h b/source/compiler-core/slang-slice-allocator.h index 41ed3943a..984ad32eb 100644 --- a/source/compiler-core/slang-slice-allocator.h +++ b/source/compiler-core/slang-slice-allocator.h @@ -10,43 +10,35 @@ namespace Slang { -/* -The reason to wrap in a struct rather than have as free functions is doing so will lead to compile time -errors with incorrect usage around temporaries. -*/ -struct SliceCaster + +struct SliceAllocator; + +struct SliceUtil { + /// Convert into a list of strings + static List<String> toList(const Slice<TerminatedCharSlice>& in); + + /// Gets a 0 terminated string from a blob. If not possible returns nullptr + static const char* getTerminated(ISlangBlob* blob, TerminatedCharSlice& outSlice); + + /// NOTE! the slice is only guarenteed to stay in scope whilst the blob does + static TerminatedCharSlice toTerminatedCharSlice(SliceAllocator& allocator, ISlangBlob* blob); + /// + static TerminatedCharSlice toTerminatedCharSlice(StringBuilder& storage, ISlangBlob* blob); + /// The slice will only be in scope whilst the string is static TerminatedCharSlice asTerminatedCharSlice(const String& in) { auto unowned = in.getUnownedSlice(); return TerminatedCharSlice(unowned.begin(), unowned.getLength()); } + /// Get string as a char slice static CharSlice asCharSlice(const String& in) { auto unowned = in.getUnownedSlice(); return CharSlice(unowned.begin(), unowned.getLength()); } template <typename T> - static Slice<T*> asSlice(const List<ComPtr<T>>& list) { return makeSlice((T*const*)list.getBuffer(), list.getCount()); } + static Slice<T*> asSlice(const List<ComPtr<T>>& list) { return makeSlice((T* const*)list.getBuffer(), list.getCount()); } /// Get a list as a slice template <typename T> static Slice<T> asSlice(const List<T>& list) { return Slice<T>(list.getBuffer(), list.getCount()); } -private: - /// We don't want to make a temporary list into a slice.. - template <typename T> - static Slice<T> asSlice(const List<T>&& list) = delete; - // We don't want temporaries to be 'asSliced' so disable - static TerminatedCharSlice asTerminatedCharSlice(const String&& in) = delete; - static CharSlice asCharSlice(const String&& in) = delete; -}; - -struct SliceAllocator; - -struct SliceConverter -{ - /// Convert into a list of strings - static List<String> toList(const Slice<TerminatedCharSlice>& in); - - /// NOTE! the slice is only guarenteed to stay in scope whilst the blob does - static TerminatedCharSlice toTerminatedCharSlice(SliceAllocator& allocator, ISlangBlob* blob); - template <typename T> static List<ComPtr<T>> toComPtrList(const Slice<T*>& in) { @@ -57,6 +49,20 @@ struct SliceConverter for (Index i = 0; i < in.count; ++i) list[i] = ComPtr<T>(in[i]); return list; } + +private: + + /* + A reason to wrap in a struct rather than have as free functions is doing so will lead to compile time + errors with incorrect usage around temporaries. + */ + + /// We don't want to make a temporary list into a slice.. + template <typename T> + static Slice<T> asSlice(const List<T>&& list) = delete; + // We don't want temporaries to be 'asSliced' so disable + static TerminatedCharSlice asTerminatedCharSlice(const String&& in) = delete; + static CharSlice asCharSlice(const String&& in) = delete; }; SLANG_FORCE_INLINE UnownedStringSlice asStringSlice(const CharSlice& slice) diff --git a/source/compiler-core/slang-source-loc.cpp b/source/compiler-core/slang-source-loc.cpp index f245d1e0c..c82636248 100644 --- a/source/compiler-core/slang-source-loc.cpp +++ b/source/compiler-core/slang-source-loc.cpp @@ -4,6 +4,9 @@ #include "../core/slang-string-util.h" #include "../core/slang-string-escape-util.h" +#include "slang-artifact-representation-impl.h" +#include "slang-artifact-impl.h" + namespace Slang { /* !!!!!!!!!!!!!!!!!!!!!!!!! SourceView !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -22,6 +25,20 @@ const String PathInfo::getMostUniqueIdentity() const } } +String PathInfo::getName() const +{ + switch (type) + { + case Type::Normal: + case Type::FromString: + case Type::FoundPath: + { + return foundPath; + } + } + return String(); +} + bool PathInfo::operator==(const ThisType& rhs) const { // They must be the same type @@ -415,6 +432,77 @@ String SourceFile::calcVerbosePath() const return m_pathInfo.foundPath; } +void SourceFile::maybeAddArtifact(ISlangFileSystemExt* ext) +{ + if (!m_contentBlob) + { + return; + } + + // If there already is an artifact, or we are not using OSFile system then + if (m_artifact) + { + // TODO(JS): + // Check if it has the blob or not + SLANG_ASSERT(m_contentBlob == findRepresentation<ISlangBlob>(m_artifact)); + return; + } + + // We don't know how the source will be used + m_artifact = Artifact::create(ArtifactDesc::make(ArtifactKind::Source, ArtifactPayload::Unknown, ArtifactStyle::Unknown)); + + // Add the blob as a representation. + m_artifact->addRepresentationUnknown(m_contentBlob); + + // If we have the file system see if we can set up a path too + if (ext) + { + const auto osPathKind = ext->getOSPathKind(); + + if (osPathKind != OSPathKind::None) + { + String path; + switch (osPathKind) + { + case OSPathKind::Canonical: + { + // Get the canonical path + ComPtr<ISlangBlob> canonicalPath; + if (SLANG_SUCCEEDED(ext->getCanonicalPath(getPathInfo().foundPath.getBuffer(), canonicalPath.writeRef()))) + { + path = StringUtil::getString(canonicalPath); + } + break; + } + case OSPathKind::Direct: + { + path = getPathInfo().foundPath; + break; + } + } + + if (path.getLength()) + { + // We can sanity check that this works + SlangPathType pathType; + if (SLANG_SUCCEEDED(ext->getPathType(path.getBuffer(), &pathType))) + { + // We can add a file representation + FileArtifactRepresentation* fileRep = new FileArtifactRepresentation(IFileArtifactRepresentation::Kind::Reference, path.getUnownedSlice(), nullptr, nullptr); + m_artifact->addRepresentation(fileRep); + } + } + } + } + + // Get the name + auto name = getPathInfo().getName(); + if (name.getLength()) + { + m_artifact->setName(name.getBuffer()); + } +} + /* !!!!!!!!!!!!!!!!!!!!!!!!! SourceManager !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ void SourceManager::initialize( diff --git a/source/compiler-core/slang-source-loc.h b/source/compiler-core/slang-source-loc.h index 24471f3b0..461f09e96 100644 --- a/source/compiler-core/slang-source-loc.h +++ b/source/compiler-core/slang-source-loc.h @@ -9,6 +9,8 @@ #include "../../slang-com-ptr.h" #include "../../slang.h" +#include "slang-artifact-representation.h" + namespace Slang { /** Overview: @@ -60,6 +62,8 @@ struct PathInfo SLANG_FORCE_INLINE bool hasFoundPath() const { return type == Type::Normal || type == Type::FoundPath || (type == Type::FromString && foundPath.getLength() > 0); } /// True if has a found path that has originated from a file (as opposed to string or some other origin) SLANG_FORCE_INLINE bool hasFileFoundPath() const { return (type == Type::Normal || type == Type::FoundPath) && foundPath.getLength() > 0; } + /// Get the 'name'/path of the item. Will return an empty string if not applicable or not set. + String getName() const; bool operator==(const ThisType& rhs) const; bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } @@ -232,11 +236,19 @@ public: /// Get path info const PathInfo& getPathInfo() const { return m_pathInfo; } + /// Get the (optional) assoicated artifact. Note its desc might be Source/Unknown + IArtifact* getArtifact() const { return m_artifact; } + /// Set the artifact + void setArtifact(IArtifact* artifact) { m_artifact = artifact; } + /// Set the content as a blob void setContents(ISlangBlob* blob); /// Set the content as a string void setContents(const String& content); + /// If artifact isn't defined will try and associate one. The pathInfo must be the one associated with the PathInfo + void maybeAddArtifact(ISlangFileSystemExt* ext); + /// Calculate a display path -> can canonicalize if necessary String calcVerbosePath() const; @@ -250,11 +262,13 @@ public: protected: - SourceManager* m_sourceManager; ///< The source manager this belongs to - PathInfo m_pathInfo; ///< The path The logical file path to report for locations inside this span. - ComPtr<ISlangBlob> m_contentBlob; ///< A blob that owns the storage for the file contents. If nullptr, there is no contents - UnownedStringSlice m_content; ///< The actual contents of the file. - size_t m_contentSize; ///< The size of the actual contents + SourceManager* m_sourceManager; ///< The source manager this belongs to + PathInfo m_pathInfo; ///< The path The logical file path to report for locations inside this span. + + ComPtr<IArtifact> m_artifact; ///< Optional artifact + ComPtr<ISlangBlob> m_contentBlob; ///< A blob that owns the storage for the file contents. If nullptr, there is no contents + UnownedStringSlice m_content; ///< The actual contents of the file. + size_t m_contentSize; ///< The size of the actual contents // In order to speed up lookup of line number information, // we will cache the starting offset of each line break in diff --git a/source/compiler-core/slang-visual-studio-compiler-util.cpp b/source/compiler-core/slang-visual-studio-compiler-util.cpp index c1fb89555..17fb96ee8 100644 --- a/source/compiler-core/slang-visual-studio-compiler-util.cpp +++ b/source/compiler-core/slang-visual-studio-compiler-util.cpp @@ -74,7 +74,6 @@ static void _addFile(const String& path, const ArtifactDesc& desc, IFileArtifact /* static */SlangResult VisualStudioCompilerUtil::calcArgs(const CompileOptions& options, CommandLine& cmdLine) { - SLANG_ASSERT(options.sourceContents.count == 0); SLANG_ASSERT(options.modulePath.count); // https://docs.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-alphabetically?view=vs-2019 @@ -236,12 +235,17 @@ static void _addFile(const String& path, const ArtifactDesc& desc, IFileArtifact // https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=vs-2019 // /Eha - Specifies the model of exception handling. (a, s, c, r are options) - // Files to compile - for (const auto& sourceFile : options.sourceFiles) + // Files to compile, need to be on the file system. + for (IArtifact* sourceArtifact : options.sourceArtifacts) { - cmdLine.addArg(asString(sourceFile)); - } + ComPtr<IFileArtifactRepresentation> fileRep; + // TODO(JS): + // Do we want to keep the file on the file system? It's probably reasonable to do so. + SLANG_RETURN_ON_FAIL(sourceArtifact->requireFile(ArtifactKeep::Yes, nullptr, fileRep.writeRef())); + cmdLine.addArg(fileRep->getPath()); + } + // Link options (parameters past /link go to linker) cmdLine.addArg("/link"); @@ -430,7 +434,7 @@ static SlangResult _parseVisualStudioLine(SliceAllocator& allocator, const Unown { diagnostics->reset(); - diagnostics->setRaw(SliceCaster::asTerminatedCharSlice(exeRes.standardOutput)); + diagnostics->setRaw(SliceUtil::asTerminatedCharSlice(exeRes.standardOutput)); SliceAllocator allocator; |
