Skip to content

Commit 1b75a30

Browse files
authored
Merge pull request #13 from rsps/improve-debug-utils
Improve debugging utils
2 parents 40a7d56 + 83a12e2 commit 1b75a30

File tree

9 files changed

+1327
-12
lines changed

9 files changed

+1327
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
* `dependencies.cmake` and `dev-dependencies.cmake` scripts.
1414
* `CPM.cmake` script that downloads specified version of [CPM](https://github.com/cpm-cmake/CPM.cmake).
1515
* `fail_in_source_build()`, `extract_value()`, `requires_arguments()` and `safeguard_properties()` utils functions, in `helpers.cmake`.
16-
* `dump()` and `dd()` in `debug.cmake`.
16+
* `dump()`, `dd()` and `var_dump()` in `debug.cmake`.
1717
* ANSI utils, in `output.cmake`
1818
* `semver_parse()`, `write_version_file` and `version_from_file()` utils, in `version.cmake`.
1919
* `git_find_version_tag()` util, in `git.cmake`.
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
* `output()` helper, in `output.cmake`.
2424
* Support for ANSI, in `output.cmake`.
2525
* PSR inspired logging functions, in `logging.cmake`.
26+
* Utils for determining the datatype of a target variable or value, in `helpers.cmake`.
2627
* A "mini" testing framework for cmake modules and scripts, in `testing.cmake`.
2728
* `RSP_CMAKE_SCRIPTS_BUILD_TESTS` project option for building tests.
2829
* `tests.yaml` and `deploy-docs.yaml` GitHub Actions workflows.

cmake/rsp/debug.cmake

Lines changed: 167 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,190 @@ include_guard(GLOBAL)
77
# Debug
88
message(VERBOSE "rsp/debug module included")
99

10+
include("rsp/helpers")
11+
1012
if (NOT COMMAND "dump")
1113

1214
#! dump : Outputs given variables' name and value
1315
#
16+
# Note: function outputs using cmake's WARNING message mode
17+
#
18+
# @see https://cmake.org/cmake/help/latest/command/message.html#general-messages
19+
# @see var_dump()
20+
#
1421
# @param ... Variables to output
1522
#
1623
function(dump)
17-
foreach (var ${ARGN})
18-
message("${var} = ${${var}}")
19-
endforeach ()
24+
var_dump(OUTPUT output PROPERTIES ${ARGN})
25+
26+
# Attempt to keep the formatting - see details in rsp/output::output()
27+
string(ASCII 13 CR)
28+
set(formatted_output "${CR}${COLOR_WHITE}dump:${RESTORE}\n${output}")
29+
string(REPLACE "\n" "\n " formatted_output "${formatted_output}")
2030

21-
# Output as warning so that the developer is able to see call stack!
22-
message(WARNING " ${CMAKE_CURRENT_FUNCTION}() called from ${CMAKE_CURRENT_LIST_FILE}")
31+
message(WARNING "${formatted_output}")
2332
endfunction()
2433
endif ()
2534

2635
if (NOT COMMAND "dd")
2736

28-
#! dump and die: Outputs given variables' name and value and stops build
37+
#! dd: Outputs given variables' name and value and stops build (dump and die)
38+
#
39+
# Note: function outputs using cmake's FATAL_ERROR message mode
40+
#
41+
# @see https://cmake.org/cmake/help/latest/command/message.html#general-messages
42+
# @see var_dump()
2943
#
3044
# @param ... Variables to output
3145
#
3246
function(dd)
33-
foreach (var ${ARGN})
34-
message("${var} = ${${var}}")
47+
var_dump(OUTPUT output PROPERTIES ${ARGN})
48+
49+
# Attempt to keep the formatting - see details in rsp/output::output()
50+
string(ASCII 13 CR)
51+
set(formatted_output "${CR}${COLOR_WHITE}dd:${RESTORE}\n${output}")
52+
string(REPLACE "\n" "\n " formatted_output "${formatted_output}")
53+
54+
message(FATAL_ERROR "${formatted_output}")
55+
endfunction()
56+
endif ()
57+
58+
if (NOT COMMAND "var_dump")
59+
60+
#! var_dump : Outputs human-readable information about given properties
61+
#
62+
#
63+
# @param [OUTPUT <variable>] Optional - If specified, information is assigned to output variable
64+
# instead of being printed to stderr.
65+
# @param [PROPERTIES <variable>...] One or more variables to dump information about.
66+
# @param [WITHOUT_NAMES] Option, if given then property names are omitted from the output
67+
# @param [IGNORE_LIST] Option, if specified the variable values of the type "list" are
68+
# treated as "string".
69+
#
70+
# @return
71+
# [OUTPUT] The resulting output variable, if OUTPUT was specified.
72+
#
73+
function(var_dump)
74+
set(options WITHOUT_NAMES IGNORE_LIST)
75+
set(oneValueArgs OUTPUT)
76+
set(multiValueArgs PROPERTIES)
77+
78+
cmake_parse_arguments(INPUT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
79+
requires_arguments("PROPERTIES" INPUT)
80+
81+
# ---------------------------------------------------------------------------------------------- #
82+
83+
set(buffer "")
84+
85+
foreach (key IN LISTS INPUT_PROPERTIES)
86+
# Attempt to resolve value and it's datatype
87+
set(value "${${key}}")
88+
get_type("${key}" type)
89+
90+
# ---------------------------------------------------------------------------------------------- #
91+
92+
set(tmp_list_separator "<!list!>")
93+
if (INPUT_IGNORE_LIST AND type STREQUAL "list")
94+
# Debug
95+
#message("Ignoring list: ${key} | ${value}")
96+
97+
set(type "string")
98+
string(REPLACE ";" "${tmp_list_separator}" value "${value}")
99+
endif ()
100+
101+
# ---------------------------------------------------------------------------------------------- #
102+
103+
# If key is defined as an environment variable, the value
104+
# must be obtained via ENV{}.
105+
if (DEFINED ENV{${key}})
106+
set(value "$ENV{${key}}")
107+
get_type("${value}" type)
108+
elseif (NOT DEFINED ${key} AND type STREQUAL "string")
109+
# We ONLY deal with variables, meaning that if key isn't
110+
# defined, and the type is determined to be a string,
111+
# then we must assume that it's an undefined property!
112+
113+
set(type "${COLOR_RED}${TEXT_ITALIC}undefined${TEXT_ITALIC_RESTORE}${COLOR_DEFAULT}")
114+
endif ()
115+
116+
# Format the value...
117+
if (type STREQUAL "string")
118+
# Resolve string length, by ensuring to count the length of
119+
# the original value, without list separator replacement.
120+
set(tmp_str "${value}")
121+
string(REPLACE "${tmp_list_separator}" ";" tmp_str "${tmp_str}")
122+
string(LENGTH "${tmp_str}" str_length)
123+
124+
set(type "${type} ${str_length}")
125+
set(value "${COLOR_GREEN}\"${value}\"${RESTORE}")
126+
elseif (type STREQUAL "int" OR type STREQUAL "float")
127+
set(value "${COLOR_BRIGHT_BLUE}${value}${RESTORE}")
128+
elseif (type STREQUAL "bool")
129+
set(value "${COLOR_CYAN}${value}${RESTORE}")
130+
elseif (type STREQUAL "command")
131+
set(value "${COLOR_BLUE}${key}()${RESTORE}")
132+
elseif (type STREQUAL "list")
133+
list(LENGTH value lst_length)
134+
set(type "${type} ${lst_length}")
135+
set(list_buffer "")
136+
137+
set(i 0) # index counter
138+
foreach (item IN LISTS value)
139+
# Get property information about the "item", but without key name.
140+
# Also, ensure to ignore values of the type "list", to avoid
141+
# strange behaviour (caused by cmake's variable scopes...)
142+
set("list_item_${i}" "${item}")
143+
var_dump(OUTPUT list_item WITHOUT_NAMES IGNORE_LIST PROPERTIES "list_item_${i}")
144+
145+
# Append to list buffer and increment the "index" counter.
146+
list(APPEND list_buffer "${COLOR_MAGENTA}${i}:${RESTORE} ${list_item}")
147+
math(EXPR i "${i}+1" OUTPUT_FORMAT DECIMAL)
148+
endforeach ()
149+
150+
string(REPLACE ";" "\n " list_buffer "${list_buffer}")
151+
set(value "[ \n ${list_buffer}\n]")
152+
endif ()
153+
154+
# Mark the key as cached, if needed...
155+
if(DEFINED CACHE{${key}})
156+
set(type "${type}, ${TEXT_ITALIC}${TEXT_BOLD}cached${TEXT_BOLD_RESTORE}${TEXT_ITALIC_RESTORE}")
157+
endif ()
158+
159+
# Mark the key an environment variable, if needed...
160+
if(DEFINED ENV{${key}})
161+
set(type "${type}, ${TEXT_ITALIC}${TEXT_BOLD}ENV${TEXT_BOLD_RESTORE}${TEXT_ITALIC_RESTORE}")
162+
endif ()
163+
164+
# The output format: <key> = (<type>) <value>
165+
# Unless key is omitted.
166+
set(formatted_key "${COLOR_BRIGHT_MAGENTA}${key}${RESTORE} = ")
167+
if (INPUT_WITHOUT_NAMES)
168+
set(formatted_key "")
169+
endif ()
170+
171+
list(APPEND buffer "${formatted_key}${COLOR_WHITE}(${type}${COLOR_WHITE})${RESTORE} ${value}")
35172
endforeach ()
36173

37-
# Output as fatal error to ensure that build stops.
38-
message(FATAL_ERROR " ${CMAKE_CURRENT_FUNCTION}() called from ${CMAKE_CURRENT_LIST_FILE}")
174+
# ---------------------------------------------------------------------------------------------- #
175+
176+
string(REPLACE ";" "\n" buffer "${buffer}")
177+
178+
# Restore list value (as a string) if needed.
179+
if (INPUT_IGNORE_LIST)
180+
string(REPLACE "${tmp_list_separator}" ";" buffer "${buffer}")
181+
endif ()
182+
183+
# ---------------------------------------------------------------------------------------------- #
184+
185+
# Assign to output variable, if requested and stop any further processing.
186+
if (DEFINED INPUT_OUTPUT)
187+
set("${INPUT_OUTPUT}" "${buffer}")
188+
return(PROPAGATE "${INPUT_OUTPUT}")
189+
endif ()
190+
191+
# ---------------------------------------------------------------------------------------------- #
192+
193+
message(NOTICE "${buffer}")
194+
39195
endfunction()
40-
endif ()
196+
endif ()

cmake/rsp/helpers.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ include_guard(GLOBAL)
77
# Debug
88
message(VERBOSE "rsp/helpers module included")
99

10+
include("rsp/helpers/types")
11+
1012
if (NOT COMMAND "fail_in_source_build")
1113

1214
#! fail_in_source_build : Fails when building project in the source directory

0 commit comments

Comments
 (0)