Skip to content

cmake: Pass OPTIMIZATION_FLAG to linker too #87657

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

keith-packard
Copy link
Collaborator

The compiler may want to know the desired optimization level during linking, as when the compiler multilib configuration includes -Os as a selector.

@zephyrbot zephyrbot added size: XS A PR changing only a single line of code area: Build System labels Mar 25, 2025
@zephyrbot zephyrbot added the area: Toolchains Toolchains label Mar 25, 2025
@zephyrbot zephyrbot requested a review from stephanosio March 25, 2025 23:19
Copy link
Collaborator

@tejlmand tejlmand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the cleanup.

It would be nice to get rid of -L<libgcc_dir>, but we should ensure there are no side-effects (can't remember in which cases this happend last time I looked at this).

A couple of code observations to be addressed in addition.

@keith-packard keith-packard force-pushed the link-optimization-flag branch from 89450e4 to ca2f7c8 Compare March 26, 2025 20:01
@keith-packard
Copy link
Collaborator Author

I've reworked the second patch so that the computation of rt_library and lib_include_dir are delayed until the compiler flags are finished.

I renamed library_find_path to compiler_find_path and then placed the gcc/clang implementation of that along with a new function, compiler_set_linker_properties into cmake/compiler/target_template.cmake, which gets included just after cmake/linker/target_template.cmake from FindTargetTools.cmake.

With this, the values of lib_include_dir and rt_library are both uniformly computed using --print-libgcc-file-name. As lib_include_dir is already used in the linker, that will ensure that the -L flag continues to get passed along as before, but this time it will have a value computed using the whole set of compiler flags.

This refactoring let me remove a bunch of nearly identical code in the compiler target.cmake files.

@keith-packard keith-packard force-pushed the link-optimization-flag branch 2 times, most recently from 6649017 to 09a5f46 Compare March 28, 2025 00:07
@keith-packard
Copy link
Collaborator Author

It would be nice to get rid of -L<libgcc_dir>, but we should ensure there are no side-effects (can't remember in which cases this happend last time I looked at this).

Ok, I've discovered it's actually impossible for us to compute libgcc_dir correctly in this fashion because some of the critical compiler flags are only available in the INTERFACE_COMPILE_OPTIONS property which is a generator expression, and hence cannot be evaluated during the cmake run.

Things like -m32/-m64, various -mfpu flags and many flags used on arc targets will all affect the multilib path value, but are unavailable when computing the libgcc path. I'm kinda amazed this ever worked anywhere.

For libgcc/compiler-rt, it's pretty simple - we can figure out what the runtime library basename is and use just that, without attempting to include the directory name. That should work as we can probably assume that any compiler install will use the same library name for all multilib configs?

For crtbegin.o/crtend.o, the linker won't search along the paths for them, so we really need to compute the whole path name. And that means capturing the output of the compiler front-end with the full compiler flags evaluated at build time?

@keith-packard keith-packard force-pushed the link-optimization-flag branch from 09a5f46 to 3305ccf Compare March 28, 2025 01:15
@keith-packard
Copy link
Collaborator Author

Ok, I've discovered it's actually impossible for us to compute libgcc_dir correctly in this fashion because some of the critical compiler flags are only available in the INTERFACE_COMPILE_OPTIONS property which is a generator expression, and hence cannot be evaluated during the cmake run.

I did the best I could -- elided any flags which contained generator expressions and used the rest for all of the computations. That appears to at least get the flags needed for native_sim to work. A more complete solution would involve pushing the flag computation into the actual build run, and that seems 'problematic' as we'd have to pull the result back into the build process and insert it into the compile commands. Possible with make, but I'm unsure that could even work with ninja.

@57300 57300 removed their request for review April 1, 2025 19:05
@keith-packard keith-packard force-pushed the link-optimization-flag branch from 3305ccf to 463b68c Compare April 4, 2025 05:20
@keith-packard
Copy link
Collaborator Author

Btw, this is blocking an updated SDK which will use the optimization flag to select between versions of the C library, and that's part of the picolibc 1.8.10 uplevel process which will pull in RX target support, so we either need this in Zephyr or we need to decide that we're not doing any of this and to go back to the previous library selection mechanism kludge fest.

@keith-packard keith-packard force-pushed the link-optimization-flag branch from 463b68c to e5cf768 Compare April 5, 2025 01:27
@tejlmand
Copy link
Collaborator

tejlmand commented Apr 8, 2025

@keith-packard thanks for the effort, it's really appreciated 👍

I've been looking at the code, and in some ways we're getting a bit back to the older hassle of toolchain integration starting to depend on specific macros / functions to be available, which was addressed with the introduction of compiler properties.

However, the --print-libgcc-file-name and friends principle was not re-worked at that time, just adjusted to set the corresponding property. I will try to find a little time to take a closer look at compiler / linker property handling together with the TOOLCHAIN_C_FLAGS processing. I have some ideas.

Also I'm not too fond of the "guessing" of which compiler flags should be used when looking up the compiler dirs / which flags will impact library selection, this should be more controlled to avoid later genex surprises.

Will get back on this soon.

@keith-packard
Copy link
Collaborator Author

@keith-packard thanks for the effort, it's really appreciated 👍

Thanks.

However, the --print-libgcc-file-name and friends principle was not re-worked at that time, just adjusted to set the corresponding property. I will try to find a little time to take a closer look at compiler / linker property handling together with the TOOLCHAIN_C_FLAGS processing. I have some ideas.

There's a circular dependency here -- we need to ask the compiler to emit a path which is then used later on as a linker command line parameter. I don't think we can do that with generator expressions, which the current property mechanism uses extensively. That was the big blocker I found in this work.

Also I'm not too fond of the "guessing" of which compiler flags should be used when looking up the compiler dirs / which flags will impact library selection, this should be more controlled to avoid later genex surprises.

Agreed. Spamming the compiler with as many arguments as we can gather mostly works, but it sure doesn't seem like the right plan.

Will get back on this soon.

Can we set a deadline in the next few weeks with a plan to use this as temporary hack until you have time to fix it for real? I'm getting worried that we're going to run out of time to deliver the desired SDK features in time for the next Zephyr release.

Meanwhile, I'm adding -fsanitize=undefined support for picolibc 1.8.10 while I wait for Zephyr to be ready for that release. So at least I'm not bored?

@nashif
Copy link
Member

nashif commented Apr 14, 2025

Can we set a deadline in the next few weeks with a plan to use this as temporary hack until you have time to fix it for real? I'm getting worried that we're going to run out of time to deliver the desired SDK features in time for the next Zephyr release.

Meanwhile, I'm adding -fsanitize=undefined support for picolibc 1.8.10 while I wait for Zephyr to be ready for that release. So at least I'm not bored?

@tejlmand lets discuss this in toolchain WG on 14/4, @keith-packard if you can join, it would help :)

The compiler may want to know the desired optimization level during
linking, as when the compiler multilib configuration includes -Os as a
selector.

Do this by adding a new (optional) linker function,
toolchain_linker_add_compiler_options, which maps compiler options to
equivalent linker options, discarding any that aren't applicable.

Linker configurations which use the compiler driver (ld, lld, and xt-ld)
apply all provided compiler options. Linkers which don't provide this
function fall back to an implementation which simply discards all options.

Signed-off-by: Keith Packard <[email protected]>
@keith-packard keith-packard force-pushed the link-optimization-flag branch from e5cf768 to 1a75649 Compare April 14, 2025 01:31
With inclusion of the optimization flag into the multilib selection
process, we cannot compute the compiler library path when the compiler's
target.cmake is processed as OPTIMIZATION_FLAG is not computed until much
later.

Instead, add a function (compiler_file_path) which can be used to locate
the appropriate crtbegin.o and crtend.o files.

Delay computation of lib_include_dir and rt_library until after all
compiler flags have been computed by adding compiler_set_linker_properties
and calling that just before toolchain_linker_finalize is invoked.

Place default implementations of both of these functions in a new file,
cmake/compiler/target_template.cmake, where we assume the compiler works
like gcc or clang and handlers the --print-file-name and
--print-libgcc-file-name options. Compilers needing alternate
implementations can override these functions in their target.cmake files.

These implementations require that no generator expressions are necessary
for the compiler to compute the right library paths.

This mechanism is also used to take any additional compiler options and
pass them to the linker using toolchain_linker_add_compiler_options.

Signed-off-by: Keith Packard <[email protected]>
@keith-packard keith-packard force-pushed the link-optimization-flag branch from 1a75649 to 1bb65eb Compare April 14, 2025 05:30
@tejlmand
Copy link
Collaborator

However, the --print-libgcc-file-name and friends principle was not re-worked at that time, just adjusted to set the corresponding property. I will try to find a little time to take a closer look at compiler / linker property handling together with the TOOLCHAIN_C_FLAGS processing. I have some ideas.

There's a circular dependency here -- we need to ask the compiler to emit a path which is then used later on as a linker command line parameter. I don't think we can do that with generator expressions, which the current property mechanism uses extensively. That was the big blocker I found in this work.

Yes, I see the issue.
The original intent with compiler / linker flags properties was to avoid if(CONFIG_X) checking when dealing with flag support in compiler_flags.cmake and linker_flags.cmake and instead just describe the flags, and then where they are used do the config check. The is almost true, although for historic reasons there does exists some checks.

Following this approach I think the linker should have a property describing flags which might impact path calc, but as the actual flag usage \is config dependent we need improved Kconfig -> mapping, which I guess will be on my shoulders 😃 .

For now, I made a draft to show improved linker optimization flag #89073.
It follows the existing principle from compiler flags, meaning linker_flags.cmake can define:

set_linker_property(PROPERTY optimization_speed -O2)

but also have the ability to reference the property fetching mechanism to another target, for example to re-use compiler properties, like this:

set_property(TARGET linker PROPERTY optimization_target "compiler")

I think this can replace: 894587f

and thereby at first avoid the request for implementing toolchain_linker_add_compiler_options().

Also I'm not too fond of the "guessing" of which compiler flags should be used when looking up the compiler dirs / which flags will impact library selection, this should be more controlled to avoid later genex surprises.

Agreed. Spamming the compiler with as many arguments as we can gather mostly works, but it sure doesn't seem like the right plan.

See above reply.

Can we set a deadline in the next few weeks with a plan to use this as temporary hack until you have time to fix it for real? I'm getting worried that we're going to run out of time to deliver the desired SDK features in time for the next Zephyr release.

#89073 is a first step, will take a look and the next and hopefully have something early next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Build System area: Toolchains Toolchains size: XS A PR changing only a single line of code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants