Explicitly pass down paths to glslang/spirv-tools.

Windows and CMake really cannot get along with %PATH%, sigh ...
This commit is contained in:
Hans-Kristian Arntzen 2019-03-07 12:36:16 +01:00
parent 79d995caab
commit 074f765a83
3 changed files with 99 additions and 60 deletions

View File

@ -112,12 +112,6 @@ macro(spirv_cross_add_library name config_name)
export(TARGETS ${name} FILE ${config_name}Config.cmake)
endmacro()
macro(add_spirv_cross_test test-name)
add_test(NAME ${test-name} ${ARGN})
set_tests_properties(${test-name} PROPERTIES
ENVIRONMENT PATH=${CMAKE_CURRENT_SOURCE_DIR}/external/glslang-build/output/bin:${CMAKE_CURRENT_SOURCE_DIR}/external/spirv-tools-build/output/bin:$ENV{PATH})
endmacro()
set(spirv-cross-core-sources
${CMAKE_CURRENT_SOURCE_DIR}/GLSL.std.450.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_common.hpp
@ -268,8 +262,11 @@ if (SPIRV_CROSS_CLI)
find_program(spirv-cross-spirv-val NAMES spirv-val
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/external/spirv-tools-build/output/bin
NO_DEFAULT_PATH)
find_program(spirv-cross-spirv-opt NAMES spirv-opt
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/external/spirv-tools-build/output/bin
NO_DEFAULT_PATH)
if ((${spirv-cross-glslang} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-as} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-val} MATCHES "NOTFOUND"))
if ((${spirv-cross-glslang} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-as} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-val} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-opt} MATCHES "NOTFOUND"))
set(SPIRV_CROSS_ENABLE_TESTS OFF)
message("Could not find glslang or SPIRV-Tools build under external/. Run ./checkout_glslang_spirv_tools.sh and ./build_glslang_spirv_tools.sh. Testing will be disabled.")
else()
@ -278,8 +275,15 @@ if (SPIRV_CROSS_CLI)
message("Found glslangValidator in: ${spirv-cross-glslang}.")
message("Found spirv-as in: ${spirv-cross-spirv-as}.")
message("Found spirv-val in: ${spirv-cross-spirv-val}.")
message("Found spirv-opt in: ${spirv-cross-spirv-opt}.")
endif()
set(spirv-cross-externals
--glslang "${spirv-cross-glslang}"
--spirv-as "${spirv-cross-spirv-as}"
--spirv-opt "${spirv-cross-spirv-opt}"
--spirv-val "${spirv-cross-spirv-val}")
if (${PYTHONINTERP_FOUND} AND SPIRV_CROSS_ENABLE_TESTS)
if (${PYTHON_VERSION_MAJOR} GREATER 2)
add_executable(spirv-cross-c-api-test tests-other/c_api_test.c)
@ -288,46 +292,56 @@ if (SPIRV_CROSS_CLI)
if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang"))
target_compile_options(spirv-cross-c-api-test PRIVATE -std=c89 -Wall -Wextra)
endif()
add_spirv_cross_test(spirv-cross-c-api-test
add_test(NAME spirv-cross-c-api-test
COMMAND $<TARGET_FILE:spirv-cross-c-api-test> ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/c_api_test.spv)
add_spirv_cross_test(spirv-cross-test
add_test(NAME spirv-cross-test
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_spirv_cross_test(spirv-cross-test-no-opt
add_test(NAME spirv-cross-test-no-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-no-opt
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_spirv_cross_test(spirv-cross-test-metal
add_test(NAME spirv-cross-test-metal
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --metal --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-msl
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_spirv_cross_test(spirv-cross-test-metal-no-opt
add_test(NAME spirv-cross-test-metal-no-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --metal --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-msl-no-opt
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_spirv_cross_test(spirv-cross-test-hlsl
add_test(NAME spirv-cross-test-hlsl
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --hlsl --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-hlsl
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_spirv_cross_test(spirv-cross-test-hlsl-no-opt
add_test(NAME spirv-cross-test-hlsl-no-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --hlsl --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-hlsl-no-opt
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_spirv_cross_test(spirv-cross-test-opt
add_test(NAME spirv-cross-test-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --opt --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_spirv_cross_test(spirv-cross-test-metal-opt
add_test(NAME spirv-cross-test-metal-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --metal --opt --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-msl
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_spirv_cross_test(spirv-cross-test-hlsl-opt
add_test(NAME spirv-cross-test-hlsl-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --hlsl --opt --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-hlsl
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_spirv_cross_test(spirv-cross-test-reflection
add_test(NAME spirv-cross-test-reflection
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --reflect --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-reflection
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
endif()

View File

@ -16,6 +16,13 @@ import multiprocessing
import errno
from functools import partial
class Paths():
def __init__(self, glslang, spirv_as, spirv_val, spirv_opt):
self.glslang = glslang
self.spirv_as = spirv_as
self.spirv_val = spirv_val
self.spirv_opt = spirv_opt
def remove_file(path):
#print('Removing file:', path)
os.remove(path)
@ -131,21 +138,21 @@ def validate_shader_msl(shader, opt):
print('Error compiling Metal shader: ' + msl_path)
raise RuntimeError('Failed to compile Metal shader')
def cross_compile_msl(shader, spirv, opt):
def cross_compile_msl(shader, spirv, opt, paths):
spirv_path = create_temporary()
msl_path = create_temporary(os.path.basename(shader))
spirv_cmd = ['spirv-as', '-o', spirv_path, shader]
spirv_cmd = [paths.spirv_as, '-o', spirv_path, shader]
if '.preserve.' in shader:
spirv_cmd.append('--preserve-numeric-ids')
if spirv:
subprocess.check_call(spirv_cmd)
else:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
if opt:
subprocess.check_call(['spirv-opt', '--skip-validation', '-O', '-o', spirv_path, spirv_path])
subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path])
spirv_cross_path = './spirv-cross'
@ -166,7 +173,7 @@ def cross_compile_msl(shader, spirv, opt):
subprocess.check_call(msl_args)
if not shader_is_invalid_spirv(msl_path):
subprocess.check_call(['spirv-val', '--target-env', 'vulkan1.1', spirv_path])
subprocess.check_call([paths.spirv_val, '--target-env', 'vulkan1.1', spirv_path])
return (spirv_path, msl_path)
@ -201,8 +208,8 @@ def shader_to_win_path(shader):
return shader
ignore_fxc = False
def validate_shader_hlsl(shader, force_no_external_validation):
subprocess.check_call(['glslangValidator', '-e', 'main', '-D', '--target-env', 'vulkan1.1', '-V', shader])
def validate_shader_hlsl(shader, force_no_external_validation, paths):
subprocess.check_call([paths.glslang, '-e', 'main', '-D', '--target-env', 'vulkan1.1', '-V', shader])
is_no_fxc = '.nofxc.' in shader
global ignore_fxc
if (not ignore_fxc) and (not force_no_external_validation) and (not is_no_fxc):
@ -231,21 +238,21 @@ def shader_to_sm(shader):
else:
return '50'
def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation):
def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation, paths):
spirv_path = create_temporary()
hlsl_path = create_temporary(os.path.basename(shader))
spirv_cmd = ['spirv-as', '-o', spirv_path, shader]
spirv_cmd = [paths.spirv_as, '-o', spirv_path, shader]
if '.preserve.' in shader:
spirv_cmd.append('--preserve-numeric-ids')
if spirv:
subprocess.check_call(spirv_cmd)
else:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
if opt:
subprocess.check_call(['spirv-opt', '--skip-validation', '-O', '-o', spirv_path, spirv_path])
subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path])
spirv_cross_path = './spirv-cross'
@ -253,27 +260,27 @@ def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation):
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', hlsl_path, spirv_path, '--hlsl-enable-compat', '--hlsl', '--shader-model', sm])
if not shader_is_invalid_spirv(hlsl_path):
subprocess.check_call(['spirv-val', '--target-env', 'vulkan1.1', spirv_path])
subprocess.check_call([paths.spirv_val, '--target-env', 'vulkan1.1', spirv_path])
validate_shader_hlsl(hlsl_path, force_no_external_validation)
validate_shader_hlsl(hlsl_path, force_no_external_validation, paths)
return (spirv_path, hlsl_path)
def cross_compile_reflect(shader, spirv, opt):
def cross_compile_reflect(shader, spirv, opt, paths):
spirv_path = create_temporary()
reflect_path = create_temporary(os.path.basename(shader))
spirv_cmd = ['spirv-as', '-o', spirv_path, shader]
spirv_cmd = [paths.spirv_as, '-o', spirv_path, shader]
if '.preserve.' in shader:
spirv_cmd.append('--preserve-numeric-ids')
if spirv:
subprocess.check_call(spirv_cmd)
else:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
if opt:
subprocess.check_call(['spirv-opt', '--skip-validation', '-O', '-o', spirv_path, spirv_path])
subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path])
spirv_cross_path = './spirv-cross'
@ -281,33 +288,33 @@ def cross_compile_reflect(shader, spirv, opt):
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', reflect_path, spirv_path, '--reflect'])
return (spirv_path, reflect_path)
def validate_shader(shader, vulkan):
def validate_shader(shader, vulkan, paths):
if vulkan:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', shader])
subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', shader])
else:
subprocess.check_call(['glslangValidator', shader])
subprocess.check_call([paths.glslang, shader])
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt):
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt, paths):
spirv_path = create_temporary()
glsl_path = create_temporary(os.path.basename(shader))
if vulkan or spirv:
vulkan_glsl_path = create_temporary('vk' + os.path.basename(shader))
spirv_cmd = ['spirv-as', '-o', spirv_path, shader]
spirv_cmd = [paths.spirv_as, '-o', spirv_path, shader]
if '.preserve.' in shader:
spirv_cmd.append('--preserve-numeric-ids')
if spirv:
subprocess.check_call(spirv_cmd)
else:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
if opt and (not invalid_spirv):
subprocess.check_call(['spirv-opt', '--skip-validation', '-O', '-o', spirv_path, spirv_path])
subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path])
if not invalid_spirv:
subprocess.check_call(['spirv-val', '--target-env', 'vulkan1.1', spirv_path])
subprocess.check_call([paths.spirv_val, '--target-env', 'vulkan1.1', spirv_path])
extra_args = []
if eliminate:
@ -326,14 +333,14 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl
# A shader might not be possible to make valid GLSL from, skip validation for this case.
if not ('nocompat' in glsl_path):
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', glsl_path, spirv_path] + extra_args)
validate_shader(glsl_path, False)
validate_shader(glsl_path, False, paths)
else:
remove_file(glsl_path)
glsl_path = None
if vulkan or spirv:
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--vulkan-semantics', '--output', vulkan_glsl_path, spirv_path] + extra_args)
validate_shader(vulkan_glsl_path, True)
validate_shader(vulkan_glsl_path, True, paths)
# SPIR-V shaders might just want to validate Vulkan GLSL output, we don't always care about the output.
if not vulkan:
remove_file(vulkan_glsl_path)
@ -481,7 +488,7 @@ def shader_is_flatten_dimensions(shader):
def shader_is_noopt(shader):
return '.noopt.' in shader
def test_shader(stats, shader, update, keep, opt):
def test_shader(stats, shader, update, keep, opt, paths):
joined_path = os.path.join(shader[0], shader[1])
vulkan = shader_is_vulkan(shader[1])
desktop = shader_is_desktop(shader[1])
@ -495,7 +502,7 @@ def test_shader(stats, shader, update, keep, opt):
noopt = shader_is_noopt(shader[1])
print('Testing shader:', joined_path)
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt and (not noopt))
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt and (not noopt), paths)
# Only test GLSL stats if we have a shader following GL semantics.
if stats and (not vulkan) and (not is_spirv) and (not desktop):
@ -519,12 +526,12 @@ def test_shader(stats, shader, update, keep, opt):
a.append(str(i))
print(','.join(a), file = stats)
def test_shader_msl(stats, shader, update, keep, opt, force_no_external_validation):
def test_shader_msl(stats, shader, update, keep, opt, force_no_external_validation, paths):
joined_path = os.path.join(shader[0], shader[1])
print('\nTesting MSL shader:', joined_path)
is_spirv = shader_is_spirv(shader[1])
noopt = shader_is_noopt(shader[1])
spirv, msl = cross_compile_msl(joined_path, is_spirv, opt and (not noopt))
spirv, msl = cross_compile_msl(joined_path, is_spirv, opt and (not noopt), paths)
regression_check(shader, msl, update, keep, opt)
# Uncomment the following line to print the temp SPIR-V file path.
@ -540,34 +547,34 @@ def test_shader_msl(stats, shader, update, keep, opt, force_no_external_validati
remove_file(spirv)
def test_shader_hlsl(stats, shader, update, keep, opt, force_no_external_validation):
def test_shader_hlsl(stats, shader, update, keep, opt, force_no_external_validation, paths):
joined_path = os.path.join(shader[0], shader[1])
print('Testing HLSL shader:', joined_path)
is_spirv = shader_is_spirv(shader[1])
noopt = shader_is_noopt(shader[1])
spirv, hlsl = cross_compile_hlsl(joined_path, is_spirv, opt and (not noopt), force_no_external_validation)
spirv, hlsl = cross_compile_hlsl(joined_path, is_spirv, opt and (not noopt), force_no_external_validation, paths)
regression_check(shader, hlsl, update, keep, opt)
remove_file(spirv)
def test_shader_reflect(stats, shader, update, keep, opt):
def test_shader_reflect(stats, shader, update, keep, opt, paths):
joined_path = os.path.join(shader[0], shader[1])
print('Testing shader reflection:', joined_path)
is_spirv = shader_is_spirv(shader[1])
noopt = shader_is_noopt(shader[1])
spirv, reflect = cross_compile_reflect(joined_path, is_spirv, opt and (not noopt))
spirv, reflect = cross_compile_reflect(joined_path, is_spirv, opt and (not noopt), paths)
regression_check_reflect(shader, reflect, update, keep, opt)
remove_file(spirv)
def test_shader_file(relpath, stats, shader_dir, update, keep, opt, force_no_external_validation, backend):
def test_shader_file(relpath, stats, shader_dir, update, keep, opt, force_no_external_validation, backend, paths):
try:
if backend == 'msl':
test_shader_msl(stats, (shader_dir, relpath), update, keep, opt, force_no_external_validation)
test_shader_msl(stats, (shader_dir, relpath), update, keep, opt, force_no_external_validation, paths)
elif backend == 'hlsl':
test_shader_hlsl(stats, (shader_dir, relpath), update, keep, opt, force_no_external_validation)
test_shader_hlsl(stats, (shader_dir, relpath), update, keep, opt, force_no_external_validation, paths)
elif backend == 'reflect':
test_shader_reflect(stats, (shader_dir, relpath), update, keep, opt)
test_shader_reflect(stats, (shader_dir, relpath), update, keep, opt, paths)
else:
test_shader(stats, (shader_dir, relpath), update, keep, opt)
test_shader(stats, (shader_dir, relpath), update, keep, opt, paths)
return None
except Exception as e:
return e
@ -581,6 +588,8 @@ def test_shaders_helper(stats, backend, args):
relpath = os.path.relpath(path, args.folder)
all_files.append(relpath)
paths = Paths(args.glslang, args.spirv_as, args.spirv_val, args.spirv_opt)
# The child processes in parallel execution mode don't have the proper state for the global args variable, so
# at this point we need to switch to explicit arguments
if args.parallel:
@ -591,7 +600,7 @@ def test_shaders_helper(stats, backend, args):
results.append(pool.apply_async(test_shader_file,
args = (f, stats,
args.folder, args.update, args.keep, args.opt, args.force_no_external_validation,
backend)))
backend, paths)))
for res in results:
error = res.get()
@ -602,7 +611,7 @@ def test_shaders_helper(stats, backend, args):
sys.exit(1)
else:
for i in all_files:
e = test_shader_file(i, stats, args.folder, args.update, args.keep, args.opt, args.force_no_external_validation, backend)
e = test_shader_file(i, stats, args.folder, args.update, args.keep, args.opt, args.force_no_external_validation, backend, paths)
if e is not None:
print('Error:', e)
sys.exit(1)
@ -649,6 +658,18 @@ def main():
parser.add_argument('--parallel',
action = 'store_true',
help = 'Execute tests in parallel. Useful for doing regression quickly, but bad for debugging and stat output.')
parser.add_argument('--glslang',
default = 'glslangValidator',
help = 'Explicit path to glslangValidator')
parser.add_argument('--spirv-as',
default = 'spirv-as',
help = 'Explicit path to spirv-as')
parser.add_argument('--spirv-val',
default = 'spirv-val',
help = 'Explicit path to spirv-val')
parser.add_argument('--spirv-opt',
default = 'spirv-opt',
help = 'Explicit path to spirv-opt')
args = parser.parse_args()
if not args.folder:

View File

@ -1,5 +1,9 @@
/* Smoke test for the C API. */
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <spirv_cross_c.h>
#include <stdlib.h>
#include <stdio.h>