Skip to content

Instantly share code, notes, and snippets.

@emctague
Last active April 9, 2021 23:42
Show Gist options
  • Save emctague/4ff6f706b7e20c1608e82e3ded22fbf5 to your computer and use it in GitHub Desktop.
Save emctague/4ff6f706b7e20c1608e82e3ded22fbf5 to your computer and use it in GitHub Desktop.
GLSL Preprocessor

This is a simple Python 3.x GLSL Preprocessor script with an accompanying CMake function.

The script finds lines like this in a source GLSL file:

#include SomeLibrary.glsl

And substitutes them for that file's contents in the output, recursively processing any includes inside of that file, and inserting GLSL #line directives to ensure line numbers appear correctly.

CMake Use

Add the included CMake function declaration to your CMakeLists.txt or an included file, and add glslprepro.py in your project directory. (You could move them both to a subdirectory and adjust the CMake function appropriately, too!)

The function add_shader(TARGET, SHADER, ...DEPENDENCIES) will be available for use. The argument TARGET is the executable that will depend on these shaders (usually your main Game executable, or an Assets target.) SHADER is your source file name. ...DEPENDENCIES should list any other GLSL files your main file includes, to ensure that the output is generated properly whenever an included GLSL file is changed.

For example, if you have some project with main.cpp and a shader file test.glsl that depends on MyUtils.glsl:

add_executable(Game main.cpp)
add_shader(Game test.glsl MyUtils.glsl)

Manual Use

To use it manually, just invoke it with the source and output file paths:

python3 glslprepro.py SourceDirectory/MyShader.glsl OutputDirectory/MyShader.glsl

You may also omit the output file path in order to view output on the command line.

# GLSL Preprocessor
#
# This program handles #include directives in GLSL source files.
# These #include directives should not be wrapped in quotes or brackets.
#
# VALID:
# #include file.glsl
#
# INVALID:
# #include "file.glsl"
# #include <file.glsl>
#
#
# Command-line usage:
# python3 glslprepro.py [input-file] [output-file]
# e.g. python3 glslprepro.py source.glsl out/dest.glsl
#
# output-file can be omitted to write to stdout.
import sys
import os
def for_file(out, filename, core=True):
with open(filename, "r") as f:
if not core:
out.write("#line 1\n")
line_number = 1
for line in f:
l = line.strip()
if l.startswith('#include '):
for_file(out, os.path.dirname(os.path.realpath(filename)) + "/" + l[9:], False)
out.write("#line " + str((line_number + 1)) + "\n")
else:
out.write(line)
line_number += 1
if __name__ == "__main__":
if len(sys.argv) == 3:
with open(sys.argv[2], "w") as o:
for_file(o, sys.argv[1])
elif len(sys.argv) == 2:
for_file(sys.stdout, sys.argv[1])
else:
print("Usage: python3 glslprepro.py [input.glsl] [output.glsl (omit for stdout)]")
function(add_shader TARGET SHADER)
set(ShaderPath ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER})
set(OutPath ${CMAKE_CURRENT_BINARY_DIR}/${SHADER})
add_custom_command(
OUTPUT ${OutPath}
COMMAND python3 ${CMAKE_SOURCE_DIR}/glslprepro.py ${ShaderPath} ${OutPath}
DEPENDS ${ShaderPath} ${ARGN} ${CMAKE_SOURCE_DIR}/glslprepro.py
VERBATIM)
set_source_files_properties(${OutPath} PROPERTIES GENERATED TRUE)
target_sources(${TARGET} PRIVATE ${OutPath})
endfunction(add_shader)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment