Skip to content

Commit

Permalink
glad: add option to make glad builds reproducible.
Browse files Browse the repository at this point in the history
  • Loading branch information
Dav1dde committed Sep 18, 2018
1 parent ddf83fb commit 6a10b46
Show file tree
Hide file tree
Showing 19 changed files with 67,010 additions and 31 deletions.
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
*.pyc
*.xml
/*.xml
*.kdev4
build/
*.o
Expand All @@ -11,8 +11,9 @@ main.c
.idea
dist/
*.egg-info
khrplatform.h
eglplatform.h
/khrplatform.h
/eglplatform.h
/vk_platform.h
/glad-rs/
/rust/
target/
Expand Down
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1 @@
recursive-include glad *.c *.h *.d *.volt *.rs *.toml
recursive-include glad *.c *.h *.d *.volt *.rs *.toml *.xml
6 changes: 5 additions & 1 deletion cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ endfunction()

# Create a glad library named "${TARGET}"
function(glad_add_library TARGET)
cmake_parse_arguments(GG "MERGE;QUIET;KEEP_SOURCES;STATIC;SHARED;MODULE;EXCLUDE_FROM_ALL" "LOCATION;LANGUAGE" "API;EXTENSIONS" ${ARGN})
cmake_parse_arguments(GG "MERGE;QUIET;REPRODUCIBLE;KEEP_SOURCES;STATIC;SHARED;MODULE;EXCLUDE_FROM_ALL" "LOCATION;LANGUAGE" "API;EXTENSIONS" ${ARGN})

if(NOT GG_LOCATION)
set(GG_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/gladsources/${TARGET}")
Expand Down Expand Up @@ -209,6 +209,10 @@ function(glad_add_library TARGET)
list(APPEND GLAD_ARGS --merge)
endif()

if(GG_REPRODUCIBLE)
list(APPEND GLAD_ARGS --reproducible)
endif()

set(GLAD_LANGUAGE "c")
if(GG_LANGUAGE)
string(TOLOWER "${GG_LANGUAGE}" "${GLAD_LANGUAGE}")
Expand Down
2 changes: 1 addition & 1 deletion example/c++/multiwin_mx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ find_package(glfw3 REQUIRED)
set(GLAD_SOURCES_DIR "${PROJECT_SOURCE_DIR}/../../..")
add_subdirectory("${GLAD_SOURCES_DIR}/cmake" glad_cmake)

glad_add_library(glad_gl_core_mx_33 MX API gl:core=3.3)
glad_add_library(glad_gl_core_mx_33 REPRODUCIBLE MX API gl:core=3.3)

add_executable(multiwin_mx
multiwin_mx.cpp
Expand Down
2 changes: 1 addition & 1 deletion example/c/egl_x11/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ find_package(X11 REQUIRED)
set(GLAD_SOURCES_DIR "${PROJECT_SOURCE_DIR}/../../..")
add_subdirectory("${GLAD_SOURCES_DIR}/cmake" glad_cmake)

glad_add_library(glad_egl_15_gles2_20 LOADER API egl=1.5 gles2=2.0)
glad_add_library(glad_egl_15_gles2_20 REPRODUCIBLE LOADER API egl=1.5 gles2=2.0)
add_executable(egl_x11
egl_x11.c
)
Expand Down
2 changes: 1 addition & 1 deletion example/c/vulkan_tri_glfw/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ add_subdirectory("${GLAD_SOURCES_DIR}/cmake" glad_cmake)

find_package(glfw3 REQUIRED)

glad_add_library(glad_vulkan_11 LOADER API vulkan=1.1)
glad_add_library(glad_vulkan_11 REPRODUCIBLE LOADER API vulkan=1.1)
add_executable(vulkan_tri_glfw
vulkan_tri_glfw.c
)
Expand Down
26 changes: 20 additions & 6 deletions glad/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import logging
import os

import glad.files
from glad.config import Config, ConfigOption
from glad.sink import LoggingSink
from glad.opener import URLOpener
Expand Down Expand Up @@ -48,7 +49,7 @@ class GlobalConfig(Config):
default=None,
description='Path to a file containing a list of extensions or '
'a comma separated list of extensions, if missing '
'all possible extensions are included'
'all possible extensions are included.'
)
MERGE = ConfigOption(
converter=bool,
Expand All @@ -57,11 +58,17 @@ class GlobalConfig(Config):
)
QUIET = ConfigOption(
converter=bool,
description='Disable logging'
description='Disable logging.'
)
REPRODUCIBLE = ConfigOption(
converter=bool,
default=False,
description='Makes the build reproducible by not fetching the latest '
'specification from Khronos.'
)


def load_specifications(specification_names, opener, specification_classes=None):
def load_specifications(specification_names, opener, specification_classes=None, reproducible=False):
specifications = dict()

if specification_classes is None:
Expand All @@ -71,7 +78,10 @@ def load_specifications(specification_names, opener, specification_classes=None)
Specification = specification_classes[name]
xml_name = name + '.xml'

if os.path.isfile(xml_name):
if reproducible and False:
logger.info('reproducible build, using packaged specification: %s', xml_name)
specification = Specification.from_file(glad.files.open_local(xml_name))
elif os.path.isfile(xml_name):
logger.info('using local specification: %s', xml_name)
specification = Specification.from_file(xml_name, opener=opener)
else:
Expand Down Expand Up @@ -132,11 +142,15 @@ def main(args=None):
global_config.validate() # Done before, but doesn't hurt
config.validate()

opener = URLOpener()
if global_config['REPRODUCIBLE']:
opener = glad.files.StaticFileOpener()
else:
opener = URLOpener()

specifications = load_specifications(
[value[0] for value in global_config['API'].values()],
opener=opener
opener=opener,
reproducible=global_config['REPRODUCIBLE']
)

generator = generators[ns.subparser_name](global_config['OUT_PATH'], opener=opener)
Expand Down
56 changes: 56 additions & 0 deletions glad/files/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import os.path
import logging
import shutil

try:
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse

try:
from pkg_resources import resource_exists, resource_stream
except ImportError:
def resource_exists(*args, **kwargs):
return False

def resource_stream(*args, **kwargs):
return None


BASE_PATH = os.path.abspath(os.path.dirname(__file__))

logger = logging.getLogger('glad.files')


class GladFileException(Exception):
pass


def open_local(name, *args, **kwargs):
# use pkg_resources when available, makes it work in zipped modules
# or other environments
if resource_exists(__name__, name):
logger.info('opening packaged resource: %r', name)
return resource_stream(__name__, name)

# fallback to filesystem
logger.info('opening packaged path: %r', name)
local_path = os.path.normpath(os.path.join(BASE_PATH, os.path.join(name)))
if not local_path.startswith(BASE_PATH):
raise GladFileException('unsafe file path, won\'t open {!r}'.format(local_path))
return open(local_path, *args, **kwargs)


class StaticFileOpener(object):
def urlopen(self, url, data=None, *args, **kwargs):
logger.debug('intercepted attempt to retrieve remote resource %r', url)
if data is not None:
raise GladFileException('can not resolve requests with payload')

filename = urlparse(url).path.rsplit('/', 1)[-1]
return open_local(filename, 'rb')

def urlretrieve(self, url, filename, *args, **kwargs):
with self.urlopen(url) as src:
with open(filename, 'wb') as dst:
shutil.copyfileobj(src, dst)
Loading

0 comments on commit 6a10b46

Please sign in to comment.