yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

master
7.8 KiB252 linesraw
1// slang-downstream-compiler.cpp
2#include "slang-downstream-compiler.h"
3
4#include "../core/slang-blob.h"
5#include "../core/slang-castable.h"
6#include "../core/slang-char-util.h"
7#include "../core/slang-common.h"
8#include "../core/slang-io.h"
9#include "../core/slang-shared-library.h"
10#include "../core/slang-string-util.h"
11#include "../core/slang-type-text-util.h"
12#include "slang-artifact-associated-impl.h"
13#include "slang-artifact-desc-util.h"
14#include "slang-artifact-helper.h"
15#include "slang-artifact-impl.h"
16#include "slang-artifact-representation-impl.h"
17#include "slang-artifact-util.h"
18#include "slang-com-helper.h"
19
20namespace Slang
21{
22
23/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompilerBase !!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
24
25SlangResult DownstreamCompilerBase::convert(
26    IArtifact* from,
27    const ArtifactDesc& to,
28    IArtifact** outArtifact)
29{
30    SLANG_UNUSED(from);
31    SLANG_UNUSED(to);
32    SLANG_UNUSED(outArtifact);
33
34    return SLANG_E_NOT_AVAILABLE;
35}
36
37void* DownstreamCompilerBase::castAs(const Guid& guid)
38{
39    if (auto ptr = getInterface(guid))
40    {
41        return ptr;
42    }
43    return getObject(guid);
44}
45
46void* DownstreamCompilerBase::getInterface(const Guid& guid)
47{
48    if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() ||
49        guid == IDownstreamCompiler::getTypeGuid())
50    {
51        return static_cast<IDownstreamCompiler*>(this);
52    }
53
54    return nullptr;
55}
56
57void* DownstreamCompilerBase::getObject(const Guid& guid)
58{
59    SLANG_UNUSED(guid);
60    return nullptr;
61}
62
63/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompiler !!!!!!!!!!!!!!!!!!!!!!*/
64
65SlangResult CommandLineDownstreamCompiler::compile(
66    const CompileOptions& inOptions,
67    IArtifact** outArtifact)
68{
69    if (!isVersionCompatible(inOptions))
70    {
71        // Not possible to compile with this version of the interface.
72        return SLANG_E_NOT_IMPLEMENTED;
73    }
74
75    CompileOptions options = getCompatibleVersion(&inOptions);
76
77    // Copy the command line options
78    CommandLine cmdLine(m_cmdLine);
79
80    // Work out the ArtifactDesc
81    const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType);
82
83    auto helper = DefaultArtifactHelper::getSingleton();
84
85    List<ComPtr<IArtifact>> artifactList;
86
87    // It may be necessary to produce a temporary file 'lock file'.
88    ComPtr<IOSFileArtifactRepresentation> lockFile;
89
90    // The allocator can be used for items that are not kept in scope by the options
91    String modulePath;
92
93    // If no module path is set we will need to generate one
94    if (options.modulePath.count == 0)
95    {
96        // We could use the path to the source, or use the source name/paths as defined on the
97        // artifact For now we just go with a lock file based on "slang-generated".
98        SLANG_RETURN_ON_FAIL(
99            helper->createLockFile(asCharSlice(toSlice("slang-generated")), lockFile.writeRef()));
100
101        auto lockArtifact = Artifact::create(
102            ArtifactDesc::make(ArtifactKind::Base, ArtifactPayload::Lock, ArtifactStyle::None));
103        lockArtifact->addRepresentation(lockFile);
104
105        artifactList.add(lockArtifact);
106
107        // Add the source files such that they can exist
108        modulePath = lockFile->getPath();
109
110        options.modulePath = SliceUtil::asTerminatedCharSlice(modulePath);
111    }
112
113    // Append command line args to the end of cmdLine using the target specific function for the
114    // specified options
115    SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine));
116
117    // The 'productArtifact' is the main product produced from the compilation - the
118    // executable/sharedlibrary/object etc
119    ComPtr<IArtifact> productArtifact;
120    {
121        List<ComPtr<IArtifact>> artifacts;
122        SLANG_RETURN_ON_FAIL(
123            calcCompileProducts(options, DownstreamProductFlag::All, lockFile, artifacts));
124
125        for (IArtifact* artifact : artifacts)
126        {
127            // The main artifact must be in the list, so add it if we find it
128            if (artifact->getDesc() == targetDesc)
129            {
130                SLANG_ASSERT(productArtifact == nullptr);
131                productArtifact = artifact;
132            }
133
134            artifactList.add(ComPtr<IArtifact>(artifact));
135        }
136    }
137
138    SLANG_ASSERT(productArtifact);
139    // Somethings gone wrong if we don't find the main artifact
140    if (!productArtifact)
141    {
142        return SLANG_FAIL;
143    }
144
145    ExecuteResult exeRes;
146
147#if 0
148    // Test
149    {
150        String line = ProcessUtil::getCommandLineString(cmdLine);
151        printf("%s", line.getBuffer());
152    }
153#endif
154
155    SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes));
156
157#if 0
158    {
159        printf("stdout=\"%s\"\nstderr=\"%s\"\nret=%d\n", exeRes.standardOutput.getBuffer(), exeRes.standardError.getBuffer(), int(exeRes.resultCode));
160    }
161#endif
162
163    // Go through the list of artifacts in the artifactList and check if they exist.
164    //
165    // This is useful because `calcCompileProducts` is conservative and may produce artifacts for
166    // products that aren't actually produced, by the compilation.
167    {
168
169        Count count = artifactList.getCount();
170        for (Index i = 0; i < count; ++i)
171        {
172            IArtifact* artifact = artifactList[i];
173
174            if (!artifact->exists())
175            {
176                // We should find a file rep and if we do we can disown it. Disowning will mean
177                // when scope is lost the rep won't try and delete the (apparently non existing)
178                // backing file.
179                if (auto fileRep = findRepresentation<IOSFileArtifactRepresentation>(artifact))
180                {
181                    fileRep->disown();
182                }
183
184                // If the main artifact doesn't exist, we don't have a main artifact
185                if (artifact == productArtifact)
186                {
187                    productArtifact.setNull();
188                }
189
190                // Remove from the list
191                artifactList.removeAt(i);
192                --count;
193                --i;
194            }
195        }
196    }
197
198    // Add all of the source artifacts, that are temporary on the file system, such that they can
199    // stay in scope for debugging
200    for (auto sourceArtifact : options.sourceArtifacts)
201    {
202        if (auto fileRep = findRepresentation<IOSFileArtifactRepresentation>(sourceArtifact))
203        {
204            // If it has a lock file we can assume it's a temporary
205            if (fileRep->getLockFile())
206            {
207                artifactList.add(ComPtr<IArtifact>(sourceArtifact));
208            }
209        }
210    }
211
212    // Create the result artifact
213    auto artifact = ArtifactUtil::createArtifact(targetDesc);
214
215    // Createa the diagnostics
216    auto diagnostics = ArtifactDiagnostics::create();
217
218    SLANG_RETURN_ON_FAIL(parseOutput(exeRes, diagnostics));
219
220    ArtifactUtil::addAssociated(artifact, diagnostics);
221
222    // Find the rep from the 'main' artifact, we'll just use the same representation on the output
223    // artifact. Sharing is desirable, because the rep owns the file.
224    if (auto fileRep = productArtifact
225                           ? findRepresentation<IOSFileArtifactRepresentation>(productArtifact)
226                           : nullptr)
227    {
228        artifact->addRepresentation(fileRep);
229    }
230
231    // Add the artifact list if there is anything in it
232    if (artifactList.getCount())
233    {
234        // Holds all of the artifacts that are relatated to the final artifact - such as debug
235        // files, ancillary file and lock files
236        auto artifactContainer = ArtifactUtil::createArtifact(ArtifactDesc::make(
237            ArtifactKind::Container,
238            ArtifactPayload::Unknown,
239            ArtifactStyle::Unknown));
240
241        auto slice = SliceUtil::asSlice(artifactList);
242
243        artifactContainer->setChildren(slice.data, slice.count);
244
245        artifact->addAssociated(artifactContainer);
246    }
247
248    *outArtifact = artifact.detach();
249    return SLANG_OK;
250}
251
252} // namespace Slang