summaryrefslogtreecommitdiff
path: root/source/core/slang-gcc-compiler-util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/core/slang-gcc-compiler-util.cpp')
-rw-r--r--source/core/slang-gcc-compiler-util.cpp645
1 files changed, 0 insertions, 645 deletions
diff --git a/source/core/slang-gcc-compiler-util.cpp b/source/core/slang-gcc-compiler-util.cpp
deleted file mode 100644
index 56955f1da..000000000
--- a/source/core/slang-gcc-compiler-util.cpp
+++ /dev/null
@@ -1,645 +0,0 @@
-// slang-gcc-compiler-util.cpp
-#include "slang-gcc-compiler-util.h"
-
-#include "slang-common.h"
-#include "../../slang-com-helper.h"
-#include "slang-string-util.h"
-
-#include "slang-io.h"
-#include "slang-shared-library.h"
-
-namespace Slang
-{
-
-/* static */SlangResult GCCDownstreamCompilerUtil::parseVersion(const UnownedStringSlice& text, const UnownedStringSlice& prefix, DownstreamCompiler::Desc& outDesc)
-{
- List<UnownedStringSlice> lines;
- StringUtil::calcLines(text, lines);
-
- for (auto line : lines)
- {
- if (line.startsWith(prefix))
- {
- const UnownedStringSlice remainingSlice = UnownedStringSlice(line.begin() + prefix.getLength(), line.end()).trim();
- const Index versionEndIndex = remainingSlice.indexOf(' ');
- if (versionEndIndex < 0)
- {
- return SLANG_FAIL;
- }
-
- const UnownedStringSlice versionSlice(remainingSlice.begin(), remainingSlice.begin() + versionEndIndex);
-
- // Version is in format 0.0.0
- List<UnownedStringSlice> split;
- StringUtil::split(versionSlice, '.', split);
- List<Int> digits;
-
- for (auto v : split)
- {
- Int version;
- SLANG_RETURN_ON_FAIL(StringUtil::parseInt(v, version));
- digits.add(version);
- }
-
- if (digits.getCount() < 2)
- {
- return SLANG_FAIL;
- }
-
- outDesc.majorVersion = digits[0];
- outDesc.minorVersion = digits[1];
- return SLANG_OK;
- }
- }
-
- return SLANG_FAIL;
-}
-
-SlangResult GCCDownstreamCompilerUtil::calcVersion(const String& exeName, DownstreamCompiler::Desc& outDesc)
-{
- CommandLine cmdLine;
- cmdLine.setExecutableFilename(exeName);
- cmdLine.addArg("-v");
-
- ExecuteResult exeRes;
- SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes));
-
- const UnownedStringSlice prefixes[] =
- {
- UnownedStringSlice::fromLiteral("clang version"),
- UnownedStringSlice::fromLiteral("gcc version"),
- UnownedStringSlice::fromLiteral("Apple LLVM version"),
- };
- const SlangPassThrough types[] =
- {
- SLANG_PASS_THROUGH_CLANG,
- SLANG_PASS_THROUGH_GCC,
- SLANG_PASS_THROUGH_CLANG,
- };
-
- SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(prefixes) == SLANG_COUNT_OF(types));
-
- for (Index i = 0; i < SLANG_COUNT_OF(prefixes); ++i)
- {
- // Set the type
- outDesc.type = types[i];
- // Extract the version
- if (SLANG_SUCCEEDED(parseVersion(exeRes.standardError.getUnownedSlice(), prefixes[i], outDesc)))
- {
- return SLANG_OK;
- }
- }
- return SLANG_FAIL;
-}
-
-static SlangResult _parseSeverity(const UnownedStringSlice& in, DownstreamDiagnostic::Severity& outSeverity)
-{
- typedef DownstreamDiagnostic::Severity Severity;
-
- if (in == "error" || in == "fatal error")
- {
- outSeverity = Severity::Error;
- }
- else if (in == "warning")
- {
- outSeverity = Severity::Warning;
- }
- else if (in == "info" || in == "note")
- {
- outSeverity = Severity::Info;
- }
- else
- {
- return SLANG_FAIL;
- }
- return SLANG_OK;
-}
-
-namespace { // anonymous
-
-enum class LineParseResult
-{
- Single, ///< It's a single line
- Start, ///< Line was the start of a message
- Continuation, ///< Not totally clear, add to previous line if nothing else hit
- Ignore, ///< Ignore the line
-};
-
-} // anonymous
-
-static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParseResult& outLineParseResult, DownstreamDiagnostic& outDiagnostic)
-{
- typedef DownstreamDiagnostic Diagnostic;
- typedef Diagnostic::Severity Severity;
-
- // Set to default case
- outLineParseResult = LineParseResult::Ignore;
-
- /* example error output from different scenarios */
-
- /*
- tests/cpp-compiler/c-compile-error.c: In function 'int main(int, char**)':
- tests/cpp-compiler/c-compile-error.c:8:13: error: 'b' was not declared in this scope
- int a = b + c;
- ^
- tests/cpp-compiler/c-compile-error.c:8:17: error: 'c' was not declared in this scope
- int a = b + c;
- ^
- */
-
- /* /tmp/ccS0JCWe.o:c-compile-link-error.c:(.rdata$.refptr.thing[.refptr.thing]+0x0): undefined reference to `thing'
- collect2: error: ld returned 1 exit status*/
-
- /*
- clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]
- Undefined symbols for architecture x86_64:
- "_thing", referenced from:
- _main in c-compile-link-error-a83ace.o
- ld: symbol(s) not found for architecture x86_64
- clang: error: linker command failed with exit code 1 (use -v to see invocation) */
-
- /* /tmp/c-compile-link-error-ccf151.o: In function `main':
- c-compile-link-error.c:(.text+0x19): undefined reference to `thing'
- clang: error: linker command failed with exit code 1 (use -v to see invocation)
- */
-
- /* /tmp/c-compile-link-error-301c8c.o: In function `main':
- /home/travis/build/shader-slang/slang/tests/cpp-compiler/c-compile-link-error.c:10: undefined reference to `thing'
- clang-7: error: linker command failed with exit code 1 (use -v to see invocation)*/
-
- /* /path/slang-cpp-prelude.h:4:10: fatal error: ../slang.h: No such file or directory
- #include "../slang.h"
- ^~~~~~~~~~~~
- compilation terminated.*/
-
- outDiagnostic.stage = Diagnostic::Stage::Compile;
-
- List<UnownedStringSlice> split;
- StringUtil::split(line, ':', split);
-
- // On windows we can have paths that are a: etc... if we detect this we can combine 0 - 1 to be 1.
- if (split.getCount() > 1 && split[0].getLength() == 1)
- {
- const char c = split[0][0];
- if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
- {
- // We'll assume it's a path
- UnownedStringSlice path(split[0].begin(), split[1].end());
- split.removeAt(0);
- split[0] = path;
- }
- }
-
- if (split.getCount() == 2)
- {
- const auto split0 = split[0].trim();
- if (split0 == UnownedStringSlice::fromLiteral("ld"))
- {
- // We'll ignore for now
- outDiagnostic.stage = Diagnostic::Stage::Link;
- outDiagnostic.severity = Severity::Info;
- outDiagnostic.text = split[1].trim();
- outLineParseResult = LineParseResult::Start;
- return SLANG_OK;
- }
-
- if (SLANG_SUCCEEDED(_parseSeverity(split0, outDiagnostic.severity)))
- {
- // Command line errors can be just contain 'error:' etc. Can be seen on apple/clang
- outDiagnostic.stage = Diagnostic::Stage::Compile;
- outDiagnostic.text = split[1].trim();
- outLineParseResult = LineParseResult::Single;
- return SLANG_OK;
- }
-
- outLineParseResult = LineParseResult::Ignore;
- return SLANG_OK;
- }
- else if (split.getCount() == 3)
- {
- const auto split0 = split[0].trim();
- const auto split1 = split[1].trim();
- const auto text = split[2].trim();
-
- // Check for special handling for clang (Can be Clang or clang apparently)
- if (split0.startsWith(UnownedStringSlice::fromLiteral("clang")) ||
- split0.startsWith(UnownedStringSlice::fromLiteral("Clang")) )
- {
- // Extract the type
- SLANG_RETURN_ON_FAIL(_parseSeverity(split[1].trim(), outDiagnostic.severity));
-
- if (text.startsWith("linker command failed"))
- {
- outDiagnostic.stage = Diagnostic::Stage::Link;
- }
-
- outDiagnostic.text = text;
- outLineParseResult = LineParseResult::Start;
- return SLANG_OK;
- }
- else if (split1.startsWith("(.text"))
- {
- // This is a little weak... but looks like it's a link error
- outDiagnostic.filePath = split[0];
- outDiagnostic.severity = Severity::Error;
- outDiagnostic.stage = Diagnostic::Stage::Link;
- outDiagnostic.text = text;
- outLineParseResult = LineParseResult::Single;
- return SLANG_OK;
- }
- else if (text.startsWith("ld returned"))
- {
- outDiagnostic.stage = DownstreamDiagnostic::Stage::Link;
- SLANG_RETURN_ON_FAIL(_parseSeverity(split[1].trim(), outDiagnostic.severity));
- outDiagnostic.text = line;
- outLineParseResult = LineParseResult::Single;
- return SLANG_OK;
- }
- else if (text == "")
- {
- // This is probably a prelude line, we'll just ignore it
- outLineParseResult = LineParseResult::Ignore;
- return SLANG_OK;
- }
- }
- else if (split.getCount() == 4)
- {
- // Probably a link error, give the source line
- String ext = Path::getPathExt(split[0]);
-
- // Maybe a bit fragile -> but probably okay for now
- if (ext != "o" && ext != "obj")
- {
- outLineParseResult = LineParseResult::Ignore;
- return SLANG_OK;
- }
- else
- {
- outDiagnostic.filePath = split[1];
- outDiagnostic.fileLine = 0;
- outDiagnostic.severity = Diagnostic::Severity::Error;
- outDiagnostic.stage = Diagnostic::Stage::Link;
- outDiagnostic.text = split[3];
-
- outLineParseResult = LineParseResult::Start;
- return SLANG_OK;
- }
- }
- else if (split.getCount() >= 5)
- {
- // Probably a regular error line
- SLANG_RETURN_ON_FAIL(_parseSeverity(split[3].trim(), outDiagnostic.severity));
-
- outDiagnostic.filePath = split[0];
- SLANG_RETURN_ON_FAIL(StringUtil::parseInt(split[1], outDiagnostic.fileLine));
-
- // Everything from 4 to the end is the error
- outDiagnostic.text = UnownedStringSlice(split[4].begin(), split.getLast().end());
-
- outLineParseResult = LineParseResult::Start;
- return SLANG_OK;
- }
-
- // Assume it's a continuation
- outLineParseResult = LineParseResult::Continuation;
- return SLANG_OK;
-}
-
-/* static */SlangResult GCCDownstreamCompilerUtil::parseOutput(const ExecuteResult& exeRes, DownstreamDiagnostics& outOutput)
-{
- LineParseResult prevLineResult = LineParseResult::Ignore;
-
- outOutput.reset();
- outOutput.rawDiagnostics = exeRes.standardError;
-
- for (auto line : LineParser(exeRes.standardError.getUnownedSlice()))
- {
- Diagnostic diagnostic;
- diagnostic.reset();
-
- LineParseResult lineRes;
-
- SLANG_RETURN_ON_FAIL(_parseGCCFamilyLine(line, lineRes, diagnostic));
-
- switch (lineRes)
- {
- case LineParseResult::Start:
- {
- // It's start of a new message
- outOutput.diagnostics.add(diagnostic);
- prevLineResult = LineParseResult::Start;
- break;
- }
- case LineParseResult::Single:
- {
- // It's a single message, without anything following
- outOutput.diagnostics.add(diagnostic);
- prevLineResult = LineParseResult::Ignore;
- break;
- }
- case LineParseResult::Continuation:
- {
- if (prevLineResult == LineParseResult::Start || prevLineResult == LineParseResult::Continuation)
- {
- if (outOutput.diagnostics.getCount() > 0)
- {
- // We are now in a continuation, add to the last
- auto& text = outOutput.diagnostics.getLast().text;
- text.append("\n");
- text.append(line);
- }
- prevLineResult = LineParseResult::Continuation;
- }
- break;
- }
- case LineParseResult::Ignore:
- {
- prevLineResult = lineRes;
- break;
- }
- default: return SLANG_FAIL;
- }
- }
-
- if (outOutput.has(Diagnostic::Severity::Error) || exeRes.resultCode != 0)
- {
- outOutput.result = SLANG_FAIL;
- }
-
- return SLANG_OK;
-}
-
-/* static */ SlangResult GCCDownstreamCompilerUtil::calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath)
-{
- SLANG_ASSERT(options.modulePath.getLength());
-
- outPath.Clear();
-
- switch (options.targetType)
- {
- case TargetType::SharedLibrary:
- {
- outPath << SharedLibrary::calcPlatformPath(options.modulePath.getUnownedSlice());
- return SLANG_OK;
- }
- case TargetType::Executable:
- {
- outPath << options.modulePath;
- outPath << ProcessUtil::getExecutableSuffix();
- return SLANG_OK;
- }
- case TargetType::Object:
- {
-#if __CYGWIN__
- outPath << options.modulePath << ".obj";
-#else
- // Will be .o for typical gcc targets
- outPath << options.modulePath << ".o";
-#endif
- return SLANG_OK;
- }
- }
-
- return SLANG_FAIL;
-}
-
-/* static */SlangResult GCCDownstreamCompilerUtil::calcCompileProducts(const CompileOptions& options, ProductFlags flags, List<String>& outPaths)
-{
- SLANG_ASSERT(options.modulePath.getLength());
-
- outPaths.clear();
-
- if (flags & ProductFlag::Execution)
- {
- StringBuilder builder;
- SLANG_RETURN_ON_FAIL(calcModuleFilePath(options, builder));
- outPaths.add(builder);
- }
-
- return SLANG_OK;
-}
-
-/* static */SlangResult GCCDownstreamCompilerUtil::calcArgs(const CompileOptions& options, CommandLine& cmdLine)
-{
- SLANG_ASSERT(options.sourceContents.getLength() == 0);
- SLANG_ASSERT(options.modulePath.getLength());
-
- PlatformKind platformKind = (options.platform == PlatformKind::Unknown) ? PlatformUtil::getPlatformKind() : options.platform;
-
- if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP)
- {
- cmdLine.addArg("-fvisibility=hidden");
-
- // Need C++14 for partial specialization
- cmdLine.addArg("-std=c++14");
- }
-
- // TODO(JS): Here we always set -m32 on x86. It could be argued it is only necessary when creating a shared library
- // but if we create an object file, we don't know what to choose because we don't know what final usage is.
- // It could also be argued that the platformKind could define the actual desired target - but as it stands
- // we only have a target of 'Linux' (as opposed to Win32/64). Really it implies we need an arch enumeration too.
- //
- // For now we just make X86 binaries try and produce x86 compatible binaries as fixes the immediate problems.
-#if SLANG_PROCESSOR_X86
- /* Used to specify the processor more broadly. For a x86 binary we need to make sure we build x86 builds
- even when on an x64 system.
- -m32
- -m64*/
- cmdLine.addArg("-m32");
-#endif
-
- switch (options.optimizationLevel)
- {
- case OptimizationLevel::None:
- {
- // No optimization
- cmdLine.addArg("-O0");
- break;
- }
- case OptimizationLevel::Default:
- {
- cmdLine.addArg("-Os");
- break;
- }
- case OptimizationLevel::High:
- {
- cmdLine.addArg("-O2");
- break;
- }
- case OptimizationLevel::Maximal:
- {
- cmdLine.addArg("-O4");
- break;
- }
- default: break;
- }
-
- if (options.debugInfoType != DebugInfoType::None)
- {
- cmdLine.addArg("-g");
- }
-
- if (options.flags & CompileOptions::Flag::Verbose)
- {
- cmdLine.addArg("-v");
- }
-
- switch (options.floatingPointMode)
- {
- case FloatingPointMode::Default: break;
- case FloatingPointMode::Precise:
- {
- //cmdLine.addArg("-fno-unsafe-math-optimizations");
- break;
- }
- case FloatingPointMode::Fast:
- {
- // We could enable SSE with -mfpmath=sse
- // But that would only make sense on a x64/x86 type processor and only if that feature is present (it is on all x64)
- cmdLine.addArg("-ffast-math");
- break;
- }
- }
-
- StringBuilder moduleFilePath;
- calcModuleFilePath(options, moduleFilePath);
-
- cmdLine.addArg("-o");
- cmdLine.addArg(moduleFilePath);
-
- switch (options.targetType)
- {
- case TargetType::SharedLibrary:
- {
- // Shared library
- cmdLine.addArg("-shared");
-
- if (PlatformUtil::isFamily(PlatformFamily::Unix, platformKind))
- {
- // Position independent
- cmdLine.addArg("-fPIC");
- }
- break;
- }
- case TargetType::Executable:
- {
- break;
- }
- case TargetType::Object:
- {
- // Don't link, just produce object file
- cmdLine.addArg("-c");
- break;
- }
- default: break;
- }
-
- // Add defines
- for (const auto& define : options.defines)
- {
- StringBuilder builder;
-
- builder << "-D";
- builder << define.nameWithSig;
- if (define.value.getLength())
- {
- builder << "=" << define.value;
- }
-
- cmdLine.addArg(builder);
- }
-
- // Add includes
- for (const auto& include : options.includePaths)
- {
- cmdLine.addArg("-I");
- cmdLine.addArg(include);
- }
-
- // Link options
- if (0) // && options.targetType != TargetType::Object)
- {
- //linkOptions << "-Wl,";
- //cmdLine.addArg(linkOptions);
- }
-
- if (options.targetType == TargetType::SharedLibrary)
- {
- if (!PlatformUtil::isFamily(PlatformFamily::Apple, platformKind))
- {
- // On MacOS, this linker option is not supported. That's ok though in
- // so far as on MacOS it does report any unfound symbols without the option.
-
- // Linker flag to report any undefined symbols as a link error
- cmdLine.addArg("-Wl,--no-undefined");
- }
- }
-
- // Files to compile
- for (const auto& sourceFile : options.sourceFiles)
- {
- cmdLine.addArg(sourceFile);
- }
-
- for (const auto& libPath : options.libraryPaths)
- {
- // Note that any escaping of the path is handled in the ProcessUtil::
- cmdLine.addArg("-L");
- cmdLine.addArg(libPath);
- cmdLine.addArg("-F");
- cmdLine.addArg(libPath);
- }
-
- if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP && !PlatformUtil::isFamily(PlatformFamily::Windows, platformKind))
- {
- // Make STD libs available
- cmdLine.addArg("-lstdc++");
- // Make maths lib available
- cmdLine.addArg("-lm");
- }
-
- return SLANG_OK;
-}
-
-/* static */SlangResult GCCDownstreamCompilerUtil::createCompiler(const String& path, const String& inExeName, RefPtr<DownstreamCompiler>& outCompiler)
-{
- String exeName(inExeName);
- if (path.getLength() > 0)
- {
- exeName = Path::combine(path, inExeName);
- }
-
- DownstreamCompiler::Desc desc;
- SLANG_RETURN_ON_FAIL(GCCDownstreamCompilerUtil::calcVersion(exeName, desc));
-
- RefPtr<CommandLineDownstreamCompiler> compiler(new GCCDownstreamCompiler(desc));
- compiler->m_cmdLine.setExecutableFilename(exeName);
-
- outCompiler = compiler;
- return SLANG_OK;
-}
-
-/* static */SlangResult GCCDownstreamCompilerUtil::locateGCCCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set)
-{
- SLANG_UNUSED(loader);
- RefPtr<DownstreamCompiler> compiler;
- if (SLANG_SUCCEEDED(createCompiler(path, "g++", compiler)))
- {
- set->addCompiler(compiler);
- }
- return SLANG_OK;
-}
-
-/* static */SlangResult GCCDownstreamCompilerUtil::locateClangCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set)
-{
- SLANG_UNUSED(loader);
-
- RefPtr<DownstreamCompiler> compiler;
- if (SLANG_SUCCEEDED(createCompiler(path, "clang", compiler)))
- {
- set->addCompiler(compiler);
- }
- return SLANG_OK;
-}
-
-}