summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2017-09-29 13:43:08 -0700
committerGitHub <noreply@github.com>2017-09-29 13:43:08 -0700
commit8a0ebb9fa25fd44def17b03b3f8aa1a33ad77940 (patch)
tree3f855c1f8057e53763cb083c3b898effb559b80b
parent74f2f47cb63b02638270beecd20acea1a0f5665e (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.yml49
-rw-r--r--Makefile82
-rw-r--r--README.md2
-rw-r--r--source/core/platform.cpp15
-rw-r--r--source/core/slang-string.cpp18
-rw-r--r--source/slang-glslang/slang-glslang.cpp9
-rw-r--r--source/slang-glslang/slang-glslang.h2
-rw-r--r--source/slang/slang.cpp2
-rw-r--r--tests/reflection/arrays.hlsl2
-rw-r--r--tests/reflection/gh-55.glsl2
-rw-r--r--tests/reflection/global-uniforms.hlsl2
-rw-r--r--tests/reflection/image-types.glsl2
-rw-r--r--tests/reflection/multi-file.hlsl2
-rw-r--r--tests/reflection/reflect-imported-code.hlsl2
-rw-r--r--tests/reflection/reflection0.hlsl2
-rw-r--r--tests/reflection/resource-in-cbuffer.hlsl2
-rw-r--r--tests/reflection/std430-layout.glsl2
-rw-r--r--tests/reflection/thread-group-size.comp2
-rw-r--r--tests/reflection/thread-group-size.hlsl2
-rw-r--r--tools/slang-test/main.cpp73
-rw-r--r--tools/slang-test/os.cpp262
-rw-r--r--tools/slang-test/os.h24
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
diff --git a/Makefile b/Makefile
index 138322165..404432b81 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/README.md b/README.md
index 2a16273a4..866c89b00 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Slang
-[![AppVeyor build status](https://ci.appveyor.com/api/projects/status/3jptgsry13k6wdwp/branch/master?svg=true)](https://ci.appveyor.com/project/shader-slang/slang/branch/master)
+[![AppVeyor build status](https://ci.appveyor.com/api/projects/status/3jptgsry13k6wdwp/branch/master?svg=true)](https://ci.appveyor.com/project/shader-slang/slang/branch/master) [![Travis build status](https://travis-ci.org/shader-slang/slang.svg?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();