From ade114e12530b200e235f4af59b8bf8f10e2ddcc Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Wed, 17 Jun 2020 11:17:19 +0100 Subject: [PATCH] Generate build information from CHANGES.md This PR significantly reworks the way glslang is versioned. Instead of committing changes to the `GLSLANG_MINOR_VERSION` define in `glslang/Public/ShaderLang.h`, and using `make-revision` to generate `GLSLANG_PATCH_LEVEL` in `glslang/Include/revision.h`, all version information is now derived from the new `CHANGES.md` file. `CHANGES.md` acts as the single source of truth for glslang version information, along with a convenient place to put all release notes for each notable change made. `CHANGES.md` is parsed using the new `build_info.py` python script. This script can read basic template files to produce new source files, which it does to read the new `build_info.h.tmpl` to generate (at build time) a glslang private header at `/include/glslang/build_info.h`. I've written generators for each of the CMake, Bazel, gn, and `Android.mk` build scripts. The new version code conforms to the Semantic Versioning 2.0 spec. This new version is also used by the CMake rules to produce versioned shared objects, including a major-versioned SONAME. New APIs: --------- * `glslang::GetVersion()` returns a `Version` struct with the version major, minor, patch and flavor. Breaking API changes: --------------------- * The public defines `GLSLANG_MINOR_VERSION` and `GLSLANG_PATCH_LEVEL` have been entirely removed. * `glslang/Public/ShaderLang.h` and `glslang/Include/revision.h` have been deleted. * Instead, `/include/glslang/build_info.h` is created in the build directory, and `/include` is a CMake `PUBLIC` (dependee-inherited) include directory for the glslang targets. * `/include/glslang/build_info.h` contains the following new #defines: `GLSLANG_VERSION_MAJOR`, `GLSLANG_VERSION_MINOR`, `GLSLANG_VERSION_PATCH`, `GLSLANG_VERSION_FLAVOR`, `GLSLANG_VERSION_GREATER_THAN(major, minor, patch)`, `GLSLANG_VERSION_GREATER_OR_EQUAL_TO(major, minor, patch)`, `GLSLANG_VERSION_LESS_THAN(major, minor, patch)`, `GLSLANG_VERSION_LESS_OR_EQUAL_TO(major, minor, patch)` * The CMake install output directory contains a copy of `build_info.h` at: `include/glslang/build_info.h` * Python3 is now always required to build glslang (likely always required for transitive dependency builds). --- Android.mk | 52 ++++- BUILD.bazel | 15 ++ BUILD.gn | 33 +++- CHANGES.md | 24 +++ CMakeLists.txt | 67 ++++++- SPIRV/CMakeLists.txt | 10 +- SPIRV/GlslangToSpv.cpp | 33 ++-- StandAlone/StandAlone.cpp | 12 +- build_info.h.tmpl | 29 +++ build_info.py | 223 ++++++++++++++++++++++ glslang/CMakeLists.txt | 15 +- glslang/Include/revision.h | 3 - glslang/Include/revision.template | 13 -- glslang/MachineIndependent/ShaderLang.cpp | 19 +- glslang/Public/ShaderLang.h | 15 +- make-revision | 6 - 16 files changed, 493 insertions(+), 76 deletions(-) create mode 100644 CHANGES.md create mode 100644 build_info.h.tmpl create mode 100644 build_info.py delete mode 100644 glslang/Include/revision.h delete mode 100644 glslang/Include/revision.template delete mode 100755 make-revision diff --git a/Android.mk b/Android.mk index 48dfd1fb31..d9a9862844 100644 --- a/Android.mk +++ b/Android.mk @@ -33,6 +33,24 @@ LOCAL_PATH := $(call my-dir) +# Generate glslang/build_info.h +GLSLANG_GENERATED_INCLUDEDIR:=$(TARGET_OUT)/include +GLSLANG_BUILD_INFO_H:=$(GLSLANG_GENERATED_INCLUDEDIR)/glslang/build_info.h + +define gen_glslang_build_info_h +$(call generate-file-dir,$(GLSLANG_GENERATED_INCLUDEDIR)/dummy_filename) +$(GLSLANG_BUILD_INFO_H): \ + $(LOCAL_PATH)/build_info.py \ + $(LOCAL_PATH)/build_info.h.tmpl \ + $(LOCAL_PATH)/CHANGES.md + @$(HOST_PYTHON) $(LOCAL_PATH)/build_info.py \ + $(LOCAL_PATH) \ + -i $(LOCAL_PATH)/build_info.h.tmpl \ + -o $(GLSLANG_BUILD_INFO_H) + @echo "[$(TARGET_ARCH_ABI)] Generate : $(GLSLANG_BUILD_INFO_H) <= CHANGES.md" +endef +$(eval $(call gen_glslang_build_info_h)) + GLSLANG_OS_FLAGS := -DGLSLANG_OSINCLUDE_UNIX # AMD and NV extensions are turned on by default in upstream Glslang. GLSLANG_DEFINES:= -DAMD_EXTENSIONS -DNV_EXTENSIONS -DENABLE_HLSL $(GLSLANG_OS_FLAGS) @@ -55,18 +73,14 @@ LOCAL_C_INCLUDES:=$(LOCAL_PATH)/OGLCompiler LOCAL_STATIC_LIBRARIES:=OSDependent include $(BUILD_STATIC_LIBRARY) -# Build Glslang's HLSL parser library. +# Build the stubbed HLSL library. +# The HLSL source is now directly referenced by the glslang static library +# instead. include $(CLEAR_VARS) LOCAL_MODULE:=HLSL LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti $(GLSLANG_DEFINES) LOCAL_SRC_FILES:= \ - glslang/HLSL/hlslAttributes.cpp \ - glslang/HLSL/hlslGrammar.cpp \ - glslang/HLSL/hlslOpMap.cpp \ - glslang/HLSL/hlslParseables.cpp \ - glslang/HLSL/hlslParseHelper.cpp \ - glslang/HLSL/hlslScanContext.cpp \ - glslang/HLSL/hlslTokenStream.cpp + hlsl/stub.cpp LOCAL_C_INCLUDES:=$(LOCAL_PATH) \ $(LOCAL_PATH)/glslang/HLSL include $(BUILD_STATIC_LIBRARY) @@ -74,12 +88,23 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) GLSLANG_OUT_PATH=$(if $(call host-path-is-absolute,$(TARGET_OUT)),$(TARGET_OUT),$(abspath $(TARGET_OUT))) +# ShaderLang.cpp depends on the generated build_info.h +$(LOCAL_PATH)/glslang/MachineIndependent/ShaderLang.cpp: \ + $(GLSLANG_BUILD_INFO_H) + LOCAL_MODULE:=glslang LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti $(GLSLANG_DEFINES) LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH) LOCAL_SRC_FILES:= \ glslang/GenericCodeGen/CodeGen.cpp \ glslang/GenericCodeGen/Link.cpp \ + glslang/HLSL/hlslAttributes.cpp \ + glslang/HLSL/hlslGrammar.cpp \ + glslang/HLSL/hlslOpMap.cpp \ + glslang/HLSL/hlslParseables.cpp \ + glslang/HLSL/hlslParseHelper.cpp \ + glslang/HLSL/hlslScanContext.cpp \ + glslang/HLSL/hlslTokenStream.cpp \ glslang/MachineIndependent/attribute.cpp \ glslang/MachineIndependent/Constant.cpp \ glslang/MachineIndependent/glslang_tab.cpp \ @@ -109,14 +134,19 @@ LOCAL_SRC_FILES:= \ glslang/MachineIndependent/preprocessor/PpTokens.cpp LOCAL_C_INCLUDES:=$(LOCAL_PATH) \ $(LOCAL_PATH)/glslang/MachineIndependent \ + $(GLSLANG_GENERATED_INCLUDEDIR) \ $(GLSLANG_OUT_PATH) LOCAL_STATIC_LIBRARIES:=OSDependent OGLCompiler HLSL include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) + +# GlslangToSpv.cpp depends on the generated build_info.h +$(LOCAL_PATH)/glslang/MachineIndependent/GlslangToSpv.cpp: \ + $(GLSLANG_BUILD_INFO_H) + LOCAL_MODULE:=SPIRV LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror $(GLSLANG_DEFINES) -LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH) LOCAL_SRC_FILES:= \ SPIRV/GlslangToSpv.cpp \ SPIRV/InReadableOrder.cpp \ @@ -127,7 +157,9 @@ LOCAL_SRC_FILES:= \ SPIRV/SpvTools.cpp \ SPIRV/disassemble.cpp \ SPIRV/doc.cpp -LOCAL_C_INCLUDES:=$(LOCAL_PATH) $(LOCAL_PATH)/glslang/SPIRV +LOCAL_C_INCLUDES:=$(LOCAL_PATH) \ + $(LOCAL_PATH)/glslang/SPIRV \ + $(GLSLANG_GENERATED_INCLUDEDIR) LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)/glslang/SPIRV LOCAL_STATIC_LIBRARIES:=glslang include $(BUILD_STATIC_LIBRARY) diff --git a/BUILD.bazel b/BUILD.bazel index 7c976469ad..22ea2a3c03 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -43,6 +43,20 @@ licenses(["notice"]) exports_files(["LICENSE"]) +# Build information generation script +py_binary( + name = "build_info", + srcs = ["build_info.py"], +) + +genrule( + name = "gen_build_info_h", + srcs = ["CHANGES.md", "build_info.h.tmpl"], + outs = ["glslang/build_info.h"], + cmd = "$(location build_info) $$(dirname $(location CHANGES.md)) -i $(location build_info.h.tmpl) -o $(location glslang/build_info.h)", + tools = [":build_info"], +) + COMMON_COPTS = select({ "@bazel_tools//src/conditions:windows": [""], "//conditions:default": [ @@ -95,6 +109,7 @@ cc_library( "StandAlone/DirStackFileIncluder.h", "glslang/OSDependent/osinclude.h", "glslang/Public/ShaderLang.h", + ":gen_build_info_h", ], copts = COMMON_COPTS, defines = [ diff --git a/BUILD.gn b/BUILD.gn index f7a0441722..5d081f637b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -46,6 +46,29 @@ if (defined(is_fuchsia_tree) && is_fuchsia_tree) { _configs_to_add = [ "//build/config/compiler:no_chromium_code" ] } +action("glslang_build_info") { + script = "build_info.py" + + src_dir = "." + changes_file = "CHANGES.md" + template_file = "build_info.h.tmpl" + out_file = "${target_gen_dir}/include/glslang/build_info.h" + + inputs = [ + changes_file, + script, + template_file, + ] + outputs = [ + out_file + ] + args = [ + rebase_path(src_dir, root_build_dir), + "-i", rebase_path(template_file, root_build_dir), + "-o", rebase_path(out_file, root_build_dir), + ] +} + spirv_tools_dir = glslang_spirv_tools_dir config("glslang_public") { @@ -102,7 +125,6 @@ template("glslang_sources_common") { "glslang/Include/Types.h", "glslang/Include/arrays.h", "glslang/Include/intermediate.h", - "glslang/Include/revision.h", "glslang/MachineIndependent/Constant.cpp", "glslang/MachineIndependent/InfoSink.cpp", "glslang/MachineIndependent/Initialize.cpp", @@ -204,13 +226,18 @@ template("glslang_sources_common") { ] } + deps = [ ":glslang_build_info" ] + if (invoker.enable_opt) { - deps = [ + deps += [ + ":glslang_build_info", "${spirv_tools_dir}:spvtools_opt", "${spirv_tools_dir}:spvtools_val" ] } + include_dirs = [ "${target_gen_dir}/include" ] + configs -= _configs_to_remove configs += _configs_to_add } @@ -250,6 +277,8 @@ executable("glslang_validator") { ":glslang_standalone_sources", ] + include_dirs = [ "${target_gen_dir}/include" ] + configs -= _configs_to_remove configs += _configs_to_add } diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000000..1a7cbf5abe --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,24 @@ +# Revision history for `glslang` + +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](https://semver.org/). + +## 10.15.3847-dev 2020-06-16 + +### Breaking changes + +* The following files have been removed: + * `glslang/include/revision.h` + * `glslang/include/revision.template` + +The `GLSLANG_MINOR_VERSION` and `GLSLANG_PATCH_LEVEL` defines have been removed +from the public headers. \ +Instead each build script now uses the new `build_info.py` +script along with the `build_info.h.tmpl` and this `CHANGES.md` file to generate +the glslang build-time generated header `glslang/build_info.h`. + +The new public API to obtain the `glslang` version is `glslang::GetVersion()`. + +### Other changes +* `glslang` shared objects produced by CMake are now `SONAME` versioned using + [Semantic Versioning 2.0.0](https://semver.org/). diff --git a/CMakeLists.txt b/CMakeLists.txt index c9041d81b6..dce1909627 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,14 @@ if(BUILD_SHARED_LIBS) set(LIB_TYPE SHARED) endif() +if ("${CMAKE_BUILD_TYPE}" STREQUAL "") + # This logic inside SPIRV-Tools, which can upset build target dependencies + # if changed after targets are already defined. To prevent these issues, + # ensure CMAKE_BUILD_TYPE is assigned early and at the glslang root scope. + message(STATUS "No build type selected, default to Debug") + set(CMAKE_BUILD_TYPE "Debug") +endif() + option(SKIP_GLSLANG_INSTALL "Skip installation" ${SKIP_GLSLANG_INSTALL}) if(NOT ${SKIP_GLSLANG_INSTALL}) set(ENABLE_GLSLANG_INSTALL ON) @@ -247,12 +255,54 @@ endfunction(glslang_set_link_args) # CMake needs to find the right version of python, right from the beginning, # otherwise, it will find the wrong version and fail later -if(BUILD_EXTERNAL AND IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/External) - find_package(PythonInterp 3 REQUIRED) - - # We depend on these for later projects, so they should come first. - add_subdirectory(External) -endif() +find_package(PythonInterp 3 REQUIRED) + +# Root directory for build-time generated include files +set(GLSLANG_GENERATED_INCLUDEDIR "${CMAKE_BINARY_DIR}/include") + +################################################################################ +# Build version information generation +################################################################################ +set(GLSLANG_CHANGES_FILE "${CMAKE_SOURCE_DIR}/CHANGES.md") +set(GLSLANG_BUILD_INFO_PY "${CMAKE_SOURCE_DIR}/build_info.py") +set(GLSLANG_BUILD_INFO_H_TMPL "${CMAKE_SOURCE_DIR}/build_info.h.tmpl") +set(GLSLANG_BUILD_INFO_H "${GLSLANG_GENERATED_INCLUDEDIR}/glslang/build_info.h") + +# Command to build the build_info.h file +add_custom_command( + OUTPUT ${GLSLANG_BUILD_INFO_H} + COMMAND ${PYTHON_EXECUTABLE} "${GLSLANG_BUILD_INFO_PY}" + ${CMAKE_CURRENT_SOURCE_DIR} + "-i" ${GLSLANG_BUILD_INFO_H_TMPL} + "-o" ${GLSLANG_BUILD_INFO_H} + DEPENDS ${GLSLANG_BUILD_INFO_PY} + ${GLSLANG_CHANGES_FILE} + ${GLSLANG_BUILD_INFO_H_TMPL} + COMMENT "Generating ${GLSLANG_BUILD_INFO_H}") + +# Target to build the build_info.h file +add_custom_target(glslang-build-info DEPENDS ${GLSLANG_BUILD_INFO_H}) + +# Populate the CMake GLSLANG_VERSION* variables with the build version +# information. +execute_process( + COMMAND ${PYTHON_EXECUTABLE} "${GLSLANG_BUILD_INFO_PY}" + ${CMAKE_CURRENT_SOURCE_DIR} "..<-flavor>;;;;" + OUTPUT_VARIABLE "GLSLANG_VERSIONS" + OUTPUT_STRIP_TRAILING_WHITESPACE) +list(GET "GLSLANG_VERSIONS" 0 "GLSLANG_VERSION") +list(GET "GLSLANG_VERSIONS" 1 "GLSLANG_VERSION_MAJOR") +list(GET "GLSLANG_VERSIONS" 2 "GLSLANG_VERSION_MINOR") +list(GET "GLSLANG_VERSIONS" 3 "GLSLANG_VERSION_PATCH") +list(GET "GLSLANG_VERSIONS" 4 "GLSLANG_VERSION_FLAVOR") +configure_file(${GLSLANG_CHANGES_FILE} "${CMAKE_CURRENT_BINARY_DIR}/CHANGES.md") # Required to re-run cmake on version change + +# glslang_add_build_info_dependency() adds the glslang-build-info dependency and +# generated include directories to target. +function(glslang_add_build_info_dependency target) + target_include_directories(${target} PUBLIC $) + add_dependencies(${target} glslang-build-info) +endfunction() # glslang_only_export_explicit_symbols() makes the symbol visibility hidden by # default for when building shared libraries, and sets the @@ -269,6 +319,11 @@ function(glslang_only_export_explicit_symbols target) endif() endfunction() +if(BUILD_EXTERNAL AND IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/External) + # We depend on these for later projects, so they should come first. + add_subdirectory(External) +endif() + if(NOT TARGET SPIRV-Tools-opt) set(ENABLE_OPT OFF) endif() diff --git a/SPIRV/CMakeLists.txt b/SPIRV/CMakeLists.txt index 0f26bcca29..d699daddb6 100644 --- a/SPIRV/CMakeLists.txt +++ b/SPIRV/CMakeLists.txt @@ -72,8 +72,10 @@ add_library(SPIRV ${LIB_TYPE} ${SOURCES} ${HEADERS}) set_property(TARGET SPIRV PROPERTY FOLDER glslang) set_property(TARGET SPIRV PROPERTY POSITION_INDEPENDENT_CODE ON) target_include_directories(SPIRV PUBLIC - $ - $) + $ + $) + +glslang_add_build_info_dependency(SPIRV) if (ENABLE_SPVREMAPPER) add_library(SPVRemapper ${LIB_TYPE} ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS}) @@ -95,8 +97,8 @@ if(ENABLE_OPT) ) target_link_libraries(SPIRV PRIVATE MachineIndependent SPIRV-Tools-opt) target_include_directories(SPIRV PUBLIC - $ - $) + $ + $) else() target_link_libraries(SPIRV PRIVATE MachineIndependent) endif(ENABLE_OPT) diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 96a24af8ee..50384e5b35 100644 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -56,7 +56,9 @@ namespace spv { #include "../glslang/MachineIndependent/localintermediate.h" #include "../glslang/MachineIndependent/SymbolTable.h" #include "../glslang/Include/Common.h" -#include "../glslang/Include/revision.h" + +// Build-time generated includes +#include "glslang/build_info.h" #include #include @@ -1613,7 +1615,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, case EShLangAnyHit: case EShLangClosestHit: case EShLangMiss: - case EShLangCallable: + case EShLangCallable: { auto& extensions = glslangIntermediate->getRequestedExtensions(); if (extensions.find("GL_NV_ray_tracing") == extensions.end()) { @@ -2194,7 +2196,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI operandNode = node->getOperand()->getAsBinaryNode()->getLeft(); else operandNode = node->getOperand(); - + operandNode->traverse(this); spv::Id operand = spv::NoResult; @@ -3066,7 +3068,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; case 1: { - OpDecorations decorations = { precision, + OpDecorations decorations = { precision, TranslateNoContractionDecoration(node->getType().getQualifier()), TranslateNonUniformDecoration(node->getType().getQualifier()) }; result = createUnaryOperation( @@ -3187,7 +3189,7 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang // smear condition to vector, if necessary (AST is always scalar) // Before 1.4, smear like for mix(), starting with 1.4, keep it scalar if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4 && builder.isVector(trueValue)) { - condition = builder.smearScalar(spv::NoPrecision, condition, + condition = builder.smearScalar(spv::NoPrecision, condition, builder.makeVectorType(builder.makeBoolType(), builder.getNumComponents(trueValue))); } @@ -5207,10 +5209,10 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO assert(builder.isStructType(resultStructType)); //resType (SPIR-V type) contains 6 elements: - //Member 0 must be a Boolean type scalar(LOD), - //Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor), - //Member 2 must be a vector of integer type, whose Signedness operand is 0(offset), - //Member 3 must be a vector of integer type, whose Signedness operand is 0(mask), + //Member 0 must be a Boolean type scalar(LOD), + //Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor), + //Member 2 must be a vector of integer type, whose Signedness operand is 0(offset), + //Member 3 must be a vector of integer type, whose Signedness operand is 0(mask), //Member 4 must be a scalar of integer type, whose Signedness operand is 0(lod), //Member 5 must be a scalar of integer type, whose Signedness operand is 0(granularity). std::vector members; @@ -5223,7 +5225,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO //call ImageFootprintNV spv::Id res = builder.createTextureCall(precision, resType, sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params, signExtensionMask()); - + //copy resType (SPIR-V type) to resultStructType(OpenGL type) for (int i = 0; i < 5; i++) { builder.clearAccessChain(); @@ -5276,7 +5278,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO } #endif - std::vector result( 1, + std::vector result( 1, builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params, signExtensionMask()) ); @@ -6758,7 +6760,7 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv } else { scopeId = builder.makeUintConstant(spv::ScopeDevice); } - // semantics default to relaxed + // semantics default to relaxed spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() && glslangIntermediate->usingVulkanMemoryModel() ? spv::MemorySemanticsVolatileMask : @@ -8689,9 +8691,10 @@ void OutputSpvHex(const std::vector& spirv, const char* baseName, out.open(baseName, std::ios::binary | std::ios::out); if (out.fail()) printf("ERROR: Failed to open file: %s\n", baseName); - out << "\t// " << - GetSpirvGeneratorVersion() << "." << GLSLANG_MINOR_VERSION << "." << GLSLANG_PATCH_LEVEL << - std::endl; + out << "\t// " << + GetSpirvGeneratorVersion() << + GLSLANG_VERSION_MAJOR << "." << GLSLANG_VERSION_MINOR << "." << GLSLANG_VERSION_PATCH << + GLSLANG_VERSION_FLAVOR << std::endl; if (varName != nullptr) { out << "\t #pragma once" << std::endl; out << "const uint32_t " << varName << "[] = {" << std::endl; diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 79f13afefa..8836812742 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -44,7 +44,6 @@ #include "Worklist.h" #include "DirStackFileIncluder.h" #include "./../glslang/Include/ShHandle.h" -#include "./../glslang/Include/revision.h" #include "./../glslang/Public/ShaderLang.h" #include "../SPIRV/GlslangToSpv.h" #include "../SPIRV/GLSL.std.450.h" @@ -62,6 +61,9 @@ #include "../glslang/OSDependent/osinclude.h" +// Build-time generated includes +#include "glslang/build_info.h" + extern "C" { GLSLANG_EXPORT void ShOutputHtml(); } @@ -1278,13 +1280,13 @@ int singleMain() #endif if (Options & EOptionDumpBareVersion) { - printf("%d.%d.%d\n", - glslang::GetSpirvGeneratorVersion(), GLSLANG_MINOR_VERSION, GLSLANG_PATCH_LEVEL); + printf("%d:%d.%d.%d%s\n", glslang::GetSpirvGeneratorVersion(), GLSLANG_VERSION_MAJOR, GLSLANG_VERSION_MINOR, + GLSLANG_VERSION_PATCH, GLSLANG_VERSION_FLAVOR); if (workList.empty()) return ESuccess; } else if (Options & EOptionDumpVersions) { - printf("Glslang Version: %d.%d.%d\n", - glslang::GetSpirvGeneratorVersion(), GLSLANG_MINOR_VERSION, GLSLANG_PATCH_LEVEL); + printf("Glslang Version: %d:%d.%d.%d%s\n", glslang::GetSpirvGeneratorVersion(), GLSLANG_VERSION_MAJOR, + GLSLANG_VERSION_MINOR, GLSLANG_VERSION_PATCH, GLSLANG_VERSION_FLAVOR); printf("ESSL Version: %s\n", glslang::GetEsslVersionString()); printf("GLSL Version: %s\n", glslang::GetGlslVersionString()); std::string spirvVersion; diff --git a/build_info.h.tmpl b/build_info.h.tmpl new file mode 100644 index 0000000000..a73f3c3013 --- /dev/null +++ b/build_info.h.tmpl @@ -0,0 +1,29 @@ +#ifndef GLSLANG_BUILD_INFO +#define GLSLANG_BUILD_INFO + +#define GLSLANG_VERSION_MAJOR +#define GLSLANG_VERSION_MINOR +#define GLSLANG_VERSION_PATCH +#define GLSLANG_VERSION_FLAVOR "" + +#define GLSLANG_VERSION_GREATER_THAN(major, minor, patch) \ + (((major) > GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ + (((minor) > GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ + ((patch) > GLSLANG_VERSION_PATCH))))) + +#define GLSLANG_VERSION_GREATER_OR_EQUAL_TO(major, minor, patch) \ + (((major) > GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ + (((minor) > GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ + ((patch) >= GLSLANG_VERSION_PATCH))))) + +#define GLSLANG_VERSION_LESS_THAN(major, minor, patch) \ + (((major) < GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ + (((minor) < GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ + ((patch) < GLSLANG_VERSION_PATCH))))) + +#define GLSLANG_VERSION_LESS_OR_EQUAL_TO(major, minor, patch) \ + (((major) < GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ + (((minor) < GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ + ((patch) <= GLSLANG_VERSION_PATCH))))) + +#endif // GLSLANG_BUILD_INFO diff --git a/build_info.py b/build_info.py new file mode 100644 index 0000000000..b8d39fd8c0 --- /dev/null +++ b/build_info.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python + +# Copyright (c) 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import errno +import os +import os.path +import re +import subprocess +import sys +import time + +usage = """{} emits a string to stdout or file with project version information. + +args: [] [-i ] [-o ] + +Either or -i needs to be provided. + +The tool will output the provided string or file content with the following +tokens substituted: + + - The major version point parsed from the CHANGES.md file. + - The minor version point parsed from the CHANGES.md file. + - The point version point parsed from the CHANGES.md file. + - The optional dash suffix parsed from the CHANGES.md file (excluding + dash prefix). + <-flavor> - The optional dash suffix parsed from the CHANGES.md file (including + dash prefix). + - The optional date of the release in the form YYYY-MM-DD + - The git commit information for the directory taken from + "git describe" if that succeeds, or "git rev-parse HEAD" + if that succeeds, or otherwise a message containing the phrase + "unknown hash". + +-o is an optional flag for writing the output string to the given file. If + ommitted then the string is printed to stdout. +""" + +def mkdir_p(directory): + """Make the directory, and all its ancestors as required. Any of the + directories are allowed to already exist.""" + + if directory == "": + # We're being asked to make the current directory. + return + + try: + os.makedirs(directory) + except OSError as e: + if e.errno == errno.EEXIST and os.path.isdir(directory): + pass + else: + raise + + +def command_output(cmd, directory): + """Runs a command in a directory and returns its standard output stream. + + Captures the standard error stream. + + Raises a RuntimeError if the command fails to launch or otherwise fails. + """ + p = subprocess.Popen(cmd, + cwd=directory, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + (stdout, _) = p.communicate() + if p.returncode != 0: + raise RuntimeError('Failed to run %s in %s' % (cmd, directory)) + return stdout + + +def deduce_software_version(directory): + """Returns a software version number parsed from the CHANGES.md file + in the given directory. + + The CHANGES.md file describes most recent versions first. + """ + + # Match the first well-formed version-and-date line. + # Allow trailing whitespace in the checked-out source code has + # unexpected carriage returns on a linefeed-only system such as + # Linux. + pattern = re.compile(r'^#* +(\d+)\.(\d+)\.(\d+)(-\w+)? (\d\d\d\d-\d\d-\d\d)? *$') + changes_file = os.path.join(directory, 'CHANGES.md') + with open(changes_file, mode='r') as f: + for line in f.readlines(): + match = pattern.match(line) + if match: + return { + "major": match.group(1), + "minor": match.group(2), + "patch": match.group(3), + "flavor": match.group(4).lstrip("-"), + "-flavor": match.group(4), + "date": match.group(5), + } + raise Exception('No version number found in {}'.format(changes_file)) + + +def describe(directory): + """Returns a string describing the current Git HEAD version as descriptively + as possible. + + Runs 'git describe', or alternately 'git rev-parse HEAD', in directory. If + successful, returns the output; otherwise returns 'unknown hash, '.""" + try: + # decode() is needed here for Python3 compatibility. In Python2, + # str and bytes are the same type, but not in Python3. + # Popen.communicate() returns a bytes instance, which needs to be + # decoded into text data first in Python3. And this decode() won't + # hurt Python2. + return command_output(['git', 'describe'], directory).rstrip().decode() + except: + try: + return command_output( + ['git', 'rev-parse', 'HEAD'], directory).rstrip().decode() + except: + # This is the fallback case where git gives us no information, + # e.g. because the source tree might not be in a git tree. + # In this case, usually use a timestamp. However, to ensure + # reproducible builds, allow the builder to override the wall + # clock time with environment variable SOURCE_DATE_EPOCH + # containing a (presumably) fixed timestamp. + timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) + formatted = datetime.datetime.utcfromtimestamp(timestamp).isoformat() + return 'unknown hash, {}'.format(formatted) + +def parse_args(): + directory = None + input_string = None + input_file = None + output_file = None + + if len(sys.argv) < 2: + raise Exception("Invalid number of arguments") + + directory = sys.argv[1] + i = 2 + + if not sys.argv[i].startswith("-"): + input_string = sys.argv[i] + i = i + 1 + + while i < len(sys.argv): + opt = sys.argv[i] + i = i + 1 + + if opt == "-i" or opt == "-o": + if i == len(sys.argv): + raise Exception("Expected path after {}".format(opt)) + val = sys.argv[i] + i = i + 1 + if (opt == "-i"): + input_file = val + elif (opt == "-o"): + output_file = val + else: + raise Exception("Unknown flag {}".format(opt)) + + return { + "directory": directory, + "input_string": input_string, + "input_file": input_file, + "output_file": output_file, + } + +def main(): + args = None + try: + args = parse_args() + except Exception as e: + print(e) + print("\nUsage:\n") + print(usage.format(sys.argv[0])) + sys.exit(1) + + directory = args["directory"] + template = args["input_string"] + if template == None: + with open(args["input_file"], 'r') as f: + template = f.read() + output_file = args["output_file"] + + software_version = deduce_software_version(directory) + commit = describe(directory) + output = template \ + .replace("", software_version["major"]) \ + .replace("", software_version["minor"]) \ + .replace("", software_version["patch"]) \ + .replace("", software_version["flavor"]) \ + .replace("<-flavor>", software_version["-flavor"]) \ + .replace("", software_version["date"]) \ + .replace("", commit) + + if output_file is None: + print(output) + else: + mkdir_p(os.path.dirname(output_file)) + + if os.path.isfile(output_file): + with open(output_file, 'r') as f: + if output == f.read(): + return + + with open(output_file, 'w') as f: + f.write(output) + +if __name__ == '__main__': + main() diff --git a/glslang/CMakeLists.txt b/glslang/CMakeLists.txt index 98c8145751..139c5ece19 100644 --- a/glslang/CMakeLists.txt +++ b/glslang/CMakeLists.txt @@ -130,6 +130,8 @@ endif(ENABLE_HLSL) add_library(MachineIndependent STATIC ${MACHINEINDEPENDENT_SOURCES} ${MACHINEINDEPENDENT_HEADERS}) +glslang_add_build_info_dependency(MachineIndependent) + glslang_pch(SOURCES MachineIndependent/pch.cpp) target_link_libraries(MachineIndependent PRIVATE OGLCompiler OSDependent GenericCodeGen) @@ -153,18 +155,22 @@ set(GLSLANG_HEADERS Include/intermediate.h Include/PoolAlloc.h Include/ResourceLimits.h - Include/revision.h Include/ShHandle.h Include/Types.h) add_library(glslang ${LIB_TYPE} ${BISON_GLSLParser_OUTPUT_SOURCE} ${GLSLANG_SOURCES} ${GLSLANG_HEADERS}) -set_property(TARGET glslang PROPERTY FOLDER glslang) -set_property(TARGET glslang PROPERTY POSITION_INDEPENDENT_CODE ON) +set_target_properties(glslang PROPERTIES + FOLDER glslang + POSITION_INDEPENDENT_CODE ON + VERSION "${GLSLANG_VERSION}" + SOVERSION "${GLSLANG_VERSION_MAJOR}") target_link_libraries(glslang PRIVATE OGLCompiler OSDependent MachineIndependent) target_include_directories(glslang PUBLIC $ $) +glslang_add_build_info_dependency(glslang) + glslang_only_export_explicit_symbols(glslang) if(WIN32 AND BUILD_SHARED_LIBS) @@ -210,4 +216,7 @@ if(ENABLE_GLSLANG_INSTALL) get_filename_component(dir ${file} DIRECTORY) install(FILES ${file} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/glslang/${dir}) endforeach() + + install(FILES ${GLSLANG_BUILD_INFO_H} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/glslang) + endif(ENABLE_GLSLANG_INSTALL) diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h deleted file mode 100644 index 2012f12f45..0000000000 --- a/glslang/Include/revision.h +++ /dev/null @@ -1,3 +0,0 @@ -// This header is generated by the make-revision script. - -#define GLSLANG_PATCH_LEVEL 3847 diff --git a/glslang/Include/revision.template b/glslang/Include/revision.template deleted file mode 100644 index 4a16beeb0f..0000000000 --- a/glslang/Include/revision.template +++ /dev/null @@ -1,13 +0,0 @@ -// The file revision.h should be updated to the latest version, somehow, on -// check-in, if glslang has changed. -// -// revision.template is the source for revision.h when using SubWCRev as the -// method of updating revision.h. You don't have to do it this way, the -// requirement is only that revision.h gets updated. -// -// revision.h is under source control so that not all consumers of glslang -// source have to figure out how to create revision.h just to get a build -// going. However, if it is not updated, it can be a version behind. - -#define GLSLANG_REVISION "$WCREV$" -#define GLSLANG_DATE "$WCDATE$" diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index 476d179840..9c8610c929 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -72,6 +72,9 @@ // token to print ", but none of that seems appropriate for this file. #include "preprocessor/PpTokens.h" +// Build-time generated includes +#include "glslang/build_info.h" + namespace { // anonymous namespace for file-local functions and symbols // Total number of successful initializers of glslang: a refcount @@ -1684,19 +1687,29 @@ int ShGetUniformLocation(const ShHandle handle, const char* name) namespace glslang { -#include "../Include/revision.h" +Version GetVersion() +{ + Version version; + version.major = GLSLANG_VERSION_MAJOR; + version.minor = GLSLANG_VERSION_MINOR; + version.patch = GLSLANG_VERSION_PATCH; + version.flavor = GLSLANG_VERSION_FLAVOR; + return version; +} #define QUOTE(s) #s #define STR(n) QUOTE(n) const char* GetEsslVersionString() { - return "OpenGL ES GLSL 3.20 glslang Khronos. " STR(GLSLANG_MINOR_VERSION) "." STR(GLSLANG_PATCH_LEVEL); + return "OpenGL ES GLSL 3.20 glslang Khronos. " STR(GLSLANG_VERSION_MAJOR) "." STR(GLSLANG_VERSION_MINOR) "." STR( + GLSLANG_VERSION_PATCH) GLSLANG_VERSION_FLAVOR; } const char* GetGlslVersionString() { - return "4.60 glslang Khronos. " STR(GLSLANG_MINOR_VERSION) "." STR(GLSLANG_PATCH_LEVEL); + return "4.60 glslang Khronos. " STR(GLSLANG_VERSION_MAJOR) "." STR(GLSLANG_VERSION_MINOR) "." STR( + GLSLANG_VERSION_PATCH) GLSLANG_VERSION_FLAVOR; } int GetKhronosToolId() diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h index 897a057c7b..e3909f6374 100644 --- a/glslang/Public/ShaderLang.h +++ b/glslang/Public/ShaderLang.h @@ -51,7 +51,7 @@ #ifdef GLSLANG_IS_SHARED_LIBRARY #ifdef _WIN32 - #if GLSLANG_EXPORTING + #ifdef GLSLANG_EXPORTING #define GLSLANG_EXPORT __declspec(dllexport) #else #define GLSLANG_EXPORT __declspec(dllimport) @@ -74,11 +74,6 @@ extern "C" { #endif -// This should always increase, as some paths to do not consume -// a more major number. -// It should increment by one when new functionality is added. -#define GLSLANG_MINOR_VERSION 15 - // // Call before doing any other compiler/linker operations. // @@ -399,6 +394,14 @@ class TInfoSink; namespace glslang { +struct Version { + int major; + int minor; + int patch; + const char* flavor; +}; + +GLSLANG_EXPORT Version GetVersion(); GLSLANG_EXPORT const char* GetEsslVersionString(); GLSLANG_EXPORT const char* GetGlslVersionString(); GLSLANG_EXPORT int GetKhronosToolId(); diff --git a/make-revision b/make-revision deleted file mode 100755 index a89ff08772..0000000000 --- a/make-revision +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -( -echo "// This header is generated by the make-revision script." -echo -echo \#define GLSLANG_PATCH_LEVEL `git log --oneline | wc -l` -) > glslang/Include/revision.h