From 20b4a77872ece3153b7afa3e2ca3fe24497485c6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 19 Aug 2023 17:56:50 +1000 Subject: [PATCH] datatoc: exclude the initial C-style comment from GLSL/MSL/Cuda files Add optional argument `STRIP_LEADING_C_COMMENTS` to CMake macros: data_to_c_simple & data_to_c. Strip leading C-style comments that don't bloat binary size. Comments are replaced with blank lines so line numbers in error messages match. Reduces Blender's binary size by ~70kb. --- build_files/cmake/macros.cmake | 28 +++- intern/opencolorio/CMakeLists.txt | 2 +- intern/opensubdiv/CMakeLists.txt | 6 +- source/blender/compositor/CMakeLists.txt | 1 + .../realtime_compositor/CMakeLists.txt | 2 +- source/blender/datatoc/datatoc.cc | 136 +++++++++++++++++- source/blender/draw/CMakeLists.txt | 2 +- source/blender/gpu/CMakeLists.txt | 4 +- 8 files changed, 169 insertions(+), 12 deletions(-) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 86ab093d160..c1aaa9dbdc5 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -1096,7 +1096,8 @@ function(delayed_do_install endif() endfunction() - +# Same as above but generates the var name and output automatic. +# Takes optional: `STRIP_LEADING_C_COMMENTS` argument. function(data_to_c file_from file_to list_to_add @@ -1107,17 +1108,27 @@ function(data_to_c get_filename_component(_file_to_path ${file_to} PATH) + set(optional_args "") + foreach(f ${ARGN}) + if (f STREQUAL "STRIP_LEADING_C_COMMENTS") + set(optional_args "--options=strip_leading_c_comments") + else() + message(FATAL_ERROR "Unknown optional argument ${f} to \"data_to_c\"") + endif() + endforeach() + add_custom_command( OUTPUT ${file_to} COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path} - COMMAND "$" ${file_from} ${file_to} + COMMAND "$" ${file_from} ${file_to} ${optional_args} DEPENDS ${file_from} datatoc) set_source_files_properties(${file_to} PROPERTIES GENERATED TRUE) endfunction() -# same as above but generates the var name and output automatic. +# Same as above but generates the var name and output automatic. +# Takes optional: `STRIP_LEADING_C_COMMENTS` argument. function(data_to_c_simple file_from list_to_add @@ -1134,10 +1145,19 @@ function(data_to_c_simple get_filename_component(_file_to_path ${_file_to} PATH) + set(optional_args "") + foreach(f ${ARGN}) + if (f STREQUAL "STRIP_LEADING_C_COMMENTS") + set(optional_args "--options=strip_leading_c_comments") + else() + message(FATAL_ERROR "Unknown optional argument ${f} to \"data_to_c_simple\"") + endif() + endforeach() + add_custom_command( OUTPUT ${_file_to} COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path} - COMMAND "$" ${_file_from} ${_file_to} + COMMAND "$" ${_file_from} ${_file_to} ${optional_args} DEPENDS ${_file_from} datatoc) set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE) diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt index b8089df3934..98b7d8946e0 100644 --- a/intern/opencolorio/CMakeLists.txt +++ b/intern/opencolorio/CMakeLists.txt @@ -66,7 +66,7 @@ if(WITH_OPENCOLORIO) set(GLSL_C) foreach(GLSL_FILE ${GLSL_SRC}) - data_to_c_simple(${GLSL_FILE} GLSL_C) + data_to_c_simple(${GLSL_FILE} GLSL_C STRIP_LEADING_C_COMMENTS) endforeach() blender_add_lib(bf_ocio_shaders "${GLSL_C}" "" "" "") diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index 53b89e47c5c..5879781b70f 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -87,7 +87,11 @@ if(WITH_OPENSUBDIV) add_definitions(-D_USE_MATH_DEFINES) endif() - data_to_c_simple(internal/evaluator/shaders/glsl_compute_kernel.glsl SRC) + data_to_c_simple( + internal/evaluator/shaders/glsl_compute_kernel.glsl + SRC + STRIP_LEADING_C_COMMENTS + ) else() list(APPEND SRC stub/opensubdiv_stub.cc diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index ee1113667cc..0b4fb47b815 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -612,6 +612,7 @@ if(WITH_COMPOSITOR_CPU) ${CMAKE_CURRENT_SOURCE_DIR}/operations/COM_OpenCLKernels.cl ${CMAKE_CURRENT_BINARY_DIR}/operations/COM_OpenCLKernels.cl.h SRC + STRIP_LEADING_C_COMMENTS ) add_definitions(-DCL_USE_DEPRECATED_OPENCL_1_1_APIS) diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index de5dc823bb8..80759585f5b 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -213,7 +213,7 @@ set(GLSL_SRC set(GLSL_C) foreach(GLSL_FILE ${GLSL_SRC}) - data_to_c_simple(${GLSL_FILE} GLSL_C) + data_to_c_simple(${GLSL_FILE} GLSL_C STRIP_LEADING_C_COMMENTS) endforeach() blender_add_lib(bf_compositor_shaders "${GLSL_C}" "" "" "") diff --git a/source/blender/datatoc/datatoc.cc b/source/blender/datatoc/datatoc.cc index f8ca59cf508..4147b1a0af3 100644 --- a/source/blender/datatoc/datatoc.cc +++ b/source/blender/datatoc/datatoc.cc @@ -15,6 +15,8 @@ #define MAX2(x, y) ((x) > (y) ? (x) : (y)) #define MAX3(x, y, z) MAX2(MAX2((x), (y)), (z)) +#define STRPREFIX(a, b) (strncmp((a), (b), strlen(b)) == 0) + static char *arg_basename(char *string) { char *lfslash, *lbslash; @@ -31,6 +33,95 @@ static char *arg_basename(char *string) return MAX3(string, lfslash, lbslash); } +/** + * Detect leading C-style comments and seek the file to it's end, + * returning the number of bytes skipped and setting `r_newlines` + * or return zero and seek to the file start. + * + * The number of newlines is used so the number of lines matches + * the generated data, so any errors provide useful line numbers + * (this could be made optional, as there may be cases where it's not helpful). + */ +static int strip_leading_c_comment(FILE *fpin, int size, int *r_newlines) +{ + *r_newlines = 0; + if (size < 4) { + return 0; + } + + enum { + IS_SPACE = 1, + IS_COMMENT = 2, + IS_COMMENT_MAYBE_BEG = 3, + IS_COMMENT_MAYBE_END = 4, + } context = IS_SPACE; + + /* Last known valid offset. */ + int offset_checkpoint = 0; + int newlines_checkpoint = 0; + + int offset = 0; + int newlines = 0; + + while (offset < size) { + const char c_curr = getc(fpin); + offset += 1; + + if (context == IS_SPACE) { + if (c_curr == ' ' || c_curr == '\t' || c_curr == '\n') { + /* Pass. */ + } + else if (c_curr == '/') { + context = IS_COMMENT_MAYBE_BEG; + } + else { + /* Non-space and non-comment, exit. */ + break; + } + } + else if (context == IS_COMMENT) { + if (c_curr == '*') { + context = IS_COMMENT_MAYBE_END; + } + } + else if (context == IS_COMMENT_MAYBE_BEG) { + if (c_curr == '*') { + context = IS_COMMENT; + } + else { + /* Non-comment text, exit. */ + break; + } + } + else if (context == IS_COMMENT_MAYBE_END) { + if (c_curr == '/') { + context = IS_SPACE; + } + else if (c_curr == '*') { + /* Pass. */ + } + else { + context = IS_COMMENT; + } + } + + if (c_curr == '\n') { + newlines += 1; + } + + if (context == IS_SPACE) { + offset_checkpoint = offset; + newlines_checkpoint = newlines; + } + } + + if (offset != offset_checkpoint) { + fseek(fpin, offset_checkpoint, SEEK_SET); + } + *r_newlines = newlines_checkpoint; + return offset_checkpoint; +} + int main(int argc, char **argv) { FILE *fpin, *fpout; @@ -38,11 +129,36 @@ int main(int argc, char **argv) int i; int argv_len; + bool strip_leading_c_comments_test = false; + int leading_newlines = 0; + if (argc < 2) { - printf("Usage: datatoc \n"); + printf( + "Usage: " + "datatoc [--options=strip_leading_c_comments]\n"); exit(1); } + if (argc > 3) { + const char *arg_extra = argv[3]; + const char *arg_transform = "--options="; + if (STRPREFIX(arg_extra, arg_transform)) { + /* We may want to have other options in the future. */ + const char *options = arg_extra + strlen(arg_transform); + if (strcmp(options, "strip_leading_c_comments") == 0) { + strip_leading_c_comments_test = true; + } + else { + printf("Unknown --options=<%s>\n", options); + exit(1); + } + } + else { + printf("Unknown argument <%s>, expected --options=[...] or none.\n", arg_extra); + exit(1); + } + } + fpin = fopen(argv[1], "rb"); if (!fpin) { printf("Unable to open input <%s>\n", argv[1]); @@ -55,6 +171,11 @@ int main(int argc, char **argv) size = ftell(fpin); fseek(fpin, 0L, SEEK_SET); + if (strip_leading_c_comments_test) { + const int size_offset = strip_leading_c_comment(fpin, size, &leading_newlines); + size -= size_offset; /* The comment is skipped, */ + } + if (argv[1][0] == '.') { argv[1]++; } @@ -82,8 +203,19 @@ int main(int argc, char **argv) fprintf(fpout, "extern const int datatoc_%s_size;\n", argv[1]); fprintf(fpout, "extern const char datatoc_%s[];\n\n", argv[1]); - fprintf(fpout, "const int datatoc_%s_size = %d;\n", argv[1], int(size)); + fprintf(fpout, "const int datatoc_%s_size = %d;\n", argv[1], int(leading_newlines + size)); fprintf(fpout, "const char datatoc_%s[] = {\n", argv[1]); + + if (leading_newlines) { + while (leading_newlines--) { + if (leading_newlines % 32 == 31) { + fprintf(fpout, "\n"); + } + fprintf(fpout, "%3d,", '\n'); + } + fprintf(fpout, "\n"); + } + while (size--) { /* Even though this file is generated and doesn't need new-lines, * these files may be loaded by developers when looking up symbols. diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index e54a9d5b284..d49ad00502a 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -834,7 +834,7 @@ set(GLSL_SRC set(GLSL_C) foreach(GLSL_FILE ${GLSL_SRC}) - data_to_c_simple(${GLSL_FILE} GLSL_C) + data_to_c_simple(${GLSL_FILE} GLSL_C STRIP_LEADING_C_COMMENTS) endforeach() blender_add_lib(bf_draw_shaders "${GLSL_C}" "" "" "") diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index a6bd8c2b7b7..45d1f7c7110 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -610,13 +610,13 @@ if(WITH_METAL_BACKEND) set(MSL_C) foreach(MSL_FILE ${MSL_SRC}) - data_to_c_simple(${MSL_FILE} MSL_C) + data_to_c_simple(${MSL_FILE} MSL_C STRIP_LEADING_C_COMMENTS) endforeach() endif() set(GLSL_C) foreach(GLSL_FILE ${GLSL_SRC}) - data_to_c_simple(${GLSL_FILE} GLSL_C) + data_to_c_simple(${GLSL_FILE} GLSL_C STRIP_LEADING_C_COMMENTS) endforeach() set(SHADER_C)