-
Notifications
You must be signed in to change notification settings - Fork 8.4k
cmake: refactor zephyr_get_*_for_lang functions
#98377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
The 'convert_list_of_flags_to_string_of_flags' function was added back in 2017 with commit 89516fb at the time language support was added to the CMake build system. The same commit also added all users of that function; they were directly passed the result of get_property() calls, so a simple replace was sufficient. This code was later expanded with the use of generator expressions to manage delimiters and prefixes, which required replacing the ';' separator with '$<SEMICOLON>' to properly preserve the list entries. This made the conversion function invalid, since no ';' can be found in any 'zephyr_get_*' output, so the conversion function was effectively a no-op; setting a space as a delimiter is already sufficient to get the desired result since circa 2020. Remove this function and 'get_property_and_add_prefix', a macro that was made redundant by the same value-to-genex conversion. Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
zephyr_get_*_for lang functionszephyr_get_*_for_lang functions
tejlmand
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the direction, but couple of small adjustments proposed.
cmake/modules/extensions.cmake
Outdated
| # - STRIP_PREFIX: Omit the compiler flag prefix (-I, -D, etc.) | ||
| # - DELIMITER <delimiter>: Specify the output delimiter to use | ||
|
|
||
| function(zephyr_get_build_prop_for_lang prop lang i) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think cleaning up the current use of zephyr_get_*_for_lang.. is valuable, but if we anyway change current style, then perhaps align closer to CMake.
Like we have zephyr_string and zephyr_get, then perhaps a
zephyr_get_property(<out-var> PROPERTY <prop> LANG <C|CXX|ASM>)
alternative zephyr_get_build_property().
Optional, the _as_string could even be a flag to the function which would default the delimiter to <space> instead of $<SEMICOLON>, as to not need to remember that " " does exactly that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dropped AS_STRING once I understood it could be done with existing options. Looks a lot cleaner with it though, so I'll re-add that.
cmake/modules/extensions.cmake
Outdated
| macro(generate_build_prop_wrappers item prop) | ||
| function(zephyr_get_${item}_for_lang lang i) | ||
| zephyr_get_build_prop_for_lang(${prop} ${lang} result_output_list ${ARGN}) | ||
| set(${i} ${result_output_list} PARENT_SCOPE) | ||
| endfunction() | ||
| function(zephyr_get_${item}_for_lang_as_string lang i) | ||
| zephyr_get_build_prop_for_lang(${prop} ${lang} result_output_list DELIMITER " " ${ARGN}) | ||
| set(${i} ${result_output_list} PARENT_SCOPE) | ||
| endfunction() | ||
| endmacro() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, we should not wrap function definition in a macro like this.
It might make it easy for us, but it will make it impossible for ordinary developers to find out where a function like:
zephyr_get_include_directories_for_lang() and friends are defined.
Not to mention the impact this will have on tasks like this: #87083
When we have the property function in place, then let's just deprecate the old style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really hate copying code that should be written once only, so this was basically the first thing I did. 😅
I did consider the issue of making the definitions opaque, so I left comments with the generated function names next to each macro invocation for easy grepping. But if #87083 performs actual indexing, I will gladly revert to the verbose sequence of commands. 👍
cmake/modules/extensions.cmake
Outdated
| # | ||
| # Options: | ||
| # - STRIP_PREFIX: Omit the compiler flag prefix (-I, -D, etc.) | ||
| # - DELIMITER <delimiter>: Specify the output delimiter to use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps specify that default delimiter is $<SEMICOLON> to allow the result to be used in generator expressions.
pillo79
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, will update soon with comments.
cmake/modules/extensions.cmake
Outdated
| macro(generate_build_prop_wrappers item prop) | ||
| function(zephyr_get_${item}_for_lang lang i) | ||
| zephyr_get_build_prop_for_lang(${prop} ${lang} result_output_list ${ARGN}) | ||
| set(${i} ${result_output_list} PARENT_SCOPE) | ||
| endfunction() | ||
| function(zephyr_get_${item}_for_lang_as_string lang i) | ||
| zephyr_get_build_prop_for_lang(${prop} ${lang} result_output_list DELIMITER " " ${ARGN}) | ||
| set(${i} ${result_output_list} PARENT_SCOPE) | ||
| endfunction() | ||
| endmacro() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really hate copying code that should be written once only, so this was basically the first thing I did. 😅
I did consider the issue of making the definitions opaque, so I left comments with the generated function names next to each macro invocation for easy grepping. But if #87083 performs actual indexing, I will gladly revert to the verbose sequence of commands. 👍
cmake/modules/extensions.cmake
Outdated
| # - STRIP_PREFIX: Omit the compiler flag prefix (-I, -D, etc.) | ||
| # - DELIMITER <delimiter>: Specify the output delimiter to use | ||
|
|
||
| function(zephyr_get_build_prop_for_lang prop lang i) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dropped AS_STRING once I understood it could be done with existing options. Looks a lot cleaner with it though, so I'll re-add that.
6b4ff3f to
2fa4231
Compare
|
v2, addressing all comments:
|
tejlmand
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update 👍
Mostly some minor observations and clarification questions.
| string(REPLACE ";" "$<SEMICOLON>" genexp_output_list "${output_list}") | ||
| endif() | ||
|
|
||
| set(result_output_list "${maybe_prefix}$<JOIN:${genexp_output_list},${args_DELIMITER}${maybe_prefix}>") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if args_DELIMITER is a space, then this genex can end up not behaving / expanding as expected.
Has this been verified with more complex lists ?
See also: https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#whitespace-and-quoting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is the expected behavior? If the user asks for space as a delimiter, having the char in the${args_DELIMITER} variable will properly expand the genex to a single-space-separated string.
Now, the linked docs mention that the resulting string becomes ambiguous if there were spaces in the data (you may either have too many arguments, or a single quote-enclosed one), but to avoid that... you should use a proper list in the first place (which is returned without AS_STRING).
cmake/modules/extensions.cmake
Outdated
| set(result_output_list "-D$<JOIN:${genexp_output_list},${args_DELIMITER}-D>") | ||
| zephyr_get_property(result_output_list | ||
| PROPERTY INTERFACE_COMPILE_DEFINITIONS | ||
| PREFIX "-D" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we can simplify.
PREFIX follows the property type, so zephyr_get_property() could have a list of known pairs, like.
set(prefix_INTERFACE_COMPILE_DEFINITIONS "-D")
set(prefix_INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "-isystem")
set(prefix_INTERFACE_INCLUDE_DIRECTORIES "-I")
if(NOT DEFINED args_PREFIX)
set(args_PREFIX ${prefix_${args_PROPERTY}})
endif()
thus supporting all properties possible, by allowing PREFIX, but removing the need for passing PREFIX for known properties, like -D, -I, -isystem etc.
That will also lower the threshold for updating the code from:
zephyr_get_compile_definitions_for_lang(C zephyr_defs)
zephyr_get_include_directories_for_lang(C ZEPHYR_INCLUDES)
etc.
to
zephyr_get_property(zephyr_defs PROPERTY INTERFACE_COMPILE_DEFINITIONS LANG C)
zephyr_get_property(ZEPHYR_INCLUDES PROPERTY ZEPHYR_INCLUDES LANG C)
if we want.
and then in that process, deprecate the old functions.
Thoughts ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had in fact pushed an intermediate version (e0fb12f and parent commits) with a zephyr_get_build_property() and a long series of if()s, but I disliked it for a number of reasons:
- it is unclear which properties get an automatic prefix and which do not. Some even should never need it (e.g.
COMPILE_OPTIONS) - that is the only
_build-specific thing in the function, everything else applies to any CMake property in the project; - obviously ugly with the
ifs (but your proposal would be way cleaner!).
In my view, removing the embedded prefix list made the function clean and use-agnostic, and gave a proper meaning to the existing wrappers (collapsing all build-property-specific functionality).
Let me know if you still prefer to incorporate the prefixes in the generic function. If so, I would suggest to call that zephyr_get_build_property as it's doing build-specific stuff as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but I disliked it for a number of reasons:
yes, seeing it from the function implementation then the if's is really not nice.
I also understand from the concern on the build specific part of the function.
However, when seeing it from the caller, that is if we want to get rid of zephyr_get_*_for_lang functions, then requesting the caller to remember PREFIX -D when using INTERFACE_COMPILE_DEFINITIONS is not nice.
-D ought to be implied by the property name (when seeing things from the caller).
Let me know if you still prefer to incorporate the prefixes in the generic function.
Depends on what you believe the long term support for existing zephyr_get_*_for_lang functions is.
If so, I would suggest to call that zephyr_get_build_property as it's doing build-specific stuff as well.
That might be a better name. Especially as the function description already states:
zephyr/cmake/modules/extensions.cmake
Lines 167 to 168 in 2fa4231
| # Getter function for extracting information from a target. The function | |
| # supports filtering for specific compile languages, prefixes, and |
so it is target related, and targets are build specific, as well as LANG is very build oriented.
pillo79
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I understand the concerns, here are my thoughts on them. Let me know how to address the prefix thing.
| string(REPLACE ";" "$<SEMICOLON>" genexp_output_list "${output_list}") | ||
| endif() | ||
|
|
||
| set(result_output_list "${maybe_prefix}$<JOIN:${genexp_output_list},${args_DELIMITER}${maybe_prefix}>") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is the expected behavior? If the user asks for space as a delimiter, having the char in the${args_DELIMITER} variable will properly expand the genex to a single-space-separated string.
Now, the linked docs mention that the resulting string becomes ambiguous if there were spaces in the data (you may either have too many arguments, or a single quote-enclosed one), but to avoid that... you should use a proper list in the first place (which is returned without AS_STRING).
cmake/modules/extensions.cmake
Outdated
| set(result_output_list "-D$<JOIN:${genexp_output_list},${args_DELIMITER}-D>") | ||
| zephyr_get_property(result_output_list | ||
| PROPERTY INTERFACE_COMPILE_DEFINITIONS | ||
| PREFIX "-D" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had in fact pushed an intermediate version (e0fb12f and parent commits) with a zephyr_get_build_property() and a long series of if()s, but I disliked it for a number of reasons:
- it is unclear which properties get an automatic prefix and which do not. Some even should never need it (e.g.
COMPILE_OPTIONS) - that is the only
_build-specific thing in the function, everything else applies to any CMake property in the project; - obviously ugly with the
ifs (but your proposal would be way cleaner!).
In my view, removing the embedded prefix list made the function clean and use-agnostic, and gave a proper meaning to the existing wrappers (collapsing all build-property-specific functionality).
Let me know if you still prefer to incorporate the prefixes in the generic function. If so, I would suggest to call that zephyr_get_build_property as it's doing build-specific stuff as well.
2fa4231 to
b5e5ce0
Compare
Refactored the various 'zephyr_get_*_for_lang*' functions into a single 'zephyr_get_build_property' function that takes the property to get and the specific output formats as arguments. This avoids differences between each function, reduces code duplication, and makes it easier to support additional features in the future. Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
Extended the zephyr_get_build_property() CMake function with several
convenience options:
- GENEX:
Uses generator expressions to get the property entries at build
time, for targets that are not yet fully configured.
Cannot be used with LANG. Also, CMake will complain if the
requested property includes $<COMPILE_OPTIONS:...> expressions.
- TARGET <target>:
Specifies the target to get the property from. Defaults to
"zephyr_interface" as before.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
b5e5ce0 to
8e85b1f
Compare
|



Not for 4.3.
This PR unifies the implementation of the various
zephyr_get_*_for_langfunctions and their string variants with a genericzephyr_get_property, so that the same feature set is available to all wrappers. It also adds several new options that expand the possible use cases:AS_STRING: Return the result as a string rather than a list. Equivalent to specifyingDELIMITER " ".DELIMITER <delim>: Specify the output delimiter to use for the list entries. Defaults to$<SEMICOLON>.GENEX: Use generator expressions to get the property entries at build time, for targets that are not yet fully configured. Cannot be used withLANG. Also, CMake will complain if the requested property includes$<COMPILE_OPTIONS:...>expressions.LANG <C|CXX|ASM>: When set, the property value is filtered for$<COMPILE_LANGUAGE:lang>entries, and only those matching the given language are kept. Cannot be used withGENEX.PREFIX <prefix>: Specify a prefix to use for each entry in the output list.STRIP_PREFIX: Omit the prefix string, even if given byPREFIX.TARGET <target>: Specify the target to get the property from. Defaults tozephyr_interface.This work was done while experimenting with alternatives to #98348. It is no longer useful for the EDK, but I think it is still worth considering for merge.