Skip to content

cmake: compiler / linker infrastructure improvement #89073

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 6 commits into
base: main
Choose a base branch
from

Conversation

tejlmand
Copy link
Contributor

@tejlmand tejlmand commented Apr 25, 2025

Cleanup and improve the design and logic flow of compiler and linker handling.

With this PR then FindTargetTools.cmake is now the entry point for
loading toolchain CMake file for configuring the toolchain and its
properties.

The main target toolchain handling structure is now:

  • Load compiler, linker, bintools template properties.
  • Load actual target compiler, linker, bintools properties.
  • Load target compiler, linker, bintools target CMake files.
    Those are responsible for defining the actual CMake compiler settings,
    setting up linker invocation, etc.

For highlevel toolchain verification, a new zephyr_verify_toolchain
function has been introduced which invokes the compiler to check its
working state.

Some compiler and linker properties requires testing the flags by
invoking the actual compiler or linker. This is done using
check_set_compiler_property and check_set_linker_property.
However such tests cannot be executed until CMake's project() function
has been called. Therefore calls to those functions are defered until
the basic toolchain has been verified using zephyr_verify_toolchain.

This allows us to introduce the above structure and thereby cleaning up
toolchain handling and improving the design. It also allows compiler and
linker target CMake files to use compiler properties as they are now
available at an earlier stage.


The above prepares for improved library path handling as it becomes easier and cleaner to decide compiler flags which should be used for C and runtime library path lookup, as presented in #87657

@keith-packard
Copy link
Contributor

This appears to still use generator expressions. I think those can't be used to resolve the compiler library pathnames needed for crtbegin.o and crtend.o filenames.

@tejlmand
Copy link
Contributor Author

This appears to still use generator expressions.

Correct, because this way the principle introduced with #24851 will still be used and thereby a single approach for describing compiler/linker, and not a mix of properties and macro/functions.

I think those can't be used to resolve the compiler library pathnames needed for crtbegin.o and crtend.o filenames.

Genex'es cannot, that's correct, but properties can still be retrieved and used at CMake configure time, albeit later adjustments to the property will not be picked up, but this also goes for a macro/function, and should not be a blocker in this case.

This was what I was referring to with this comment #87657 (comment):

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 😃 .

@keith-packard
Copy link
Contributor

Genex'es cannot, that's correct, but properties can still be retrieved and used at CMake configure time, albeit later adjustments to the property will not be picked up, but this also goes for a macro/function, and should not be a blocker in this case.

I think this will still break the computation of paths for crtbegin.o/crtend.o. The directory name for those is currently computed at cmake time in either gcc/target.cmake or clang/target.cmake using

execute_process(
    COMMAND ${CMAKE_C_COMPILER} ${clang_target_flag} ${TOOLCHAIN_C_FLAGS}
            --print-libgcc-file-name
  OUTPUT_VARIABLE LIBGCC_FILE_NAME
  OUTPUT_STRIP_TRAILING_WHITESPACE
  )

This needs to have the optimization flag added or the value will be wrong. I can't see how to do that with generator expressions as the resulting directory name is used to construct the correct path for crtbegin.o and crtend.o; the full paths for those are then passed to a linker command later on in the build.

@tejlmand tejlmand force-pushed the linker_optimization branch from 2614027 to 8744ec0 Compare May 15, 2025 13:08
@tejlmand tejlmand changed the title cmake: support linker optimization levels cmake: compiler / linker infrastructure improvement May 15, 2025
@tejlmand
Copy link
Contributor Author

This needs to have the optimization flag added or the value will be wrong. I can't see how to do that with generator expressions as the resulting directory name is used to construct the correct path for crtbegin.o and crtend.o; the full paths for those are then passed to a linker command later on in the build.

@keith-packard Took a tour down the rabbit whole.
I've wanted for a long time to collect handling of target toolchain so that FindTargetTools.cmake is the highlevel entry and not pieces scattered throughout the build system. (some in FindTargetTools, some in kernel.cmake, and so on)

Also I improved the property handling so that linker and compiler set the known flags in compiler_flags / linker_flags, and calculated properties can be set in the respective <compiler|linker>/target.cmake files.

There is a little more cleaning to do in future, but this improves the flow, and makes in much cleaner to support optimization flags on the linker.

I took 1bb65eb and reworked it a little bit, namely aligning the two path computation functions so they both returns the results and then it's for the caller to decide how to use the result.
That will also make it more visible and clear which CMake code is responsible for setting properties.

tejlmand and others added 6 commits May 16, 2025 11:25
This commit cleanup and improve the structure of target toolchain
handling in Zephyr.

With this commit FindTargetTools.cmake is now the entry point for
loading toolchain CMake file for configuring the toolchain and its
properties.

The main target toolchain handling structure is now:
- Load compiler, linker, bintools template properties.
- Load actual target compiler, linker, bintools properties.
- Load target compiler, linker, bintools target CMake files.
  Those are responsible for defining the actual CMake compiler settings,
  setting up linker invocation, etc.

For highlevel toolchain verification, a new `zephyr_verify_toolchain`
function has been introduced which invokes the compiler to check its
working state.

Some compiler and linker properties requires testing the flags by
invoking the actual compiler or linker. This is done using
`check_set_compiler_property` and `check_set_linker_property`.
However such tests cannot be executed until CMake's `project()` function
has been called. Therefore calls to those functions are defered until
the basic toolchain has been verified using `zephyr_verify_toolchain`.

This allows us to introduce the above structure and thereby cleaning up
toolchain handling and improving the design. It also allows compiler and
linker target CMake files to use compiler properties as they are now
available at an earlier stage.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
Align the compiler optimization property names with their corresponding
Kconfig settings, as example so the property name `size_optimizations`
matches `CONFIG_SIZE_OPTIMIZATIONS`.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
Support choice handling for compiler property.
Some compiler configuration in Kconfig is handled using choices, such as
compiler optimization.
The compiler infrastructure uses property values for handling compiler
flag variations between compilers.
This works well when describing the compiler but when having to apply
flags based on a Kconfig choice selection it results in constructs like:
> if(CONFIG_ENTRY_A)
>   zephyr_compile_options($<TARGET_PROPERTY:compiler,entry_a>)
> elseif(CONFIG_ENTRY_B)
>   zephyr_compile_options($<TARGET_PROPERTY:compiler,entry_b>)
> elseif(CONFIG_ENTRY_C)
>   zephyr_compile_options($<TARGET_PROPERTY:compiler,entry_c>)
> ...

which may even have to be repeated multiple times.

Introduce a higher property name which can match the choice name and
which support taking the currently selected property value, while
still keep current infrastructure of the compiler defining property
values for all flags.

Function signature:
> set_compiler_property([APPEND] PROPERTY <name> CHOICE <name>...)

This allows the if construct above to be simplified to:
>  zephyr_compile_options($<TARGET_PROPERTY:compiler,<choice_name>)

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
Support linker optimization properties.
Allow the linker property to inherit the property values of the compiler
when those are identical.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
The path to a library may be depending on optimization level.
Therefor include compiler optimization level for gcc / clang.

For gcc and clang, then the same optimization flags are used during
linking and therefor the property from the compiler flags is used.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
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 <keithp@keithp.com>
@tejlmand tejlmand force-pushed the linker_optimization branch from 370151c to 4fc9a17 Compare May 16, 2025 09:25
Copy link

Copy link
Contributor

@keith-packard keith-packard left a comment

Choose a reason for hiding this comment

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

I've tested this using Zephyr SDK 0.18 pre-release bits (which enable multilib-space). It's selecting the right libraries for libc, libstdc++, libgcc as well as the correct object files for crtbegin and crtend. If the remaining minor issues can be resolved, this looks good to me

Comment on lines +20 to +25
set_compiler_property(PROPERTY optimization
CHOICE no_optimizations
debug_optimizations
speed_optimizations
size_optimizations
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Weird indentation here (mixing leading tabs and spaces)

Comment on lines +32 to +38
set_compiler_property(PROPERTY optimization
CHOICE no_optimizations
debug_optimizations
speed_optimizations
size_optimizations
size_optimizations_aggressive
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

Comment on lines +31 to +37
set_compiler_property(PROPERTY optimization
CHOICE no_optimizations
debug_optimizations
speed_optimizations
size_optimizations
size_optimizations_aggressive
)
Copy link
Contributor

Choose a reason for hiding this comment

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

And here

@keith-packard
Copy link
Contributor

I can't reproduce the failure shown in CI, but I think it's because compile_rt_library doesn't use the -m32 option. I've created a small patch which just disables use of that function and lets the linker sort out the runtime library itself. The alternative would be to create a function that appends options to TOOLCHAIN_C_FLAGS and have arch/posix/CMakeLists.txt use that.

keith-packard@6c1e250

@keith-packard
Copy link
Contributor

I added a bunch of minor fixes on top of this over in #90353. Feel free to mix those in if you like and get this ready for merging.

Copy link

This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time.

@github-actions github-actions bot added the Stale label Jul 23, 2025
@keith-packard
Copy link
Contributor

We still need something like this for SDK 0.18

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants