-
Notifications
You must be signed in to change notification settings - Fork 7.3k
extensions.cmake: need unique strings, not random ones #14776
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
extensions.cmake: need unique strings, not random ones #14776
Conversation
1. To support being called multiple times, the function zephyr_library_compile_options() uses unique options_interface_lib_${random} names. These only need to be unique, not random. So replace them with a simple MD5 hash of the ${item} argument. To reproduce quickly run: sanitycheck -b -p qemu_xtensa --tag shell ... a few times and compare the output directories. This bug sits for now at the top of the list of build reproducibility issues the most bizarre and difficult to root cause. When running sanitycheck over a large sample of configurations it was affecting only qemu_xtensa/**/zephyr/arch/arch/xtensa/core/startup/Makefile files (and their corresponding CMakeFiles/TargetDirectories.txt), randomly ordering the following three Make targets and only these three: rebuild_cache, edit_cache, arch__xtensa__core__startup. The key to root causing was cmake --trace-expand which prints the random string. 2. generate_unique_target_name_from_filename() also generated a random string for the same uniqueness reason. This one was easier to root cause and reproduce with: sanitycheck --tag gen_inc_file Signed-off-by: Marc Herbert <[email protected]>
f7258dc
to
74783a7
Compare
Codecov Report
@@ Coverage Diff @@
## master #14776 +/- ##
=======================================
Coverage 52.51% 52.51%
=======================================
Files 309 309
Lines 45048 45048
Branches 10419 10419
=======================================
Hits 23656 23656
Misses 16584 16584
Partials 4808 4808 Continue to review full report at Codecov.
|
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.
LGTM if it passes CI
Would appreciate @SebastianBoe review on this. |
@@ -1219,7 +1219,7 @@ function(generate_unique_target_name_from_filename filename target_name) | |||
string(REPLACE "." "_" x ${basename}) | |||
string(REPLACE "@" "_" x ${x}) | |||
|
|||
string(RANDOM LENGTH 8 random_chars) | |||
string(MD5 unique_chars ${filename}) |
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.
Is filename relative or absolute?
Can we get into trouble if we invoke 'generate_unique_target_name_from_filename' twice on two different generated files with the same relative address?
If not, then this looks good :)
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 questioning this. I've done some research and experimentation. I think this collision issue:
- might be possible in theory,
- is extremely unlikely in practice,
- if ever, will trigger a very clear error message like this one:
CMake Error at zephyr/cmake/extensions.cmake:512 (add_custom_target):
add_custom_target cannot create target
"gen_lets_encrypt_x3_der_inc_7ea3a619643a01cb9f7b7914adc3ad38" because
another target with the same name already exists. The existing target is a
custom target created in source directory
"zephyr/samples/net/sockets/big_http_download".
See documentation for policy CMP0002 for more details.
Call Stack (most recent call first):
src2/CMakeLists.txt:7 (generate_inc_file_for_target)
To trigger the above error message I hacked samples/net/sockets/big_http_download/
and invoked generate_inc_file_for_target()
with the same include/generated//lets_encrypt_x3.der.inc
relative argument twice. This is really not how CMakeLists.txt files are normally written because CMake generally hates/discourages/deprecates relative paths https://cmake.org/cmake/help/v3.3/variable/CMAKE_USE_RELATIVE_PATHS.html (gone in 3.4)
I scanned the current code base. There are currently eight places where this function is used:
cfb.cmake: generate_cfb_font_for_target()
samples/display/cfb_custom_font/
extensions.cmake: generate_inc_file_for_target()
samples/net/sockets/big_http_download/
samples/net/sockets/dumb_http_server/
samples/net/sockets/echo_client/
samples/net/sockets/echo_server/
samples/net/sockets/http_get/
soc/arm/nxp_lpc/lpc54xxx/
tests/application_development/gen_inc_file/
I traced these invocations and they all use absolute paths because they all rely after a (scary...) number of indirections on MAKE_CURRENT_BINARY_DIR
. CMake's love of absolute paths makes sure CMAKE_CURRENT_BINARY_DIR
is one https://cmake.org/cmake/help/v3.13/variable/CMAKE_CURRENT_BINARY_DIR.html
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.
Thank you for the thorough analysis. I agree with your findings and conclusion that this is safe.
string(RANDOM random) | ||
set(lib_name options_interface_lib_${random}) | ||
string(MD5 uniqueness ${item}) | ||
set(lib_name options_interface_lib_${uniqueness}) |
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.
What if we add the same item twice?
Expected behaviour would for it to be silently added once due to CMake's de-duplication pass. But now I expect we will get an obscure error.
Perhaps we need to add our own "if not exists" check to silently de-duplicate.
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.
PR zephyrproject-rtos#14776 / commit 915a353 changed function zephyr_library_compile_options() to use MD5 instead of RANDOM for build reproduction reasons. As later predicted by Sebastian Bøe in the PR (thx), the names generated for these pseudo-libraries won't be unique anymore if the exact same flag gets added more than once. To reproduce the issue, simply add the following two lines in some CMakeLists.txt file like samples/hello_world/CMakeLists.txt: zephyr_library_compile_options("-Dfubar=barfu") zephyr_library_compile_options("-Dfubar=barfu") cmake will then fail like this: CMake Error at zephyr/cmake/extensions.cmake:403 (add_library): add_library cannot create target "options_interface_lib_e689fdb7eb15d801c2f95dd61301fc5e" because another target with the same name already exists. The existing target is an interface library created in source directory "zephyr/samples/hello_world". See documentation for policy CMP0002 for more details. Call Stack (most recent call first): CMakeLists.txt:9 (zephyr_library_compile_options) As requested by Sebastian, silently discard duplicate options just like CMake does. Fixes zephyrproject-rtos#15093 Signed-off-by: Marc Herbert <[email protected]>
PR #14776 / commit 915a353 changed function zephyr_library_compile_options() to use MD5 instead of RANDOM for build reproduction reasons. As later predicted by Sebastian Bøe in the PR (thx), the names generated for these pseudo-libraries won't be unique anymore if the exact same flag gets added more than once. To reproduce the issue, simply add the following two lines in some CMakeLists.txt file like samples/hello_world/CMakeLists.txt: zephyr_library_compile_options("-Dfubar=barfu") zephyr_library_compile_options("-Dfubar=barfu") cmake will then fail like this: CMake Error at zephyr/cmake/extensions.cmake:403 (add_library): add_library cannot create target "options_interface_lib_e689fdb7eb15d801c2f95dd61301fc5e" because another target with the same name already exists. The existing target is an interface library created in source directory "zephyr/samples/hello_world". See documentation for policy CMP0002 for more details. Call Stack (most recent call first): CMakeLists.txt:9 (zephyr_library_compile_options) As requested by Sebastian, silently discard duplicate options just like CMake does. Fixes #15093 Signed-off-by: Marc Herbert <[email protected]>
zephyr_library_compile_options() uses unique
options_interface_lib_${random} names. These only need to be unique, not
random. So replace them with a simple MD5 hash of the ${item} argument.
To reproduce quickly run:
sanitycheck -b -p qemu_xtensa --tag shell
... a few times and compare the output directories.
This bug sits for now at the top of the list of build reproducibility
issues the most bizarre and difficult to root cause. When running
sanitycheck over a large sample of configurations it was affecting
only qemu_xtensa/**/zephyr/arch/arch/xtensa/core/startup/Makefile
files (and their corresponding CMakeFiles/TargetDirectories.txt),
randomly ordering the following three Make targets and only these
three: rebuild_cache, edit_cache, arch__xtensa__core__startup.
The key to root causing was cmake --trace-expand which prints the random
string.
string for the same uniqueness reason. This one was easier to root cause
and reproduce with: sanitycheck --tag gen_inc_file
Signed-off-by: Marc Herbert [email protected]