diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2017-09-29 13:43:08 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-09-29 13:43:08 -0700 |
| commit | 8a0ebb9fa25fd44def17b03b3f8aa1a33ad77940 (patch) | |
| tree | 3f855c1f8057e53763cb083c3b898effb559b80b | |
| parent | 74f2f47cb63b02638270beecd20acea1a0f5665e (diff) | |
Get tests running/passing under Linux (#194)
* Get tests running/passing under Linux
- Fix up `dlopen` abstraction
- Fix up some test cases to request hlsl (rather than default to dxbc) so they can run on non-Windows targets
- Fix up test runner ignore tests that can't run on current platform (and not count those as failure)
- Fix file handle leeak in process spawner absttraction
- Get additional test-related applications building
- More tweaks to Travis script; in theory deployment is set up now (yeah, right)
* fixup
* fixup: Travis environment variable syntax
* fixup: Buffer->begin
* fixup: actually run full tests on one config
* fixup: add build status badge for Travis
| -rw-r--r-- | .travis.yml | 49 | ||||
| -rw-r--r-- | Makefile | 82 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | source/core/platform.cpp | 15 | ||||
| -rw-r--r-- | source/core/slang-string.cpp | 18 | ||||
| -rw-r--r-- | source/slang-glslang/slang-glslang.cpp | 9 | ||||
| -rw-r--r-- | source/slang-glslang/slang-glslang.h | 2 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 2 | ||||
| -rw-r--r-- | tests/reflection/arrays.hlsl | 2 | ||||
| -rw-r--r-- | tests/reflection/gh-55.glsl | 2 | ||||
| -rw-r--r-- | tests/reflection/global-uniforms.hlsl | 2 | ||||
| -rw-r--r-- | tests/reflection/image-types.glsl | 2 | ||||
| -rw-r--r-- | tests/reflection/multi-file.hlsl | 2 | ||||
| -rw-r--r-- | tests/reflection/reflect-imported-code.hlsl | 2 | ||||
| -rw-r--r-- | tests/reflection/reflection0.hlsl | 2 | ||||
| -rw-r--r-- | tests/reflection/resource-in-cbuffer.hlsl | 2 | ||||
| -rw-r--r-- | tests/reflection/std430-layout.glsl | 2 | ||||
| -rw-r--r-- | tests/reflection/thread-group-size.comp | 2 | ||||
| -rw-r--r-- | tests/reflection/thread-group-size.hlsl | 2 | ||||
| -rw-r--r-- | tools/slang-test/main.cpp | 73 | ||||
| -rw-r--r-- | tools/slang-test/os.cpp | 262 | ||||
| -rw-r--r-- | tools/slang-test/os.h | 24 |
22 files changed, 506 insertions, 54 deletions
diff --git a/.travis.yml b/.travis.yml index 8084c6bab..96b797b05 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,17 +4,56 @@ language: cpp -# Let's test against both major compilers just to be sure. -compiler: - - clang - - gcc - +# Build and test (clang, gcc) x (debug, release) +# +# We customize the set of tests run per-target to +# avoid having the build take too long. matrix: include: - os: linux + compiler: gcc + env: + - CONFIGURATION=debug + - SLANG_TEST_CATEGORY=smoke + - os: linux + compiler: clang + env: + - CONFIGURATION=debug + - SLANG_TEST_CATEGORY=smoke + - os: linux + compiler: clang + env: + - CONFIGURATION=release + - SLANG_TEST_CATEGORY=smoke + - os: linux + compiler: gcc + env: + - CONFIGURATION=release + - SLANG_TEST_CATEGORY=full + - SLANG_DEPLOY=true # Travis wants to default to a build script that invokes # `./configure && make && make test` which is appropriate # for autoconf, but I don't want to get into that mess.. # script: make && make test + +before_deploy: | + export SLANG_OS_NAME=$(TRAVIS_OS_NAME) + export SLANG_ARCH_NAME=`uname -p` + export SLANG_TAG=${TRAVIS_TAG#v} + export SLANG_BINARY_ARCHIVE=slang-$(SLANG_OS_NAME)-$(SLANG_ARCH_NAME)-$(SLANG_TAG).zip + zip -r $(SLANG_BINARY_ARCHIVE) bin/*/*/slangc bin/*/*/libslang.so bin/*/*/libslang-glslang.so docs/*.md README.md LICENSE slang.h + +# We are going to deploy to GitHub Releases +# on a successful build from a tag, but only +# on the one target in the build matrix that set +# `SLANG_DEPLOY` +deploy: + provider: releases + api_key: "$GITHUB_RELEASE_TOKEN" + file: "$SLANG_BINARY_ARCHIVE" + skip_cleanup: true + on: + condition: "$SLANG_DEPLOY = true" + tags: true @@ -9,10 +9,21 @@ # or track fine-grained dependencies, so almost any source change will # trigger a full rebuild. Anybody who wants to do their active development # on a platform supported by this Makefile should feel free to contribute -# improvements, with the caveat that we will not be adoptttting autoconf, -# CMake, or any other build system that has a tendency to "infect" a codebbbase. +# improvements, with the caveat that we will not be adopting autoconf, +# CMake, or any other build system that has a tendency to "infect" a codebase. # +PLATFORM := $(shell uname -s | tr '[:upper:]' '[:lower:]') +ARCHITECTURE := $(shell uname -p) + +ifeq (,$(CONFIGURATION)) + CONFIGURATION := release +endif + +ifeq (,$(SLANG_TEST_CATEGORY)) + SLANG_TEST_CATEGORY := full +endif + # # The Windows build (using Visual Studio) tries to output things to # directories that take the target platform (and build configuration) into @@ -20,8 +31,7 @@ # "triple" from the compiler (which we assume is either gcc or clang) and # call that our target "platformm" # -TARGET := $(shell $(CXX) -dumpmachine) - +TARGET := $(PLATFORM)-$(ARCHITECTURE) # # TODO: We need a way to control the "configuration" (debug vs. release) # but for now just geting *something* working will be a good start. @@ -32,8 +42,8 @@ TARGET := $(shell $(CXX) -dumpmachine) # the target platform chosen. If we ever have steps that need to # output intermediate files, we'd set up the directory here. # -OUTPUTDIR := bin/$(TARGET)/ -INTERMEDIATEDIR := intermediate/$(TARGET)/ +OUTPUTDIR := bin/$(TARGET)/$(CONFIGURATION)/ +INTERMEDIATEDIR := intermediate/$(TARGET)/$(CONFIGURATION)/ # # Now we will start defining a bunch of variables for build @@ -48,10 +58,17 @@ BIN_SUFFIX := # Note: we set `visibility=hidden` to avoid exporting more symbols than # we really need. CFLAGS := -std=c++11 -fvisibility=hidden +CFLAGS += -I. LDFLAGS := -L$(OUTPUTDIR) SHARED_LIB_LDFLAGS := -shared SHARED_LIB_CFLAGS := -fPIC +ifeq (debug,$(CONFIGURATION)) +CFLAGS += -g +else +CFLAGS += -O2 +endif + # Make sure that shared library inherits build flags # from the default case. SHARED_LIB_LDFLAGS += $(LDFLAGS) @@ -74,11 +91,40 @@ CORE_HEADERS := source/core/*.h SLANG_SOURCES := source/slang/*.cpp SLANG_HEADERS := slang.h source/slang/*.h +# SLANG_SOURCES += $(CORE_SOURCES) SLANG_HEADERS += $(CORE_HEADERS) SLANGC_SOURCES := source/slangc/*.cpp SLANGC_HEADERS := $(SLANG_HEADERS) +# +SLANGC_SOURCES += $(CORE_SOURCES) + +SLANG_GLSLANG_SOURCES := source/slang-glslang/*.cpp +SLANG_GLSLANG_HEADERS := source/slang-glslang/*.h + +SLANG_EVAL_TEST_SOURCES := tools/eval-test/*.cpp +SLANG_EVAL_TEST_HEADERS := + +# Add `glslang` sources to the build or `slang-glslang` +# +# Note: We aren't going to wasttte time trying to work with +# the existing CMake-based build for `glslang`. +# +SLANG_GLSLANG_SOURCES += \ + external/glslang/OGLCompilersDLL/*.cpp \ + external/glslang/SPIRV/*.cpp \ + external/glslang/glslang/GenericCodeGen/*.cpp \ + external/glslang/glslang/MachineIndependent/*.cpp \ + external/glslang/glslang/MachineIndependent/preprocessor/*.cpp \ + external/glslang/glslang/OSDependent/Unix/*.cpp + + +SLANG_TEST_SOURCES := tools/slang-test/*.cpp +SLANG_TEST_HEADERS := tools/slang-test/*.h +# +SLANG_TEST_SOURCES += $(CORE_SOURCES) +SLANG_TEST_HEADERS += $(CORE_HEADERS) # # Each project will have a variable that is an alias for @@ -86,31 +132,43 @@ SLANGC_HEADERS := $(SLANG_HEADERS) # SLANG := $(OUTPUTDIR)$(SHARED_LIB_PREFIX)slang$(SHARED_LIB_SUFFIX) SLANGC := $(OUTPUTDIR)slangc$(BIN_SUFFIX) +SLANG_GLSLANG := $(OUTPUTDIR)$(SHARED_LIB_PREFIX)slang-glslang$(SHARED_LIB_SUFFIX) +SLANG_TEST := $(OUTPUTDIR)slang-test$(BIN_SUFFIX) +SLANG_EVAL_TEST := $(OUTPUTDIR)slang-eval-test$(BIN_SUFFIX) # By default, when the user invokes `make`, we will build the # `slang` shared library, and the `slangc` front-end application. -all: slang slangc +all: slang slang-glslang slangc slang-test slang-eval-test mkdirs: $(OUTPUTDIR) # Project-specific targets depend on making theappropriate binary. slang: mkdirs $(SLANG) slangc: mkdirs $(SLANGC) - +slang-glslang: mkdirs $(SLANG_GLSLANG) +slang-test: mkdirs $(SLANG_TEST) +slang-eval-test: mkdirs $(SLANG_EVAL_TEST) $(SLANG): $(SLANG_SOURCES) $(SLANG_HEADERS) - $(CXX) $(SHARED_LIB_LDFLAGS) -o $@ -DSLANG_DYNAMIC_EXPORT $(SHARED_LIB_CFLAGS) $(SLANG_SOURCES) + $(CXX) $(SHARED_LIB_LDFLAGS) -o $@ -DSLANG_DYNAMIC_EXPORT $(SHARED_LIB_CFLAGS) $(SLANG_SOURCES) -ldl $(RELATIVE_RPATH_INCANTATION) $(SLANGC): $(SLANGC_SOURCES) $(SLANGC_HEADERS) $(SLANG) - $(CXX) $(LDFLAGS) -o $@ $(CFLAGS) $(SLANGC_SOURCES) $(CORE_SOURCES) -ldl $(RELATIVE_RPATH_INCANTATION) -lslang + $(CXX) $(LDFLAGS) -o $@ $(CFLAGS) $(SLANGC_SOURCES) -ldl $(RELATIVE_RPATH_INCANTATION) -lslang + +$(SLANG_GLSLANG): $(SLANG_GLSLANG_SOURCES) $(SLANG_GLSLANG_HEADERS) + $(CXX) $(SHARED_LIB_LDFLAGS) -pthread -o $@ -Iexternal/glslang/ $(SHARED_LIB_CFLAGS) $(SLANG_GLSLANG_SOURCES) +$(SLANG_TEST): $(SLANG_TEST_SOURCES) $(SLANG_TEST_HEADERS) $(SLANG) + $(CXX) $(LDFLAGS) -o $@ $(CFLAGS) $(SLANG_TEST_SOURCES) -ldl $(RELATIVE_RPATH_INCANTATION) -lslang +$(SLANG_EVAL_TEST): $(SLANG_EVAL_TEST_SOURCES) $(SLANG) + $(CXX) $(LDFLAGS) -o $@ $(CFLAGS) $(SLANG_EVAL_TEST_SOURCES) $(RELATIVE_RPATH_INCANTATION) -lslang $(OUTPUTDIR): mkdir -p $(OUTPUTDIR) -test: - # TODO need to actually run the test runner +test: $(SLANG_TEST) $(SLANG_EVAL_TEST) + $(SLANG_TEST) -bindir $(OUTPUTDIR) -category $(SLANG_TEST_CATEGORY) clean: rm -rf $(OUTPUTDIR) @@ -1,6 +1,6 @@ # Slang -[](https://ci.appveyor.com/project/shader-slang/slang/branch/master) +[](https://ci.appveyor.com/project/shader-slang/slang/branch/master) [](https://travis-ci.org/shader-slang/slang) Slang is a library and a stand-alone compiler for working with real-time shader code. It can be used with existing HLSL or GLSL code, but also supports a new HLSL-like shading language, also called Slang. diff --git a/source/core/platform.cpp b/source/core/platform.cpp index dbb536b0f..374606e4a 100644 --- a/source/core/platform.cpp +++ b/source/core/platform.cpp @@ -8,6 +8,7 @@ #undef WIN32_LEAN_AND_MEAN #undef NOMINMAX #else + #include "slang-string.h" #include <dlfcn.h> #endif @@ -27,7 +28,19 @@ namespace Slang } #else { - void* h = dlopen(name, RTLD_LOCAL); + String fullName; + fullName.append("lib"); + fullName.append(name); + fullName.append(".so"); + + void* h = dlopen(fullName.Buffer(), RTLD_NOW|RTLD_LOCAL); + if(!h) + { + if(auto msg = dlerror()) + { + fprintf(stderr, "error: %s\n", msg); + } + } result.handle = (Handle) h; } diff --git a/source/core/slang-string.cpp b/source/core/slang-string.cpp index 5a3d8e4f9..460a077b5 100644 --- a/source/core/slang-string.cpp +++ b/source/core/slang-string.cpp @@ -172,14 +172,26 @@ namespace Slang else { List<char> buf; - Slang::Encoding::UTF16->GetBytes(buf, *this); + switch(sizeof(wchar_t)) + { + case 2: + Slang::Encoding::UTF16->GetBytes(buf, *this); + break; + + case 4: + Slang::Encoding::UTF32->GetBytes(buf, *this); + break; + + default: + break; + } auto length = buf.Count() / sizeof(wchar_t); if (outLength) *outLength = length; - buf.Add(0); - buf.Add(0); + for(int ii = 0; ii < sizeof(wchar_t); ++ii) + buf.Add(0); wchar_t* beginData = (wchar_t*)buf.Buffer(); wchar_t* endData = beginData + length; diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp index 21a95c3b9..ae61823d1 100644 --- a/source/slang-glslang/slang-glslang.cpp +++ b/source/slang-glslang/slang-glslang.cpp @@ -28,6 +28,7 @@ #include <Windows.h> #endif +#include <memory> #include <sstream> // This is a wrapper to allow us to run the `glslang` compiler @@ -67,7 +68,11 @@ static void dump( // also output it for debug purposes std::string str((char const*)data, size); + #ifdef _WIN32 OutputDebugStringA(str.c_str()); + #else + fprintf(stderr, "%s\n", str.c_str());; + #endif } } @@ -177,7 +182,11 @@ static int glslang_dissassembleSPIRV(glslang_CompileRequest* request) } extern "C" +#ifdef _MSC_VER _declspec(dllexport) +#else +__attribute__((__visibility__("default"))) +#endif int glslang_compile(glslang_CompileRequest* request) { glslang::InitializeProcess(); diff --git a/source/slang-glslang/slang-glslang.h b/source/slang-glslang/slang-glslang.h index 748ad3dd1..22014de72 100644 --- a/source/slang-glslang/slang-glslang.h +++ b/source/slang-glslang/slang-glslang.h @@ -2,6 +2,8 @@ #ifndef SLANG_GLSLANG_H_INCLUDED #define SLANG_GLSLANG_H_INCLUDED +#include <stddef.h> + typedef void (*glslang_OutputFunc)(void const* data, size_t size, void* userData); enum diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 65abbb3f2..e51d111de 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -859,7 +859,7 @@ SLANG_API int spCompile( { auto req = REQ(request); -#if 1 +#if 0 // By default we'd like to catch as many internal errors as possible, // and report them to the user nicely (rather than just crash their // application). Internally Slang currently uses exceptions for this. diff --git a/tests/reflection/arrays.hlsl b/tests/reflection/arrays.hlsl index 8880aaebd..3ef512d31 100644 --- a/tests/reflection/arrays.hlsl +++ b/tests/reflection/arrays.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile ps_4_0 -target reflection-json +//TEST:SIMPLE:-profile ps_4_0 -target hlsl -target reflection-json // Confirm that we can generate reflection info for arrays // diff --git a/tests/reflection/gh-55.glsl b/tests/reflection/gh-55.glsl index 4ced68c9e..ab8177c77 100644 --- a/tests/reflection/gh-55.glsl +++ b/tests/reflection/gh-55.glsl @@ -1,4 +1,4 @@ -//TEST(smoke):SIMPLE:-profile ps_4_0 -target reflection-json +//TEST(smoke):SIMPLE:-profile ps_4_0 -target glsl -target reflection-json // Confirm fix for GitHub issue #55 diff --git a/tests/reflection/global-uniforms.hlsl b/tests/reflection/global-uniforms.hlsl index 7845af4b6..4ad1a4bbb 100644 --- a/tests/reflection/global-uniforms.hlsl +++ b/tests/reflection/global-uniforms.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile ps_4_0 -target reflection-json +//TEST:SIMPLE:-profile ps_4_0 -target hlsl -target reflection-json // Confirm that we handle uniforms at global scope diff --git a/tests/reflection/image-types.glsl b/tests/reflection/image-types.glsl index 73ecdaa82..bf7c396af 100644 --- a/tests/reflection/image-types.glsl +++ b/tests/reflection/image-types.glsl @@ -1,4 +1,4 @@ -//TEST(smoke):SIMPLE:-profile ps_4_0 -target reflection-json +//TEST(smoke):SIMPLE:-profile ps_4_0 -target glsl -target reflection-json // Confirm that we expose GLSL `image` types through reflection diff --git a/tests/reflection/multi-file.hlsl b/tests/reflection/multi-file.hlsl index 7f79f08c9..47264f2ec 100644 --- a/tests/reflection/multi-file.hlsl +++ b/tests/reflection/multi-file.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile ps_4_0 -entry mainFS -target reflection-json tests/reflection/multi-file-extra.hlsl -profile vs_4_0 -entry mainVS +//TEST:SIMPLE:-profile ps_4_0 -entry mainFS -target hlsl -target reflection-json tests/reflection/multi-file-extra.hlsl -profile vs_4_0 -entry mainVS // Here we are testing the case where multiple translation units are provided // at once, so that we want combined reflection information for the resulting diff --git a/tests/reflection/reflect-imported-code.hlsl b/tests/reflection/reflect-imported-code.hlsl index b95493f7e..04f58af19 100644 --- a/tests/reflection/reflect-imported-code.hlsl +++ b/tests/reflection/reflect-imported-code.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile ps_4_0 -target reflection-json +//TEST:SIMPLE:-profile ps_4_0 -target hlsl -target reflection-json // Confirm that shader parameters in imported modules get reflected properly. diff --git a/tests/reflection/reflection0.hlsl b/tests/reflection/reflection0.hlsl index 1f138894f..944bb795e 100644 --- a/tests/reflection/reflection0.hlsl +++ b/tests/reflection/reflection0.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile ps_4_0 -target reflection-json +//TEST:SIMPLE:-profile ps_4_0 -target hlsl -target reflection-json // Confirm that basic reflection info can be output diff --git a/tests/reflection/resource-in-cbuffer.hlsl b/tests/reflection/resource-in-cbuffer.hlsl index 9ab127363..b54399bd7 100644 --- a/tests/reflection/resource-in-cbuffer.hlsl +++ b/tests/reflection/resource-in-cbuffer.hlsl @@ -1,4 +1,4 @@ -//TEST(smoke):SIMPLE:-profile ps_4_0 -target reflection-json +//TEST(smoke):SIMPLE:-profile ps_4_0 -target hlsl -target reflection-json // Confirm that we can generate reflection // information for resources nested inside diff --git a/tests/reflection/std430-layout.glsl b/tests/reflection/std430-layout.glsl index 0e61556fc..8afda8e0c 100644 --- a/tests/reflection/std430-layout.glsl +++ b/tests/reflection/std430-layout.glsl @@ -1,5 +1,5 @@ #version 450 -//TEST(smoke):SIMPLE:-profile ps_4_0 -target reflection-json +//TEST(smoke):SIMPLE:-profile ps_4_0 -target glsl -target reflection-json // Confirm fix for GitHub issue #55 diff --git a/tests/reflection/thread-group-size.comp b/tests/reflection/thread-group-size.comp index 2edf2c2df..fac755433 100644 --- a/tests/reflection/thread-group-size.comp +++ b/tests/reflection/thread-group-size.comp @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-no-checking -target reflection-json +//TEST:SIMPLE:-no-checking -target glsl -target reflection-json // Confirm that we provide reflection data for the `local_size_*` attributes diff --git a/tests/reflection/thread-group-size.hlsl b/tests/reflection/thread-group-size.hlsl index 650a41e46..eb2fb98ad 100644 --- a/tests/reflection/thread-group-size.hlsl +++ b/tests/reflection/thread-group-size.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile cs_5_0 -target reflection-json +//TEST:SIMPLE:-profile cs_5_0 -target hlsl -target reflection-json // Confirm that we provide reflection data for the `numthreads` attribute diff --git a/tools/slang-test/main.cpp b/tools/slang-test/main.cpp index 563fc5dab..50716d2c4 100644 --- a/tools/slang-test/main.cpp +++ b/tools/slang-test/main.cpp @@ -179,7 +179,7 @@ void parseOptions(int* argc, char** argv) } // any arguments left over were positional arguments - argCount = (int)(writeCursor - argv); + argCount = (int)((char**)writeCursor - argv); argCursor = argv; argEnd = argCursor + argCount; @@ -548,14 +548,15 @@ OSError spawnAndWait(String testPath, OSProcessSpawner& spawner) { if( options.shouldBeVerbose ) { - fprintf(stderr, "%s\n", spawner.commandLine_.ToString().begin()); + String commandLine = spawner.getCommandLine(); + fprintf(stderr, "%s\n", commandLine.begin()); } OSError err = spawner.spawnAndWaitForCompletion(); if (err != kOSError_None) { // fprintf(stderr, "failed to run test '%S'\n", testPath.ToWString()); - error("failed to run test '%S'", testPath.ToWString()); + error("failed to run test '%S'", testPath.ToWString().begin()); } return err; } @@ -580,6 +581,8 @@ String getOutput(OSProcessSpawner& spawner) return actualOutputBuilder.ProduceString(); } +List<String> gFailedTests; + struct TestInput { // Path to the input file for the test @@ -609,7 +612,7 @@ TestResult runSimpleTest(TestInput& input) OSProcessSpawner spawner; - spawner.pushExecutablePath(String(options.binDir) + "slangc.exe"); + spawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix()); spawner.pushArgument(filePath999); for( auto arg : input.testOptions->args ) @@ -680,7 +683,7 @@ TestResult runEvalTest(TestInput& input) OSProcessSpawner spawner; - spawner.pushExecutablePath(String(options.binDir) + "slang-eval-test.exe"); + spawner.pushExecutablePath(String(options.binDir) + "slang-eval-test" + osGetExecutableSuffix()); spawner.pushArgument(filePath); for( auto arg : input.testOptions->args ) @@ -754,8 +757,8 @@ TestResult runCrossCompilerTest(TestInput& input) OSProcessSpawner actualSpawner; OSProcessSpawner expectedSpawner; - actualSpawner.pushExecutablePath(String(options.binDir) + "slangc.exe"); - expectedSpawner.pushExecutablePath(String(options.binDir) + "slangc.exe"); + actualSpawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix()); + expectedSpawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix()); actualSpawner.pushArgument(filePath); expectedSpawner.pushArgument(filePath + ".glsl"); @@ -827,7 +830,7 @@ TestResult generateHLSLBaseline(TestInput& input) auto outputStem = input.outputStem; OSProcessSpawner spawner; - spawner.pushExecutablePath(String(options.binDir) + "slangc.exe"); + spawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix()); spawner.pushArgument(filePath999); for( auto arg : input.testOptions->args ) @@ -873,7 +876,7 @@ TestResult runHLSLComparisonTest(TestInput& input) OSProcessSpawner spawner; - spawner.pushExecutablePath(String(options.binDir) + "slangc.exe"); + spawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix()); spawner.pushArgument(filePath999); for( auto arg : input.testOptions->args ) @@ -973,7 +976,7 @@ TestResult doGLSLComparisonTestRun( OSProcessSpawner spawner; - spawner.pushExecutablePath(String(options.binDir) + "slangc.exe"); + spawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix()); spawner.pushArgument(filePath999); if( langDefine ) @@ -1062,7 +1065,7 @@ TestResult doRenderComparisonTestRun(TestInput& input, char const* langOption, c OSProcessSpawner spawner; - spawner.pushExecutablePath(String(options.binDir) + "render-test.exe"); + spawner.pushExecutablePath(String(options.binDir) + "render-test" + osGetExecutableSuffix()); spawner.pushArgument(filePath999); for( auto arg : input.testOptions->args ) @@ -1217,6 +1220,11 @@ TestResult runHLSLAndGLSLComparisonTest(TestInput& input) return runHLSLRenderComparisonTestImpl(input, "-hlsl-rewrite", "-glsl-rewrite"); } +TestResult skipTest(TestInput& input) +{ + return kTestResult_Ignored; +} + TestResult runTest( String const& filePath, String const& outputStem, @@ -1230,10 +1238,17 @@ TestResult runTest( TestCallback callback; } kTestCommands[] = { { "SIMPLE", &runSimpleTest }, +#if SLANG_TEST_SUPPORT_HLSL { "COMPARE_HLSL", &runHLSLComparisonTest }, { "COMPARE_HLSL_RENDER", &runHLSLRenderComparisonTest }, { "COMPARE_HLSL_CROSS_COMPILE_RENDER", &runHLSLCrossCompileRenderComparisonTest}, { "COMPARE_HLSL_GLSL_RENDER", &runHLSLAndGLSLComparisonTest }, +#else + { "COMPARE_HLSL", &skipTest }, + { "COMPARE_HLSL_RENDER", &skipTest }, + { "COMPARE_HLSL_CROSS_COMPILE_RENDER", &skipTest}, + { "COMPARE_HLSL_GLSL_RENDER", &skipTest }, +#endif { "COMPARE_GLSL", &runGLSLComparisonTest }, { "CROSS_COMPILE", &runCrossCompilerTest }, { "EVAL", &runEvalTest }, @@ -1265,6 +1280,7 @@ struct TestContext int totalTestCount; int passedTestCount; int failedTestCount; + int ignoredTestCount; }; // deal with the fallout of a test having completed, whether @@ -1278,6 +1294,7 @@ void handleTestResult( { case kTestResult_Fail: context->failedTestCount++; + gFailedTests.Add(testName); break; case kTestResult_Pass: @@ -1285,8 +1302,7 @@ void handleTestResult( break; case kTestResult_Ignored: - // Note that we don't currently add ignored tests into - // the totals, which is kind of inaccurate. + context->ignoredTestCount++; break; default: @@ -1344,7 +1360,7 @@ void handleTestResult( if( err != kOSError_None ) { - error("failed to add appveyor test results for '%S'\n", testName.ToWString()); + error("failed to add appveyor test results for '%S'\n", testName.ToWString().begin()); #if 0 fprintf(stderr, "[%d] TEST RESULT: %s {%d} {%s} {%s}\n", err, spawner.commandLine_.Buffer(), @@ -1512,6 +1528,7 @@ void runTestsInDirectory( { if( shouldRunTest(context, file) ) { +// fprintf(stderr, "slang-test: found '%s'\n", file.Buffer()); runTestsOnFile(context, file); } } @@ -1571,6 +1588,30 @@ int main( return 0; } - printf("\n===\n%d%% of tests passed (%d/%d)\n===\n\n", (context.passedTestCount*100) / context.totalTestCount, context.passedTestCount, context.totalTestCount); - return context.passedTestCount == context.totalTestCount ? 0 : 1; + + auto passCount = context.passedTestCount; + auto rawTotal = context.totalTestCount; + auto ignoredCount = context.ignoredTestCount; + + auto runTotal = rawTotal - ignoredCount; + + printf("\n===\n%d%% of tests passed (%d/%d)", (passCount*100) / runTotal, passCount, runTotal); + if(ignoredCount) + { + printf(", %d tests ingored", ignoredCount); + } + printf("\n===\n\n"); + + if(context.failedTestCount) + { + printf("failing tests:\n"); + printf("---\n"); + for(auto name : gFailedTests) + { + printf("%s\n", name.Buffer()); + } + printf("---\n"); + } + + return passCount == runTotal ? 0 : 1; } diff --git a/tools/slang-test/os.cpp b/tools/slang-test/os.cpp index 40fd8afff..18f81318d 100644 --- a/tools/slang-test/os.cpp +++ b/tools/slang-test/os.cpp @@ -224,6 +224,11 @@ void OSProcessSpawner::pushArgument( commandLine_.Append(argument); } +Slang::String OSProcessSpawner::getCommandLine() +{ + return commandLine_; +} + OSError OSProcessSpawner::spawnAndWaitForCompletion() { SECURITY_ATTRIBUTES securityAttributes; @@ -372,8 +377,263 @@ OSError OSProcessSpawner::spawnAndWaitForCompletion() return kOSError_None; } +char const* osGetExecutableSuffix() +{ + return ".exe"; +} + #else -// TODO(tfoley): write a default POSIX implementation +static bool advance(OSFindFilesResult& result) +{ + result.entry_ = readdir(result.directory_); + return result.entry_ != NULL; +} + +static bool checkValidResult(OSFindFilesResult& result) +{ +// fprintf(stderr, "checkValidResullt(%s)\n", result.entry_->d_name); + + if (strcmp(result.entry_->d_name, ".") == 0) + return false; + + if (strcmp(result.entry_->d_name, "..") == 0) + return false; + + String path = result.directoryPath_ + + String(result.entry_->d_name); + +// fprintf(stderr, "stat(%s)\n", path.Buffer()); + struct stat fileInfo; + if(stat(path.Buffer(), &fileInfo) != 0) + return false; + + if(S_ISDIR(fileInfo.st_mode)) + path = path + "/"; + + + result.filePath_ = path; + return true; +} + +static bool adjustToValidResult(OSFindFilesResult& result) +{ + for (;;) + { + if(checkValidResult(result)) + return true; + + if (!advance(result)) + return false; + } +} + + +bool OSFindFilesResult::findNextFile() +{ +// fprintf(stderr, "OSFindFilesResult::findNextFile()\n"); + if (!advance(*this)) return false; + return adjustToValidResult(*this); +} + +OSFindFilesResult osFindFilesInDirectory( + Slang::String directoryPath) +{ + OSFindFilesResult result; + +// fprintf(stderr, "osFindFilesInDirectory(%s)\n", directoryPath.Buffer()); + + result.directory_ = opendir(directoryPath.Buffer()); + if(!result.directory_) + { + result.entry_ = NULL; + return result; + } + + result.directoryPath_ = directoryPath; + result.findNextFile(); + return result; +} + +OSFindFilesResult osFindChildDirectories( + Slang::String directoryPath) +{ + OSFindFilesResult result; + + result.directory_ = opendir(directoryPath.Buffer()); + if(!result.directory_) + { + result.entry_ = NULL; + return result; + } + + // TODO: Set attributes to ignore everything but directories + + result.directoryPath_ = directoryPath; + result.findNextFile(); + return result; +} + +// OSProcessSpawner + +void OSProcessSpawner::pushExecutableName( + Slang::String executableName) +{ + executableName_ = executableName; + pushArgument(executableName); + isExecutablePath_ = false; +} + +void OSProcessSpawner::pushExecutablePath( + Slang::String executablePath) +{ + executableName_ = executablePath; + pushArgument(executablePath); + isExecutablePath_ = true; +} + +void OSProcessSpawner::pushArgument( + Slang::String argument) +{ + arguments_.Add(argument); +} + +Slang::String OSProcessSpawner::getCommandLine() +{ + Slang::UInt argCount = arguments_.Count(); + + Slang::StringBuilder sb; + for(Slang::UInt ii = 0; ii < argCount; ++ii) + { + if(ii != 0) sb << " "; + sb << arguments_[ii]; + + } + return sb.ProduceString(); +} + +OSError OSProcessSpawner::spawnAndWaitForCompletion() +{ + List<char const*> argPtrs; + for(auto arg : arguments_) + { + argPtrs.Add(arg.Buffer()); + } + argPtrs.Add(NULL); + + int stdoutPipe[2]; + int stderrPipe[2]; + + if(pipe(stdoutPipe) == -1) + return kOSError_OperationFailed; + + if(pipe(stderrPipe) == -1) + return kOSError_OperationFailed; + + pid_t childProcessID = fork(); + if(childProcessID == 0) + { + // We are the child process. + + dup2(stdoutPipe[1], STDOUT_FILENO); + dup2(stderrPipe[1], STDERR_FILENO); + + close(stdoutPipe[0]); + close(stdoutPipe[1]); + + close(stderrPipe[0]); + close(stderrPipe[1]); + + execvp( + argPtrs[0], + (char* const*) &argPtrs[0]); + + // If we get here, then `exec` failed + fprintf(stderr, "error: `exec` failed\n"); + exit(1); + } + else + { + // We are the parent process + + close(stdoutPipe[1]); + close(stderrPipe[1]); + + int stdoutFD = stdoutPipe[0]; + int stderrFD = stderrPipe[0]; + + int maxFD = stdoutFD > stderrFD ? stdoutFD : stderrFD; + + fd_set readSet; + int result; + + int remainingCount = 2; + while(remainingCount) + { + FD_ZERO(&readSet); + FD_SET(stdoutFD, &readSet); + FD_SET(stderrFD, &readSet); + + result = select(maxFD + 1, &readSet, NULL, NULL, NULL); + + if(result == -1 || errno == EINTR) + continue; + + enum { kBufferSize = 1024 }; + char buffer[kBufferSize]; + + if(FD_ISSET(stdoutFD, &readSet)) + { + auto count = read(stdoutFD, buffer, kBufferSize); + if(count == 0) + remainingCount--; + + standardOutput_.append( + buffer, buffer + count); + } + + if(FD_ISSET(stderrFD, &readSet)) + { + auto count = read(stderrFD, buffer, kBufferSize); + if(count == 0) + remainingCount--; + + standardError_.append( + buffer, buffer + count); + } + } + + int childStatus = 0; + for(;;) + { + pid_t terminatedProcessID = wait(&childStatus); + if(terminatedProcessID == childProcessID) + { + if(WIFEXITED(childStatus)) + { + resultCode_ = (int)(int8_t)WEXITSTATUS(childStatus); + + } + else + { + resultCode_ = 1; + } + + close(stdoutPipe[0]); + close(stderrPipe[0]); + + return kOSError_None; + } + } + + } + + return kOSError_OperationFailed; +} + +char const* osGetExecutableSuffix() +{ + return ""; +} #endif diff --git a/tools/slang-test/os.h b/tools/slang-test/os.h index c6eb8f410..cc1fa4065 100644 --- a/tools/slang-test/os.h +++ b/tools/slang-test/os.h @@ -18,6 +18,14 @@ #undef NOMINMAX #else + +#include <dirent.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + #endif // A simple set of error codes for possible runtime failures @@ -41,6 +49,8 @@ struct OSFindFilesResult DWORD disallowedMask_; OSError error_; #else + DIR* directory_; + dirent* entry_; #endif bool findNextFile(); @@ -68,6 +78,7 @@ struct OSFindFilesResult #ifdef WIN32 Iterator result = { findHandle_ ? this : NULL }; #else + Iterator result = { entry_ ? this : NULL }; #endif return result; } @@ -138,6 +149,10 @@ struct OSProcessSpawner void pushArgument( Slang::String argument); + // Get a printable version of the command line + // that will be run (can be used for debugging) + Slang::String getCommandLine(); + // Attempt to spawn the process, and wait for it to complete. // Returns an error if the attempt to spawn and/or wait fails, // but returns `kOSError_None` if the process is run to completion, @@ -157,12 +172,15 @@ struct OSProcessSpawner Slang::String standardOutput_; Slang::String standardError_; ResultCode resultCode_; -#ifdef WIN32 Slang::String executableName_; +#ifdef WIN32 Slang::StringBuilder commandLine_; +#else + Slang::List<Slang::String> arguments_; +#endif // Is the executable specified by path, rather than just by name? bool isExecutablePath_; -#else -#endif }; + +char const* osGetExecutableSuffix(); |
