From b2a5b10d5957bd95605e7d1a7fce507bdba75e05 Mon Sep 17 00:00:00 2001 From: alin Date: Thu, 6 Feb 2025 13:49:44 +0100 Subject: [PATCH 01/13] Add types sub-module Utils to determine the type of a target value --- cmake/rsp/helpers.cmake | 2 + cmake/rsp/helpers/types.cmake | 355 ++++++++++++++++++++++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 cmake/rsp/helpers/types.cmake diff --git a/cmake/rsp/helpers.cmake b/cmake/rsp/helpers.cmake index 0d2f6e0..431182d 100644 --- a/cmake/rsp/helpers.cmake +++ b/cmake/rsp/helpers.cmake @@ -7,6 +7,8 @@ include_guard(GLOBAL) # Debug message(VERBOSE "rsp/helpers module included") +include("rsp/helpers/types") + if (NOT COMMAND "fail_in_source_build") #! fail_in_source_build : Fails when building project in the source directory diff --git a/cmake/rsp/helpers/types.cmake b/cmake/rsp/helpers/types.cmake new file mode 100644 index 0000000..c2bd243 --- /dev/null +++ b/cmake/rsp/helpers/types.cmake @@ -0,0 +1,355 @@ +# -------------------------------------------------------------------------------------------------------------- # +# Types +# -------------------------------------------------------------------------------------------------------------- # + +include_guard(GLOBAL) + +# Debug +message(VERBOSE "rsp/helpers/types module included") + +if (NOT COMMAND "is_int") + + #! is_int : Determine if value is an integer + # + # @param target_value The value in question + # @param output The variable to assign extracted result to + # + # @return + # output True or false + # + function(is_int target_value output) + set("${output}" false) + + # Resolve "value" from variable + if (DEFINED "${target_value}") + set(target_value "${${target_value}}") + endif () + + if (target_value MATCHES "^([\-\+]?)([0-9]+)$") + set("${output}" true) + endif () + + return(PROPAGATE "${output}") + endfunction() +endif () + +if (NOT COMMAND "is_float") + + #! is_float : Determine if value is a float + # + # @param target_value The value in question + # @param output The variable to assign extracted result to + # + # @return + # output True or false + # + function(is_float target_value output) + set("${output}" false) + + # Resolve "value" from variable + if (DEFINED "${target_value}") + set(target_value "${${target_value}}") + endif () + + if (target_value MATCHES "^([\-\+]?)([0-9]+)\.([0-9]+)$") + set("${output}" true) + endif () + + return(PROPAGATE "${output}") + endfunction() +endif () + +if (NOT COMMAND "is_numeric") + + #! is_numeric : Determine if value is numeric + # + # @param target_value The value in question + # @param output The variable to assign extracted result to + # + # @return + # output True or false + # + function(is_numeric target_value output) + set("${output}" false) + + # Resolve "value" from variable + if (DEFINED "${target_value}") + set(target_value "${${target_value}}") + endif () + + if (target_value MATCHES "^([\-\+]?)([0-9]+)$" OR target_value MATCHES "^([\-\+]?)([0-9]+)\.([0-9]+)$") + set("${output}" true) + endif () + + return(PROPAGATE "${output}") + endfunction() +endif () + +if (NOT COMMAND "is_bool") + + #! is_bool : Determine if value is a boolean + # + # Caution: Function only recognises `true` and `false` as + # boolean values. + # + # @see is_bool_like() + # + # @param target_value The value in question + # @param output The variable to assign extracted result to + # + # @return + # output True or false + # + function(is_bool target_value output) + set("${output}" false) + + # Resolve "value" from variable + if (DEFINED "${target_value}") + set(target_value "${${target_value}}") + endif () + + set(accepted "true;false") + string(TOLOWER "${target_value}" target_value) + + if (target_value IN_LIST accepted) + set("${output}" true) + endif () + + return(PROPAGATE "${output}") + endfunction() +endif () + +if (NOT COMMAND "is_bool_like") + + #! is_bool_like : Determine if value is a boolean + # + # Caution: Function recognises all values that cmake can + # evaluate as truthy or falsy. + # + # @see https://cmake.org/cmake/help/latest/command/if.html#constant + # @see https://cmake.org/cmake/help/latest/command/if.html#logic-operators + # + # @param target_value The value in question + # @param output The variable to assign extracted result to + # + # @return + # output True or false + # + function(is_bool_like target_value output) + set("${output}" false) + + # Resolve "value" from variable + if (DEFINED "${target_value}") + set(target_value "${${target_value}}") + endif () + + # ...a non-zero number (including floating point numbers) is also considered + # to be boolean (true). + # NOTE: negative values DO NOT evaluate to false! + is_numeric("${target_value}" is_num) + if (is_num AND "${target_value}" GREATER_EQUAL 0) + set("${output}" true) + return(PROPAGATE "${output}") + endif () + + set(accepted "on;yes;true;y;off;0;no;false;n;ignore;notfound") + string(TOLOWER "${target_value}" target_value) + string(LENGTH "${target_value}" length) + + if (target_value IN_LIST accepted OR length EQUAL 0 OR target_value MATCHES "-notfound$") + set("${output}" true) + endif () + + return(PROPAGATE "${output}") + endfunction() +endif () + +if (NOT COMMAND "is_list") + + #! is_list : Determine if value is a list of values + # + # @see https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#cmake-language-lists + # @see https://cmake.org/cmake/help/latest/command/list.html + # + # @param target_value The value in question + # @param output The variable to assign extracted result to + # + # @return + # output True or false + # + function(is_list target_value output) + set("${output}" false) + + # Resolve "value" from variable + if (DEFINED "${target_value}") + set(target_value "${${target_value}}") + endif () + + string(FIND "${target_value}" ";" has_separator) + list(LENGTH target_value length) + + if (NOT has_separator EQUAL -1 AND length GREATER 0) + set("${output}" true) + endif () + + return(PROPAGATE "${output}") + endfunction() +endif () + +if (NOT COMMAND "is_command") + + #! is_command : Determine if value is command, macro or function + # + # @see https://cmake.org/cmake/help/latest/command/if.html#command + # + # @param target_value The value in question + # @param output The variable to assign extracted result to + # + # @return + # output True or false + # + function(is_command target_value output) + set("${output}" false) + + # Resolve "value" from variable + if (DEFINED "${target_value}") + set(target_value "${${target_value}}") + endif () + + if (COMMAND "${target_value}") + set("${output}" true) + endif () + + return(PROPAGATE "${output}") + endfunction() +endif () + +if (NOT COMMAND "is_string") + + #! is_string : Determine if value is a string + # + # Warning: This function evaluates only to true, if given value + # is: + # - not numeric + # - not a boolean (true or false) + # - not a list (semicolon separated list) + # - not a command + # + # @see https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#variables + # @see is_numeric() + # @see is_bool() + # @see is_list() + # @see is_command() + # + # @param target_value The value in question + # @param output The variable to assign extracted result to + # + # @return + # output True or false + # + function(is_string target_value output) + set("${output}" false) + + # Resolve "value" from variable + if (DEFINED "${target_value}") + set(target_value "${${target_value}}") + endif () + + is_numeric("${target_value}" num) + is_bool("${target_value}" bool) + is_list("${target_value}" lst) + is_command("${target_value}" cmd) + + if (NOT num + AND NOT bool + AND NOT lst + AND NOT cmd + ) + set("${output}" true) + endif () + + return(PROPAGATE "${output}") + endfunction() +endif () + +if (NOT COMMAND "get_type") + + #! get_type : Determine the type of given value + # + # @see is_int() + # @see is_float() + # @see is_bool() + # @see is_list() + # @see is_command() + # @see is_string() + # + # @param target_value The value in question + # @param output The variable to assign extracted result to + # + # @return + # output String representation of the type (int, float, bool, list, command, or string). + # @throws If unable to determine target value's type + # + # + function(get_type target_value output) + set("${output}" "undefined") + + # Resolve "value" from variable + if (DEFINED "${target_value}") + set(target_value "${${target_value}}") + endif () + + # ---------------------------------------------------------------------------------------------- # + + is_string("${target_value}" str) + if (str) + set("${output}" "string") + return(PROPAGATE "${output}") + endif () + + # ---------------------------------------------------------------------------------------------- # + + is_int("${target_value}" int) + if (int) + set("${output}" "int") + return(PROPAGATE "${output}") + endif () + + # ---------------------------------------------------------------------------------------------- # + + is_float("${target_value}" float) + if (float) + set("${output}" "float") + return(PROPAGATE "${output}") + endif () + + # ---------------------------------------------------------------------------------------------- # + + is_bool("${target_value}" bool) + if (bool) + set("${output}" "bool") + return(PROPAGATE "${output}") + endif () + + # ---------------------------------------------------------------------------------------------- # + + is_list("${target_value}" lst) + if (lst) + set("${output}" "list") + return(PROPAGATE "${output}") + endif () + + # ---------------------------------------------------------------------------------------------- # + + is_command("${target_value}" cmd) + if (cmd) + set("${output}" "command") + return(PROPAGATE "${output}") + endif () + + # ---------------------------------------------------------------------------------------------- # + # Fail in case that the type cannot be determined! + + message(FATAL_ERROR "Unable to determine type of target value: ${target_value}") + endfunction() +endif () \ No newline at end of file From 81ca39cb625ae3a5823af5a95a9c69e20ce69566 Mon Sep 17 00:00:00 2001 From: alin Date: Thu, 6 Feb 2025 13:50:05 +0100 Subject: [PATCH 02/13] Add tests for is_[type] functions and for get_type() --- tests/unit/helpers/types_test.cmake | 370 ++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 tests/unit/helpers/types_test.cmake diff --git a/tests/unit/helpers/types_test.cmake b/tests/unit/helpers/types_test.cmake new file mode 100644 index 0000000..8f0f6fc --- /dev/null +++ b/tests/unit/helpers/types_test.cmake @@ -0,0 +1,370 @@ +include("rsp/testing") +include("rsp/helpers") + +define_test_case( + "Types Test" + LABELS "types;helpers" +) + +# -------------------------------------------------------------------------------------------------------------- # +# Data Providers +# -------------------------------------------------------------------------------------------------------------- # + +function(provides_values output) + # Format: + # | + # [@] | - list + set("${output}" + "foo|string" + "|string" + "?|string" + "0|int" + "-2|int" + "0.1|float" + "-0.1|float" + "true|bool" + "false|bool" + "a@b@c|list" # "@" must be replaced with ";" in test! + "define_test_case|command" + "define_test|command" + ) + return (PROPAGATE "${output}") +endfunction() + +# -------------------------------------------------------------------------------------------------------------- # +# Actual tests +# -------------------------------------------------------------------------------------------------------------- # + +define_test("can determine if integer" "can_determine_if_int") +function(can_determine_if_int) + + is_int(22 a) + assert_truthy(a MESSAGE "a should be an int") + + is_int(0 b) + assert_truthy(b MESSAGE "b should be an int") + + set(value 8) + is_int(value c) + assert_truthy(c MESSAGE "c should be an int") + + set(value -8) + is_int(value d) + assert_truthy(d MESSAGE "d should be an int") + + is_int(2.34 e) + assert_falsy(e MESSAGE "e should NOT be an int") + + set(value 1.123) + is_int(value f) + assert_falsy(f MESSAGE "f should NOT be an int") + + is_int("str" g) + assert_falsy(g MESSAGE "g should NOT be an int") + + is_int(true h) + assert_falsy(h MESSAGE "h should NOT be an int") + + is_int(false i) + assert_falsy(i MESSAGE "i should NOT be an int") + + set(my_list "foo;bar;zim") + is_int(my_list j) + assert_falsy(j MESSAGE "j should NOT be an int") +endfunction() + +define_test("can determine if float" "can_determine_if_float") +function(can_determine_if_float) + + is_float(22 a) + assert_falsy(a MESSAGE "a should NOT be a float") + + set(value 8) + is_float(value b) + assert_falsy(b MESSAGE "b should NOT be a float") + + is_float(2.34 c) + assert_truthy(c MESSAGE "c should be a float") + + set(value 1.123) + is_float(value d) + assert_truthy(d MESSAGE "d should be a float") + + is_float("str" e) + assert_falsy(e MESSAGE "e should NOT be a float") + + is_float(true f) + assert_falsy(f MESSAGE "f should NOT be a float") + + is_float(false g) + assert_falsy(g MESSAGE "g should NOT be a float") + + set(my_list "foo;bar;zim") + is_float(my_list h) + assert_falsy(h MESSAGE "g should NOT be a float") + + set(value -1.02) + is_float(value i) + assert_truthy(i MESSAGE "i should be a float") +endfunction() + +define_test("can determine if numeric" "can_determine_if_numeric") +function(can_determine_if_numeric) + + is_numeric(22 a) + assert_truthy(a MESSAGE "a should be numeric") + + set(value 8) + is_numeric(value b) + assert_truthy(b MESSAGE "b should be numeric") + + is_numeric(2.34 c) + assert_truthy(c MESSAGE "c should be numeric") + + set(value 1.123) + is_numeric(value d) + assert_truthy(d MESSAGE "d should be numeric") + + is_numeric("str" e) + assert_falsy(e MESSAGE "e should NOT be numeric") + + is_numeric(true f) + assert_falsy(f MESSAGE "f should NOT be numeric") + + is_numeric(false g) + assert_falsy(g MESSAGE "g should NOT be numeric") + + set(my_list "foo;bar;zim") + is_numeric(my_list h) + assert_falsy(h MESSAGE "g should NOT be numeric") + + set(value -22.02) + is_numeric(value i) + assert_truthy(i MESSAGE "i should be numeric") +endfunction() + +define_test("can determine if boolean" "can_determine_if_bool") +function(can_determine_if_bool) + + is_bool(22 a) + assert_falsy(a MESSAGE "a should NOT be a bool") + + set(value 8) + is_bool(value b) + assert_falsy(b MESSAGE "b should NOT be a bool") + + is_bool(2.34 c) + assert_falsy(c MESSAGE "c should NOT be a bool") + + set(value 1.123) + is_bool(value d) + assert_falsy(d MESSAGE "d should NOT be a bool") + + is_bool("str" e) + assert_falsy(e MESSAGE "e should NOT be a bool") + + is_bool(true f) + assert_truthy(f MESSAGE "f should be a bool") + + is_bool(false g) + assert_truthy(g MESSAGE "g should be a bool") + + set(my_list "foo;bar;zim") + is_bool(my_list h) + assert_falsy(h MESSAGE "g should NOT be a bool") +endfunction() + +define_test("can determine if boolean like" "can_determine_if_bool_like") +function(can_determine_if_bool_like) + + set(valid "1;on;yes;true;y;0;off;no;false;n;ignore;notfound") + foreach (v IN LISTS value) + is_bool_like(v result) + assert_truthy(result MESSAGE "${v} should be bool like") + endforeach () + + # ------------------------------------------------------------ # + + is_bool_like("" empty_str) + assert_truthy(empty_str MESSAGE "empty string should be bool like") + + # ------------------------------------------------------------ # + + is_bool_like("foo-NOTFOUND" end_with_not_found) + assert_truthy(end_with_not_found MESSAGE "string with '-NOTFOUND' should be bool like") + + # ------------------------------------------------------------ # + + is_bool_like(22 a) + assert_truthy(a MESSAGE "a should be bool like") + + set(value 8) + is_bool_like(value b) + assert_truthy(b MESSAGE "b should be bool like") + + is_bool_like(2.34 c) + assert_truthy(c MESSAGE "c should be bool like") + + set(value 1.123) + is_bool_like(value d) + assert_truthy(d MESSAGE "d should be bool like") + + # ------------------------------------------------------------ # + + is_bool_like("str" e) + assert_falsy(e MESSAGE "e should NOT be bool like") + + set(my_list "foo;bar;zim") + is_bool_like(my_list f) + assert_falsy(h MESSAGE "f should NOT be bool like") + + # ------------------------------------------------------------ # + + # NOTE: Negative numbers DO NOT evaluate to false in cmake! + set(my_negative_value "-1") +# if (NOT my_negative_value) +# message("Expected this to work...") +# endif () + is_bool_like(my_negative_value g) + assert_falsy(g MESSAGE "g should NOT be bool like") + +endfunction() + +define_test("can determine if list" "can_determine_if_list") +function(can_determine_if_list) + + set(list_a "aa;bbb;ccc") + is_list(list_a a) + assert_truthy(a MESSAGE "a should be a list") + + set(list_b aa bbb ccc) + is_list(list_b b) + assert_truthy(b MESSAGE "b should be a list") + + set(not_list "aa bbb ccc") + is_list(not_list c) + assert_falsy(c MESSAGE "c should NOT be a list") + + is_list("aa;bbb;ccc" d) + assert_truthy(d MESSAGE "d should be a list") + + is_list("aa bbb ccc" e) + assert_falsy(e MESSAGE "e should NOT be a list") + + is_list("foo" f) + assert_falsy(f MESSAGE "f should NOT be a list") + + is_list(1 g) + assert_falsy(g MESSAGE "g should NOT be a list") + + is_list(1.32 h) + assert_falsy(h MESSAGE "h should NOT be a list") + + is_list(-1 i) + assert_falsy(i MESSAGE "i should NOT be a list") + + is_list(false j) + assert_falsy(j MESSAGE "j should NOT be a list") +endfunction() + + +define_test("can determine if command" "can_determine_if_cmd") +function(can_determine_if_cmd) + + macro(my_macro) + endmacro() + is_command(my_macro a) + assert_truthy(a MESSAGE "a should be a command (macro)") + + function(my_function) + endfunction() + is_command(my_function b) + assert_truthy(b MESSAGE "b should be a command (function)") + + # Not sure if this even can be tested... + # add_custom_command(TARGET my_command + # PRE_BUILD + # COMMAND ${CMAKE_COMMAND} -E echo hello + # COMMENT "FOR TESTING PURPOSES ONLY" + # VERBATIM + # ) + # is_command(my_command c) + # assert_truthy(c MESSAGE "c should be a command (custom command)") + + set(my_var "") + is_command(my_var d) + assert_falsy(d MESSAGE "d should NOT be a command") + + set(fn_ref "my_function") + is_command(fn_ref e) + assert_truthy(e MESSAGE "e should be a command (reference)") + +endfunction() + +define_test("can determine if string" "can_determine_if_str") +function(can_determine_if_str) + + is_string("abc" a) + assert_truthy(a MESSAGE "a should be a string") + + set(my_str "foo") + is_string(my_str b) + assert_truthy(b MESSAGE "b should be a string") + + set(my_empty_str "") + is_string(my_empty_str c) + assert_truthy(c MESSAGE "c should be a string") + + is_string(my_undefined_var d) + assert_truthy(d MESSAGE "d should be a string") + + is_string(42 e) + assert_falsy(e MESSAGE "e should NOT be a string") + + is_string(-42.1 f) + assert_falsy(f MESSAGE "f should NOT be a string") + + set(list_a "a;b;c") + is_string(list_a g) + assert_falsy(g MESSAGE "g should NOT be a string") + + set(list_b aa bb cc) + is_string(list_b h) + assert_falsy(h MESSAGE "h should NOT be a string") + + set(not_list "aa bb cc") + is_string(not_list i) + assert_truthy(i MESSAGE "i should be a string") + + macro(my_macro) + endmacro() + is_string(my_macro j) + assert_falsy(j MESSAGE "j should NOT be a string") + + function(my_function) + endfunction() + is_string(my_function k) + assert_falsy(k MESSAGE "k should NOT be a string") + + set(fn_ref "my_function") + is_string(fn_ref l) + assert_falsy(l MESSAGE "l should NOT be a string") +endfunction() + +define_test("can determine type" "can_determine_type" DATA_PROVIDER "provides_values") +function(can_determine_type item) + + string(REPLACE "|" ";" parts "${item}") + list(GET parts 0 value) + list(GET parts 1 expected) + + string(FIND "${value}" "@" is_sublist) + if (NOT is_sublist EQUAL -1) + string(REPLACE "@" ";" value "${value}") + endif () + + message("Value: ${value}") + + get_type(value result) + assert_string_equals("${expected}" "${result}" MESSAGE "incorrect '${result}' type for value: ${value}") +endfunction() \ No newline at end of file From 26a039c4a39472f5924d99b063237da4bcea0082 Mon Sep 17 00:00:00 2001 From: alin Date: Thu, 6 Feb 2025 13:51:54 +0100 Subject: [PATCH 03/13] Change release notes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9fc596..48500f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `output()` helper, in `output.cmake`. * Support for ANSI, in `output.cmake`. * PSR inspired logging functions, in `logging.cmake`. +* Utils for determining the datatype of a target variable or value, in `helpers.cmake`. * A "mini" testing framework for cmake modules and scripts, in `testing.cmake`. * `RSP_CMAKE_SCRIPTS_BUILD_TESTS` project option for building tests. * `tests.yaml` and `deploy-docs.yaml` GitHub Actions workflows. From 996bc18acd5e09d3ab42c146e14857246a83c8fb Mon Sep 17 00:00:00 2001 From: alin Date: Thu, 6 Feb 2025 13:52:51 +0100 Subject: [PATCH 04/13] Cleanup --- tests/unit/helpers/types_test.cmake | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/tests/unit/helpers/types_test.cmake b/tests/unit/helpers/types_test.cmake index 8f0f6fc..19fe9db 100644 --- a/tests/unit/helpers/types_test.cmake +++ b/tests/unit/helpers/types_test.cmake @@ -281,23 +281,13 @@ function(can_determine_if_cmd) is_command(my_function b) assert_truthy(b MESSAGE "b should be a command (function)") - # Not sure if this even can be tested... - # add_custom_command(TARGET my_command - # PRE_BUILD - # COMMAND ${CMAKE_COMMAND} -E echo hello - # COMMENT "FOR TESTING PURPOSES ONLY" - # VERBATIM - # ) - # is_command(my_command c) - # assert_truthy(c MESSAGE "c should be a command (custom command)") - set(my_var "") - is_command(my_var d) - assert_falsy(d MESSAGE "d should NOT be a command") + is_command(my_var c) + assert_falsy(c MESSAGE "c should NOT be a command") set(fn_ref "my_function") - is_command(fn_ref e) - assert_truthy(e MESSAGE "e should be a command (reference)") + is_command(fn_ref d) + assert_truthy(d MESSAGE "d should be a command (reference)") endfunction() From f992a7cfd17f12bdd131bb89d6c1a2e94d2edaa9 Mon Sep 17 00:00:00 2001 From: alin Date: Thu, 6 Feb 2025 15:50:37 +0100 Subject: [PATCH 05/13] Add var_dump() --- cmake/rsp/debug.cmake | 114 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/cmake/rsp/debug.cmake b/cmake/rsp/debug.cmake index 3e82993..1433b5b 100644 --- a/cmake/rsp/debug.cmake +++ b/cmake/rsp/debug.cmake @@ -7,6 +7,8 @@ include_guard(GLOBAL) # Debug message(VERBOSE "rsp/debug module included") +include("rsp/helpers") + if (NOT COMMAND "dump") #! dump : Outputs given variables' name and value @@ -37,4 +39,114 @@ if (NOT COMMAND "dd") # Output as fatal error to ensure that build stops. message(FATAL_ERROR " ${CMAKE_CURRENT_FUNCTION}() called from ${CMAKE_CURRENT_LIST_FILE}") endfunction() -endif () \ No newline at end of file +endif () + +if (NOT COMMAND "var_dump") + + #! var_dump : Output human readable information about given properties + # + # + # @param [OUTPUT ] Optional - If specified, information is assigned to output variable + # instead of being printed to stderr. + # @param [WITHOUT_NAMES] Option, if given then property names are omitted from the output + # @param [PROPERTIES ...] One or more variables to dump information about. + # + # @return + # [OUTPUT] The resulting output variable, if OUTPUT was specified. + # + function(var_dump) + set(options WITHOUT_NAMES) + set(oneValueArgs OUTPUT) + set(multiValueArgs PROPERTIES) + + cmake_parse_arguments(INPUT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + requires_arguments("PROPERTIES" INPUT) + + # ---------------------------------------------------------------------------------------------- # + + set(buffer "") + + foreach (key IN LISTS INPUT_PROPERTIES) + # Attempt to resolve value and it's datatype + set(value "${${key}}") + get_type(key type) + + # If key is defined as an environment variable, the value + # must be obtained via ENV{}. + if (DEFINED ENV{${key}}) + set(value "$ENV{${key}}") + get_type("${value}" type) + elseif (NOT DEFINED ${key} AND type STREQUAL "string") + # We ONLY deal with variables, meaning that if key isn't + # defined, and the type is determined to be a string, + # then we must assume that it's an undefined property! + + set(type "${COLOR_RED}${TEXT_ITALIC}undefined${TEXT_ITALIC_RESTORE}${COLOR_DEFAULT}") + endif () + + # Format the value... + if (type STREQUAL "string") + string(LENGTH "${value}" str_length) + set(type "${type} ${str_length}") + set(value "${COLOR_GREEN}\"${value}\"${RESTORE}") + elseif (type STREQUAL "int" OR type STREQUAL "float") + set(value "${COLOR_BRIGHT_BLUE}${value}${RESTORE}") + elseif (type STREQUAL "bool") + set(value "${COLOR_CYAN}${value}${RESTORE}") + elseif (type STREQUAL "command") + set(value "${COLOR_BLUE}${key}()${RESTORE}") + elseif (type STREQUAL "list") + list(LENGTH value lst_length) + set(type "${type} ${lst_length}") + set(list_buffer "") + + set(i 0) # index counter + foreach (item IN LISTS value) + # Get property information about the "item", but without key name. + var_dump(OUTPUT list_item WITHOUT_NAMES PROPERTIES item) + + # Append to list buffer and increment the "index" counter. + list(APPEND list_buffer "${COLOR_MAGENTA}${i}:${RESTORE} ${list_item}") + math(EXPR i "${i}+1" OUTPUT_FORMAT DECIMAL) + endforeach () + + string(REPLACE ";" "\n " list_buffer "${list_buffer}") + set(value "[ \n ${list_buffer}\n]") + endif () + + # Mark the key as cached, if needed... + if(DEFINED CACHE{${key}}) + set(type "${type}, ${TEXT_ITALIC}${TEXT_BOLD}cached${TEXT_BOLD_RESTORE}${TEXT_ITALIC_RESTORE}") + endif () + + # Mark the key an environment variable, if needed... + if(DEFINED ENV{${key}}) + set(type "${type}, ${TEXT_ITALIC}${TEXT_BOLD}ENV${TEXT_BOLD_RESTORE}${TEXT_ITALIC_RESTORE}") + endif () + + # The output format: = () + # Unless key is omitted. + set(formatted_key "${COLOR_BRIGHT_MAGENTA}${key}${RESTORE} = ") + if (INPUT_WITHOUT_NAMES) + set(formatted_key "") + endif () + + list(APPEND buffer "${formatted_key}${COLOR_WHITE}(${type}${COLOR_WHITE})${RESTORE} ${value}") + endforeach () + + string(REPLACE ";" "\n" buffer "${buffer}") + + # ---------------------------------------------------------------------------------------------- # + + # Assign to output variable, if requested and stop any further processing. + if (DEFINED INPUT_OUTPUT) + set("${INPUT_OUTPUT}" "${buffer}") + return(PROPAGATE "${INPUT_OUTPUT}") + endif () + + # ---------------------------------------------------------------------------------------------- # + + message(NOTICE "${buffer}") + + endfunction() +endif () From a58a4f2245b460d87265bbfa17e789c4fc1e7bc1 Mon Sep 17 00:00:00 2001 From: alin Date: Fri, 7 Feb 2025 08:19:11 +0100 Subject: [PATCH 06/13] Reformat param descriptions --- cmake/rsp/debug.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/rsp/debug.cmake b/cmake/rsp/debug.cmake index 1433b5b..091f202 100644 --- a/cmake/rsp/debug.cmake +++ b/cmake/rsp/debug.cmake @@ -46,10 +46,10 @@ if (NOT COMMAND "var_dump") #! var_dump : Output human readable information about given properties # # - # @param [OUTPUT ] Optional - If specified, information is assigned to output variable - # instead of being printed to stderr. - # @param [WITHOUT_NAMES] Option, if given then property names are omitted from the output - # @param [PROPERTIES ...] One or more variables to dump information about. + # @param [OUTPUT ] Optional - If specified, information is assigned to output variable + # instead of being printed to stderr. + # @param [PROPERTIES ...] One or more variables to dump information about. + # @param [WITHOUT_NAMES] Option, if given then property names are omitted from the output # # @return # [OUTPUT] The resulting output variable, if OUTPUT was specified. From 4dfc28b23eeffde4d996073980998ad35ea7c3a9 Mon Sep 17 00:00:00 2001 From: alin Date: Fri, 7 Feb 2025 11:12:32 +0100 Subject: [PATCH 07/13] Fix issue where list values were treated as "nested" lists --- cmake/rsp/debug.cmake | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/cmake/rsp/debug.cmake b/cmake/rsp/debug.cmake index 091f202..a07a2ab 100644 --- a/cmake/rsp/debug.cmake +++ b/cmake/rsp/debug.cmake @@ -50,12 +50,14 @@ if (NOT COMMAND "var_dump") # instead of being printed to stderr. # @param [PROPERTIES ...] One or more variables to dump information about. # @param [WITHOUT_NAMES] Option, if given then property names are omitted from the output + # @param [IGNORE_LIST] Option, if specified the variable values of the type "list" are + # treated as "string". # # @return # [OUTPUT] The resulting output variable, if OUTPUT was specified. # function(var_dump) - set(options WITHOUT_NAMES) + set(options WITHOUT_NAMES IGNORE_LIST) set(oneValueArgs OUTPUT) set(multiValueArgs PROPERTIES) @@ -69,7 +71,20 @@ if (NOT COMMAND "var_dump") foreach (key IN LISTS INPUT_PROPERTIES) # Attempt to resolve value and it's datatype set(value "${${key}}") - get_type(key type) + get_type("${key}" type) + + # ---------------------------------------------------------------------------------------------- # + + set(tmp_list_separator "") + if (INPUT_IGNORE_LIST AND type STREQUAL "list") + # Debug + #message("Ignoring list: ${key} | ${value}") + + set(type "string") + string(REPLACE ";" "${tmp_list_separator}" value "${value}") + endif () + + # ---------------------------------------------------------------------------------------------- # # If key is defined as an environment variable, the value # must be obtained via ENV{}. @@ -86,7 +101,12 @@ if (NOT COMMAND "var_dump") # Format the value... if (type STREQUAL "string") - string(LENGTH "${value}" str_length) + # Resolve string length, by ensuring to count the length of + # the original value, without list separator replacement. + set(tmp_str "${value}") + string(REPLACE "${tmp_list_separator}" ";" tmp_str "${tmp_str}") + string(LENGTH "${tmp_str}" str_length) + set(type "${type} ${str_length}") set(value "${COLOR_GREEN}\"${value}\"${RESTORE}") elseif (type STREQUAL "int" OR type STREQUAL "float") @@ -103,7 +123,10 @@ if (NOT COMMAND "var_dump") set(i 0) # index counter foreach (item IN LISTS value) # Get property information about the "item", but without key name. - var_dump(OUTPUT list_item WITHOUT_NAMES PROPERTIES item) + # Also, ensure to ignore values of the type "list", to avoid + # strange behaviour (caused by cmake's variable scopes...) + set("list_item_${i}" "${item}") + var_dump(OUTPUT list_item WITHOUT_NAMES IGNORE_LIST PROPERTIES "list_item_${i}") # Append to list buffer and increment the "index" counter. list(APPEND list_buffer "${COLOR_MAGENTA}${i}:${RESTORE} ${list_item}") @@ -134,8 +157,15 @@ if (NOT COMMAND "var_dump") list(APPEND buffer "${formatted_key}${COLOR_WHITE}(${type}${COLOR_WHITE})${RESTORE} ${value}") endforeach () + # ---------------------------------------------------------------------------------------------- # + string(REPLACE ";" "\n" buffer "${buffer}") + # Restore list value (as a string) if needed. + if (INPUT_IGNORE_LIST) + string(REPLACE "${tmp_list_separator}" ";" buffer "${buffer}") + endif () + # ---------------------------------------------------------------------------------------------- # # Assign to output variable, if requested and stop any further processing. From 452d981d706c52b0b3d3d01b69b0c9b125422c88 Mon Sep 17 00:00:00 2001 From: alin Date: Fri, 7 Feb 2025 11:23:30 +0100 Subject: [PATCH 08/13] Add tests for var_dump() --- tests/unit/debug/var_dump_test.cmake | 173 +++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 tests/unit/debug/var_dump_test.cmake diff --git a/tests/unit/debug/var_dump_test.cmake b/tests/unit/debug/var_dump_test.cmake new file mode 100644 index 0000000..62217a1 --- /dev/null +++ b/tests/unit/debug/var_dump_test.cmake @@ -0,0 +1,173 @@ +include("rsp/testing") +include("rsp/debug") + +define_test_case( + "Var Dump Test" + LABELS "debug;var_dump;dump" +) + +# -------------------------------------------------------------------------------------------------------------- # +# Actual tests +# -------------------------------------------------------------------------------------------------------------- # + +define_test("dumps 'undefined' when is not declared" "dumps_undefined") +function(dumps_undefined) + + var_dump(OUTPUT result PROPERTIES foo) + + string(STRIP "${result}" result) + assert_string_equals("foo = (undefined)" "${result}" MESSAGE "Incorrect dump") +endfunction() + +define_test("can dump without property name" "dumps_without_prop_name") +function(dumps_without_prop_name) + + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES foo) + + string(STRIP "${result}" result) + assert_string_equals("(undefined)" "${result}" MESSAGE "Incorrect dump") +endfunction() + +define_test("can dump string with length" "can_dump_str_width_length") +function(can_dump_str_width_length) + + set(prop "foo") + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES prop) + + string(STRIP "${result}" result) + assert_string_equals("(string 3) \"${prop}\"" "${result}" MESSAGE "Incorrect dump of string") +endfunction() + +define_test("can dump empty string" "can_dump_empty_str") +function(can_dump_empty_str) + + set(prop "") + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES prop) + + string(STRIP "${result}" result) + assert_string_equals("(string 0) \"\"" "${result}" MESSAGE "Incorrect dump of empty string") +endfunction() + +define_test("can dump integer" "can_dump_int") +function(can_dump_int) + + set(prop 42) + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES prop) + + string(STRIP "${result}" result) + assert_string_equals("(int) ${prop}" "${result}" MESSAGE "Incorrect dump of integer") +endfunction() + +define_test("can dump float" "can_dump_float") +function(can_dump_float) + + set(prop 42.1234) + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES prop) + + string(STRIP "${result}" result) + assert_string_equals("(float) ${prop}" "${result}" MESSAGE "Incorrect dump of float") +endfunction() + +define_test("can dump boolean" "can_dump_bool") +function(can_dump_bool) + + set(prop false) + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES prop) + + string(STRIP "${result}" result) + assert_string_equals("(bool) ${prop}" "${result}" MESSAGE "Incorrect dump of boolean") +endfunction() + +define_test("can dump list" "can_dump_list") +function(can_dump_list) + + set(prop "a;12;true") + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES prop) + + string(STRIP "${result}" result) + + # Debug + # message("${result}") + + assert_string_contains("${result}" "0: (string 1) \"a\"" MESSAGE "Incorrect list item") + assert_string_contains("${result}" "1: (int) 12" MESSAGE "Incorrect list item") + assert_string_contains("${result}" "2: (bool) true" MESSAGE "Incorrect list item") +endfunction() + +define_test("can ignore list" "can_ignore_list") +function(can_ignore_list) + + set(prop "a;12;true") + var_dump(OUTPUT result WITHOUT_NAMES IGNORE_LIST PROPERTIES prop) + + string(STRIP "${result}" result) + + # Debug + # message("${result}") + + assert_string_contains("${result}" "(string 9) \"${prop}\"" MESSAGE "Incorrect dump of list (as string)") +endfunction() + +define_test("does not attempt to dump 'nested' list" "does_not_dump_as_nested_list") +function(does_not_dump_as_nested_list) + + # A different list... + set(other_list "foo;bar") + + # In this list, a value corresponds to the "other_list" property, which + # is a bit unlucky. Nevertheless, the var_dump SHOULD not attempt to treat + # it as a "nested" list. Instead, it should see this a string value... + set(prop "a;12;true;other_list") + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES prop) + + string(STRIP "${result}" result) + + # Debug + # message("${result}") + + assert_string_contains("${result}" "0: (string 1) \"a\"" MESSAGE "Incorrect list item") + assert_string_contains("${result}" "1: (int) 12" MESSAGE "Incorrect list item") + assert_string_contains("${result}" "2: (bool) true" MESSAGE "Incorrect list item") + assert_string_contains("${result}" "3: (string 10) \"other_list\"" MESSAGE "Incorrect list item") +endfunction() + +define_test("can dump command" "can_dump_cmd") +function(can_dump_cmd) + + macro(my_macro) + endmacro() + + function(my_function) + endfunction() + + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES my_macro my_function) + + string(STRIP "${result}" result) + + assert_string_contains("${result}" "(command) my_macro()" MESSAGE "Incorrect dump of command (macro)") + assert_string_contains("${result}" "(command) my_function()" MESSAGE "Incorrect dump of command (function)") +endfunction() + +define_test("shows if variable is cached" "dump_shows_if_prop_cached") +function(dump_shows_if_prop_cached) + + set(rsp_test_prop "foo" CACHE STRING "For testing only") + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES rsp_test_prop) + + string(STRIP "${result}" result) + assert_string_equals("(string 3, cached) \"${rsp_test_prop}\"" "${result}" MESSAGE "Incorrect dump of cached state") + + unset(rsp_test_prop CACHE) +endfunction() + +define_test("shows if environment variable" "dump_shows_if_env_prop") +function(dump_shows_if_env_prop) + + set(ENV{rsp_test_env_prop} "/lorum/lipsum") + var_dump(OUTPUT result WITHOUT_NAMES PROPERTIES rsp_test_env_prop) + + string(STRIP "${result}" result) + assert_string_equals("(string 13, ENV) \"$ENV{rsp_test_env_prop}\"" "${result}" MESSAGE "Incorrect dump of env state") + + unset(ENV{rsp_test_env_prop}) +endfunction() \ No newline at end of file From 8a26f23c8e4045c8c1b757d3b48bc88127a33067 Mon Sep 17 00:00:00 2001 From: alin Date: Fri, 7 Feb 2025 11:54:43 +0100 Subject: [PATCH 09/13] Refactor dump() and dd(), use var_dump --- cmake/rsp/debug.cmake | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/cmake/rsp/debug.cmake b/cmake/rsp/debug.cmake index a07a2ab..178817b 100644 --- a/cmake/rsp/debug.cmake +++ b/cmake/rsp/debug.cmake @@ -13,31 +13,45 @@ if (NOT COMMAND "dump") #! dump : Outputs given variables' name and value # + # Note: function outputs using cmake's WARNING message mode + # + # @see https://cmake.org/cmake/help/latest/command/message.html#general-messages + # @see var_dump() + # # @param ... Variables to output # function(dump) - foreach (var ${ARGN}) - message("${var} = ${${var}}") - endforeach () + var_dump(OUTPUT output PROPERTIES ${ARGN}) + + # Attempt to keep the formatting - see details in rsp/output::output() + string(ASCII 13 CR) + set(formatted_output "${CR}${COLOR_WHITE}dump:${RESTORE}\n${output}") + string(REPLACE "\n" "\n " formatted_output "${formatted_output}") - # Output as warning so that the developer is able to see call stack! - message(WARNING " ${CMAKE_CURRENT_FUNCTION}() called from ${CMAKE_CURRENT_LIST_FILE}") + message(WARNING "${formatted_output}") endfunction() endif () if (NOT COMMAND "dd") - #! dump and die: Outputs given variables' name and value and stops build + #! dd: Outputs given variables' name and value and stops build (dump and die) + # + # Note: function outputs using cmake's FATAL_ERROR message mode + # + # @see https://cmake.org/cmake/help/latest/command/message.html#general-messages + # @see var_dump() # # @param ... Variables to output # function(dd) - foreach (var ${ARGN}) - message("${var} = ${${var}}") - endforeach () + var_dump(OUTPUT output PROPERTIES ${ARGN}) + + # Attempt to keep the formatting - see details in rsp/output::output() + string(ASCII 13 CR) + set(formatted_output "${CR}${COLOR_WHITE}dd:${RESTORE}\n${output}") + string(REPLACE "\n" "\n " formatted_output "${formatted_output}") - # Output as fatal error to ensure that build stops. - message(FATAL_ERROR " ${CMAKE_CURRENT_FUNCTION}() called from ${CMAKE_CURRENT_LIST_FILE}") + message(FATAL_ERROR "${formatted_output}") endfunction() endif () From 775dd3457887c8b9e15acd11a1224db73e523021 Mon Sep 17 00:00:00 2001 From: alin Date: Fri, 7 Feb 2025 12:43:04 +0100 Subject: [PATCH 10/13] Cleanup --- cmake/rsp/debug.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/rsp/debug.cmake b/cmake/rsp/debug.cmake index 178817b..7d7e0f7 100644 --- a/cmake/rsp/debug.cmake +++ b/cmake/rsp/debug.cmake @@ -57,7 +57,7 @@ endif () if (NOT COMMAND "var_dump") - #! var_dump : Output human readable information about given properties + #! var_dump : Outputs human-readable information about given properties # # # @param [OUTPUT ] Optional - If specified, information is assigned to output variable From 62057e4ff0ad028cdb4793e2ea3e1fe4f54907d4 Mon Sep 17 00:00:00 2001 From: alin Date: Fri, 7 Feb 2025 12:43:17 +0100 Subject: [PATCH 11/13] Add docs for debug module --- docs/+current/modules/debug/dump.md | 199 +++++++++++++++++++++++++++ docs/+current/modules/debug/index.md | 37 +++++ 2 files changed, 236 insertions(+) create mode 100644 docs/+current/modules/debug/dump.md create mode 100644 docs/+current/modules/debug/index.md diff --git a/docs/+current/modules/debug/dump.md b/docs/+current/modules/debug/dump.md new file mode 100644 index 0000000..c29ae0b --- /dev/null +++ b/docs/+current/modules/debug/dump.md @@ -0,0 +1,199 @@ +--- +title: Dump +description: How to dump variables. +keywords: debug, debugging, dump, dd, var_dump, cmake +author: RSP Systems A/S +--- + +# Dump Variables + +[TOC] + +## `dump()` + +Outputs the names and values of given variables. +Behind the scene, [`var_dump()`](#var_dump) is used. + +```cmake +set(build_assets true) +set(assets_dir "/home/code/my-project/resources") + +dump( + build_assets + assets_dir +) + +message("Onward...") +``` + +The above will output a [`WARNING`](https://cmake.org/cmake/help/latest/command/message.html#general-messages) message, +and continue to process your cmake script: + +```txt +CMake Warning at cmake/rsp/debug.cmake:31 (message): +dump: + + build_assets = (bool) true + assets_dir = (string 31) "/home/code/my-project/resources" +Call Stack (most recent call first): + CMakeLists.txt:132 (dump) + +Onward... +``` + +## `dd()` + +Outputs the names and values of given variables, and stops the build (_dump and die_). +Behind the scene, [`var_dump()`](#var_dump) is used. + +```cmake +set(build_assets true) +set(assets_dir "/home/code/my-project/resources") + +dd( + build_assets + assets_dir +) + +# This message will never be reached! +message("Onward...") +``` + +The `dd()` function will output using cmake's [`FATAL_ERROR`](https://cmake.org/cmake/help/latest/command/message.html#general-messages) +message mode. Your cmake script will not continue to be processed: + +```txt +CMake Error at cmake/rsp/debug.cmake:54 (message): +dd: + + build_assets = (bool) true + assets_dir = (string 31) "/home/code/my-project/resources" +Call Stack (most recent call first): + CMakeLists.txt:132 (dd) +``` + +## `var_dump()` + +Outputs human-readable information about given properties. +It accepts the following parameters: + +* `PROPERTIES`: _The variables to be dumped._ +* `OUTPUT`: (_optional_), _output variable. If specified, message is assigned to variable, instead of being printed to `stdout` or `stderr`._ +* `WITHOUT_NAMES`: (_option_), _Output information without the variable names._ +* `IGNORE_LIST`: (_option_), _Variables of the type "list" are treated as "string" type instead._ + +!!! info "Note" + Unless `OUTPUT` is specified, `var_dump()` will output using cmake's [`NOTICE`](https://cmake.org/cmake/help/latest/command/message.html#general-messages) + message mode. + +```cmake +set(my_str "Hi there") +set(my_empty_str "") +set(my_num 23) +set(my_float 1.1234) +set(my_bool true) +set(my_const on) +set(my_list "foo;bar;42;true") +set(my_cached_prop "My cached var..." CACHE STRING "Testing") +set(ENV{my_env_prop} "/home/other/place") + +macro(my_macro) +endmacro() + +function(my_function) +endfunction() + +var_dump(PROPERTIES + my_str + my_empty_str + my_num + my_float + my_const + my_undefined_prop + my_list + my_cached_prop + my_env_prop + my_macro + my_function +) +``` + +The above will output: + +```txt +my_str = (string 8) "Hi there" +my_empty_str = (string 0) "" +my_num = (int) 23 +my_float = (float) 1.1234 +my_const = (string 2) "on" +my_undefined_prop = (undefined) +my_list = (list 4) [ + 0: (string 3) "foo" + 1: (string 3) "bar" + 2: (int) 42 + 3: (bool) true +] +my_cached_prop = (string 4, cached) "Yolo" +my_env_prop = (string 17, ENV) "/home/other/place" +my_macro = (command) my_macro() +my_function = (command) my_function() +``` + +### Without Names + +If the `WITHOUT_NAMES` option is set, then variable names are not part of the output. + +```cmake +var_dump( + WITHOUT_NAMES + PROPERTIES + my_str +) +``` + +Outputs: + +```txt +(string 8) "Hi there" +``` + +### Ignore List + +By default, `var_dump()` will attempt to parse any list variable and output each item on a new line. +To disable this behaviour, set the `IGNORE_LIST` option. When doing so, lists are treated as a regular string. + +**Default behaviour** + +```cmake +var_dump( + PROPERTIES + my_list +) +``` + +Outputs: + +```txt +my_list = (list 4) [ + 0: (string 3) "foo" + 1: (string 3) "bar" + 2: (int) 42 + 3: (bool) true +] +``` + +**With ignore list option** + +```cmake +var_dump( + IGNORE_LIST + PROPERTIES + my_list +) +``` + +Outputs: + +```txt +my_list = (string 15) "foo;bar;42;true" +``` \ No newline at end of file diff --git a/docs/+current/modules/debug/index.md b/docs/+current/modules/debug/index.md new file mode 100644 index 0000000..5e76df7 --- /dev/null +++ b/docs/+current/modules/debug/index.md @@ -0,0 +1,37 @@ +--- +title: Debug +description: How to use the debug module. +keywords: debug, debugging, cmake +author: RSP Systems A/S +--- + +# Debug + +The debug module offers a few functions that might help you debug your cmake scripts. + +## How to include + +```cmake +include("rsp/debug") +``` + +## Example + +```cmake +dump( + CMAKE_MODULE_PATH + CMAKE_CURRENT_LIST_FILE +) +``` + +The above example will output: + +```txt +CMake Warning at cmake/rsp/debug.cmake:31 (message): +dump: + + CMAKE_MODULE_PATH = (string 35) "/home/code/cmake-scripts/cmake" + CMAKE_CURRENT_LIST_FILE = (string 44) "/home/code/cmake-scripts/CMakeLists.txt" +Call Stack (most recent call first): + CMakeLists.txt:129 (dump) +``` \ No newline at end of file From 31685c007a2ce3c6cad787869a08fda215801765 Mon Sep 17 00:00:00 2001 From: alin Date: Fri, 7 Feb 2025 12:49:29 +0100 Subject: [PATCH 12/13] Highlight debug module --- docs/+current/01_release-notes.md | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/+current/01_release-notes.md b/docs/+current/01_release-notes.md index 62ac252..0b1bde9 100644 --- a/docs/+current/01_release-notes.md +++ b/docs/+current/01_release-notes.md @@ -92,6 +92,38 @@ output("Building package assets" NOTICE LABEL "✓" LABEL_FORMAT "[ %label% ] ") See [output module](./modules/output/index.md) for additional information. +### Debug + +(_available since `v0.1`_) + +Debugging utils. + +```cmake +set(resources_list "chart.png;driver.ini;config.json") + +dump( + resources_list +) +``` + +Outputs: + +```txt +CMake Warning at cmake/rsp/debug.cmake:31 (message): +dump: + + resources_list = (list 3) [ + 0: (string 9) "chart.png" + 1: (string 10) "driver.ini" + 2: (string 11) "config.json" + ] +Call Stack (most recent call first): + CMakeLists.txt:108 (dump) +``` + +See [debug module](./modules/debug/index.md) for additional information. + + ### Logging (_available since `v0.1`_) From 83a12e2fd9877d9a9403135e66d0c56ce8737299 Mon Sep 17 00:00:00 2001 From: alin Date: Fri, 7 Feb 2025 12:50:50 +0100 Subject: [PATCH 13/13] Change release notes --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48500f0..ef70d4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `dependencies.cmake` and `dev-dependencies.cmake` scripts. * `CPM.cmake` script that downloads specified version of [CPM](https://github.com/cpm-cmake/CPM.cmake). * `fail_in_source_build()`, `extract_value()`, `requires_arguments()` and `safeguard_properties()` utils functions, in `helpers.cmake`. -* `dump()` and `dd()` in `debug.cmake`. +* `dump()`, `dd()` and `var_dump()` in `debug.cmake`. * ANSI utils, in `output.cmake` * `semver_parse()`, `write_version_file` and `version_from_file()` utils, in `version.cmake`. * `git_find_version_tag()` util, in `git.cmake`.