Skip to content

Commit 3e74d39

Browse files
authored
Feature/include refactor (shader-slang#675)
* Refactor of path handling. * Added PathInfo * Changed ISlangFileSystem - such that has separate concepts of reading a file, getting a relative path and getting a canonical path * Added support for getting a canonical path for windows/linux * Made maps/testing around canonicalPaths * User output remains around 'foundPath' - which is the same as before * Small improvements around PathInfo * Added a type and make constructors to make clear the different 'path' uses * Fixed bug in findViewRecursively * Checking and reporting for ignored #pragma once. * Removed SLANG_PATH_TYPE_NONE as doesn't serve any useful purpose. * Improve comments in slang.h aroung ISlangFileSystem * Remove the need for <windows.h> in slang-io.cpp * Ran premake5. * Improvements and fixes around PathInfo. * Fix typo on linix GetCanonical * Make the ISlangFileSystem the same as before, and ISlangFileSystem contain the new methods. Internally it always uses the ISlangFileSystemExt, and will wrap a ISlangFileSystem with WrapFileSystem, if it is determined (via queryInterface) that it doesn't implement the full interface.
1 parent 204fb3c commit 3e74d39

27 files changed

+770
-242
lines changed

slang.h

+64-2
Original file line numberDiff line numberDiff line change
@@ -656,12 +656,16 @@ extern "C"
656656
Slang can make use of this interface whenever it would otherwise try to load files
657657
from disk, allowing applications to hook and/or override filesystem access from
658658
the compiler.
659+
660+
It is the responsibility of
661+
the caller of any method that returns a ISlangBlob to release the blob when it is no
662+
longer used (using 'release').
659663
*/
664+
660665
struct ISlangFileSystem : public ISlangUnknown
661666
{
662667
public:
663668
/** Load a file from `path` and return a blob of its contents
664-
665669
@param path The path to load from, as a null-terminated UTF-8 string.
666670
@param outBlob A destination pointer to receive the blob of the file contents.
667671
@returns A `SlangResult` to indicate success or failure in loading the file.
@@ -673,10 +677,68 @@ extern "C"
673677
*/
674678
virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(
675679
char const* path,
676-
ISlangBlob** outBlob) = 0;
680+
ISlangBlob** outBlob) = 0;
677681
};
678682
#define SLANG_UUID_ISlangFileSystem { 0x003A09FC, 0x3A4D, 0x4BA0, 0xAD, 0x60, 0x1F, 0xD8, 0x63, 0xA9, 0x15, 0xAB }
679683

684+
/* Type that identifies how a path should be interpreted */
685+
typedef unsigned int SlangPathType;
686+
enum
687+
{
688+
SLANG_PATH_TYPE_DIRECTORY, /**< Path specified specifies a directory. */
689+
SLANG_PATH_TYPE_FILE, /**< Path specified is to a file. */
690+
};
691+
692+
/** An extended file system abstraction.
693+
694+
Implementing and using this interface over ISlangFileSystem gives much more control over how paths
695+
are managed, as well as how it is determined if two files 'are the same'.
696+
697+
All paths as input char*, or output as ISlangBlobs are always encoded as UTF-8 strings.
698+
Blobs that contain strings are always zero terminated.
699+
*/
700+
struct ISlangFileSystemExt : public ISlangFileSystem
701+
{
702+
public:
703+
/** Get a canonical path which uniquely identifies an object of the file system.
704+
705+
Given a path, returns a 'canonical' path which will return the same path for the same file/directory.
706+
The canonical path is used to compare if two includes are the same file.
707+
The string for the canonical path is held zero terminated in the ISlangBlob of canonicalPathOut.
708+
709+
Note that a canonical path doesn't *have* to be a 'canonical' path, or a path at all
710+
- it can just be a string that uniquely identifies a file. For example another possible mechanism
711+
could be to store the filename combined with the file date time to uniquely identify it.
712+
713+
The client must ensure the blob be released when no longer used, otherwise memory will leak.
714+
715+
@param path
716+
@param canonicalPathOut
717+
@returns A `SlangResult` to indicate success or failure getting the canonical path.
718+
*/
719+
virtual SLANG_NO_THROW SlangResult SLANG_MCALL getCanoncialPath(
720+
const char* path,
721+
ISlangBlob** canonicalPathOut) = 0;
722+
723+
/** Get a path relative to a 'from' path.
724+
725+
The client must ensure the blob be released when no longer used, otherwise memory will leak.
726+
727+
@param fromPathType How to interpret the from path - as a file or a directory.
728+
@param fromPath The from path.
729+
@param path Path to be determined relative to the fromPath
730+
@param pathOut Holds the string which is the relative path. The string is held in the blob zero terminated.
731+
@returns A `SlangResult` to indicate success or failure in loading the file.
732+
*/
733+
virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcRelativePath(
734+
SlangPathType fromPathType,
735+
const char* fromPath,
736+
const char* path,
737+
ISlangBlob** pathOut) = 0;
738+
};
739+
740+
#define SLANG_UUID_ISlangFileSystemExt { 0x5fb632d2, 0x979d, 0x4481, { 0x9f, 0xee, 0x66, 0x3c, 0x3f, 0x14, 0x49, 0xe1 } }
741+
680742
/*!
681743
@brief An instance of the Slang library.
682744
*/

slang.sln

+82-82
Large diffs are not rendered by default.

source/core/core.vcxproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@
213213
<ClCompile Include="token-reader.cpp" />
214214
</ItemGroup>
215215
<ItemGroup>
216-
<None Include="core.natvis" />
216+
<Natvis Include="core.natvis" />
217217
</ItemGroup>
218218
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
219219
<ImportGroup Label="ExtensionTargets">

source/core/core.vcxproj.filters

+2-2
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@
130130
</ClCompile>
131131
</ItemGroup>
132132
<ItemGroup>
133-
<None Include="core.natvis">
133+
<Natvis Include="core.natvis">
134134
<Filter>Source Files</Filter>
135-
</None>
135+
</Natvis>
136136
</ItemGroup>
137137
</Project>

source/core/slang-io.cpp

+38-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
#include "slang-io.h"
22
#include "exception.h"
3+
34
#ifndef __STDC__
4-
#define __STDC__ 1
5+
# define __STDC__ 1
56
#endif
7+
68
#include <sys/stat.h>
9+
710
#ifdef _WIN32
8-
#include <direct.h>
11+
# include <direct.h>
912
#endif
1013

14+
#include <limits.h> /* PATH_MAX */
15+
#include <stdio.h>
16+
#include <stdlib.h>
17+
1118
namespace Slang
1219
{
1320
bool File::Exists(const String & fileName)
@@ -125,6 +132,32 @@ namespace Slang
125132
#endif
126133
}
127134

135+
/* static */SlangResult Path::GetCanonical(const String & path, String & canonicalPathOut)
136+
{
137+
#if defined(_WIN32)
138+
// https://msdn.microsoft.com/en-us/library/506720ff.aspx
139+
wchar_t* absPath = ::_wfullpath(nullptr, path.ToWString(), 0);
140+
if (!absPath)
141+
{
142+
return SLANG_FAIL;
143+
}
144+
145+
canonicalPathOut = String::FromWString(absPath);
146+
::free(absPath);
147+
return SLANG_OK;
148+
#else
149+
// http://man7.org/linux/man-pages/man3/realpath.3.html
150+
char* canonicalPath = ::realpath(path.begin(), nullptr);
151+
if (canonicalPath)
152+
{
153+
canonicalPathOut = canonicalPath;
154+
::free(canonicalPath);
155+
return SLANG_OK;
156+
}
157+
return SLANG_FAIL;
158+
#endif
159+
}
160+
128161
Slang::String File::ReadAllText(const Slang::String & fileName)
129162
{
130163
StreamReader reader(new FileStream(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
@@ -152,4 +185,7 @@ namespace Slang
152185
StreamWriter writer(new FileStream(fileName, FileMode::Create));
153186
writer.Write(text);
154187
}
188+
189+
155190
}
191+

source/core/slang-io.h

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ namespace Slang
3131
static String Combine(const String & path1, const String & path2);
3232
static String Combine(const String & path1, const String & path2, const String & path3);
3333
static bool CreateDir(const String & path);
34+
35+
static SlangResult GetCanonical(const String & path, String& canonicalPathOut);
3436
};
3537
}
3638

source/slang/compiler.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,10 @@ namespace Slang
186186
for(auto sourceFile : translationUnit->sourceFiles)
187187
{
188188
codeBuilder << "#line 1 \"";
189-
for(auto c : sourceFile->path)
189+
190+
const String& path = sourceFile->pathInfo.foundPath;
191+
192+
for(auto c : path)
190193
{
191194
char buffer[] = { c, 0 };
192195
switch(c)

source/slang/compiler.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace Slang
1515
{
16+
struct PathInfo;
1617
struct IncludeHandler;
1718
class CompileRequest;
1819
class ProgramLayout;
@@ -395,6 +396,11 @@ namespace Slang
395396
///
396397
ComPtr<ISlangFileSystem> fileSystem;
397398

399+
/// The extended file system implementation. Will be set to a default implementation
400+
/// if fileSystem is nullptr. Otherwise it will either be fileSystem's interface,
401+
/// or a wrapped impl that makes fileSystem operate as fileSystemExt
402+
ComPtr<ISlangFileSystemExt> fileSystemExt;
403+
398404
/// Load a file into memory using the configured file system.
399405
///
400406
/// @param path The path to attempt to load from
@@ -454,14 +460,14 @@ namespace Slang
454460

455461
RefPtr<ModuleDecl> loadModule(
456462
Name* name,
457-
String const& path,
458-
ISlangBlob* sourceBlob,
463+
const PathInfo& filePathInfo,
464+
ISlangBlob* fileContentsBlob,
459465
SourceLoc const& loc);
460466

461467
void loadParsedModule(
462468
RefPtr<TranslationUnitRequest> const& translationUnit,
463469
Name* name,
464-
String const& path);
470+
PathInfo const& pathInfo);
465471

466472
RefPtr<ModuleDecl> findOrImportModule(
467473
Name* name,

source/slang/diagnostic-defs.h

+3
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ DIAGNOSTIC(-1, Note, seeOpeningToken, "see opening '$0'")
125125
DIAGNOSTIC(15300, Error, includeFailed, "failed to find include file '$0'")
126126
DIAGNOSTIC(15301, Error, importFailed, "failed to find imported file '$0'")
127127
DIAGNOSTIC(-1, Error, noIncludeHandlerSpecified, "no `#include` handler was specified")
128+
DIAGNOSTIC(15302, Error, noCanonicalPath, "`#include` handler didn't generate a canonical path for '$0'")
129+
128130

129131
// 154xx - macro definition
130132
DIAGNOSTIC(15400, Warning, macroRedefinition, "redefinition of macro '$0'")
@@ -138,6 +140,7 @@ DIAGNOSTIC(15501, Error, wrongNumberOfArgumentsToMacro, "wrong number of argumen
138140
// 156xx - pragmas
139141
DIAGNOSTIC(15600, Error, expectedPragmaDirectiveName, "expected a name after '#pragma'")
140142
DIAGNOSTIC(15601, Warning, unknownPragmaDirectiveIgnored, "ignoring unknown directive '#pragma $0'")
143+
DIAGNOSTIC(15602, Warning, pragmaOnceIgnored, "pragma once was ignored - this is typically because is not placed in an include")
141144

142145
// 159xx - user-defined error/warning
143146
DIAGNOSTIC(15900, Error, userDefinedError, "#error: $0")

source/slang/diagnostics.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ static void formatDiagnostic(
171171

172172
auto humaneLoc = sourceManager->getHumaneLoc(diagnostic.loc);
173173

174-
sb << humaneLoc.path;
174+
sb << humaneLoc.pathInfo.foundPath;
175175
sb << "(";
176176
sb << humaneLoc.line;
177177
sb << "): ";

source/slang/emit.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ struct EmitVisitor
541541
emitRawText(buffer);
542542

543543
// Only emit the path part of a `#line` directive if needed
544-
if(sourceLocation.path != context->shared->loc.path)
544+
if(sourceLocation.pathInfo.foundPath != context->shared->loc.pathInfo.foundPath)
545545
{
546546
emitRawText(" ");
547547

@@ -578,7 +578,7 @@ struct EmitVisitor
578578

579579
if(shouldUseGLSLStyleLineDirective)
580580
{
581-
auto path = sourceLocation.path;
581+
auto path = sourceLocation.pathInfo.foundPath;
582582

583583
// GLSL doesn't support the traditional form of a `#line` directive without
584584
// an extension. Rather than depend on that extension we will output
@@ -609,7 +609,8 @@ struct EmitVisitor
609609
// in a module that tracks source files.
610610

611611
emitRawText("\"");
612-
for(auto c : sourceLocation.path)
612+
const auto& path = sourceLocation.pathInfo.foundPath;
613+
for(auto c : path)
613614
{
614615
char charBuffer[] = { c, 0 };
615616
switch(c)
@@ -673,7 +674,7 @@ struct EmitVisitor
673674
// a differnet file or line, *or* if the source location is
674675
// somehow later on the line than what we want to emit,
675676
// then we need to emit a new `#line` directive.
676-
if(sourceLocation.path != context->shared->loc.path
677+
if(sourceLocation.pathInfo.foundPath != context->shared->loc.pathInfo.foundPath
677678
|| sourceLocation.line != context->shared->loc.line
678679
|| sourceLocation.column < context->shared->loc.column)
679680
{
@@ -682,7 +683,7 @@ struct EmitVisitor
682683
// to get us caught up.
683684
enum { kSmallLineCount = 3 };
684685
auto lineDiff = sourceLocation.line - context->shared->loc.line;
685-
if(sourceLocation.path == context->shared->loc.path
686+
if(sourceLocation.pathInfo.foundPath == context->shared->loc.pathInfo.foundPath
686687
&& sourceLocation.line > context->shared->loc.line
687688
&& lineDiff <= kSmallLineCount)
688689
{

0 commit comments

Comments
 (0)