Skip to content
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

CMake: Set required toolchain and processor flags globally, instead of per-target #13987

Merged
merged 9 commits into from
Dec 10, 2020

Conversation

multiplemonomials
Copy link
Contributor

Summary of changes

On the surface, this change fixes this issue when using GCC Arm:

Detecting C Compiler ABI -- Failed

The cause of the issue is that certain key compiler flags were only being added on a per-target basis instead of to CMAKE_C_FLAGS etc. This is a problem because CMake needs to perform compile checks when configuring a project, and to do these it only uses CMAKE_C_FLAGS etc., not any of the per-target flags. And since the flags were missing, all of the compile checks were failing. Until now, this has been papered over by:

set(CMAKE_C_COMPILER_WORKS TRUE)
set(CMAKE_CXX_COMPILER_WORKS TRUE)

which lets CMake continue even though it can't successfully run the compiler (!). Also, I believe that the issue only manifests with GCC, not ARMClang, because ARMClang happens to work OK without any additional options provided. However, there are likely more subtle issues: CMake scripts that check if a function exists are likely to always fail because CMake cannot use the linker. Additionally, CMake scripts that test various attributes of the target processor (e.g. "how large is an int for this processor target") might return the wrong results because CMake is always testing with the default compiler target rather than the set one.

To fix the issue, I changed how the options for the target are collected. The toolchain file now builds a list of compiler and link options directly. It then passes these off to CMake via CMAKE_<LANGUAGE>_FLAGS_INIT and CMAKE_EXE_LINKER_FLAGS_INIT, which will get loaded into CMAKE_C_FLAGS etc. the first time CMake is run. Yes, this method is undocumented, but it is the correct way to do it based on research I did into the CMake source code when I was creating mbed-cmake.

One caveat of this method: If the toolchain or processor core is changed, then the build dir has to be deleted and the project must be reconfigured from scratch (just like with mbed-cmake). This is the only way to force CMake to pick up the new compiler flags. However, I think this change is a big win overall as it allows all of CMake's internal logic to actually function properly.

Also, I don't have access to ARMClang right now, so I could only test with GCC Arm. You will need to test that on your guys' end before merging.

Hope this all makes sense! Let me know if there are any questions or concerns.

Impact of changes

Migration actions required

core.cmake

Documentation

None


Pull request type

[X] Patch update (Bug fix / Target update / Docs update / Test update / Refactor)
[] Feature update (New feature / Functionality change / New API)
[] Major update (Breaking change E.g. Return code change / API behaviour change)

Test results

[X] No Tests required for this change (E.g docs only update)
[] Covered by existing mbed-os tests (Greentea or Unittest)
[] Tests / results supplied as part of this PR

Reviewers

@0xc0170
@hugueskamba


@multiplemonomials
Copy link
Contributor Author

Oh also, almost forgot, this code uses an undocumented trick I discovered a while ago with CMake. If you just include the toolchain file before calling enable_language(), that's actually the same as using CMAKE_TOOLCHAIN_FILE. Plus, variables that you set in your main script can actually be loaded by the toolchain file this way.

@ciarmcom ciarmcom added the release-type: patch Indentifies a PR as containing just a patch label Dec 1, 2020
@ciarmcom ciarmcom requested review from 0xc0170, hugueskamba and a team December 1, 2020 00:30
@ciarmcom
Copy link
Member

ciarmcom commented Dec 1, 2020

@multiplemonomials, thank you for your changes.
@0xc0170 @hugueskamba @ARMmbed/mbed-os-tools @ARMmbed/mbed-os-maintainers please review.

Copy link
Collaborator

@hugueskamba hugueskamba left a comment

Choose a reason for hiding this comment

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

Quick review, a more in-depth one coming up.
Thanks

Comment on lines 57 to 52
MBED_RTOS_SINGLE_THREAD
__NEWLIB_NANO
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please revert this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Dang, CLion has no setting for putting the closing paren at the outer indent level, and in fact it auto indents it whenever I paste code... Do you have any way to auto reformat these?

Copy link
Contributor

Choose a reason for hiding this comment

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

We do not yet have auto formatter in place, if you got any suggestions , we would like to try it out.

Comment on lines 63 to 57
"--specs=nano.specs"
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please revert this.

list_to_space_separated(CMAKE_C_FLAGS_INIT ${common_options} ${c_cxx_compile_options})
set(CMAKE_CXX_FLAGS_INIT ${CMAKE_C_FLAGS_INIT})
list_to_space_separated(CMAKE_ASM_FLAGS_INIT ${common_options} ${asm_compile_options})
list_to_space_separated(CMAKE_EXE_LINKER_FLAGS_INIT ${link_options})
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add a new line.

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 1, 2020

I'll fetch this tomorrow to review locally to get detail view as this changes lot of files.

For consideration: _COMPILER_WORKS we defined and add set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) - just try to compile but not link as we are not at the stage where linker works (we need custom flags that come later from targets and application possibly).

We intentionally do not touch global symbols as xxx_FLAGS. We started using global symbols like this but then refactored to use target properties, following the simple guidance: Reduce the usage of global variables and embrace targets and properties.

I think this change is a big win overall as it allows all of CMake's internal logic to actually function properly.

Is this referring to try_compile() check CMake is doing at first run? I wonder how project using target properties rather than touching directory/project settings shall work with this check? The initial check should not force us to add our flags to the global symbols ? I'll need to check this in detail.

@multiplemonomials
Copy link
Contributor Author

we are not at the stage where linker works (we need custom flags that come later from targets and application possibly).

The whole point of this PR is to get us to the stage where the compiler and linker do work reliably when CMake needs to use them! In my testing with GCC at least, this problem is totally fixed.

We started using global symbols like this but then refactored to use target properties, following the simple guidance: Reduce the usage of global variables and embrace targets and properties.

This is good advice to follow in general, but unfortunately it does not apply in the specific case of cross compiling and toolchain files. They are an older feature of CMake and require the older style of setting up flags in order to make things work properly. Trust me, I've been using CMake for 6 years, this is the only correct way to add these flags and there isn't a way to do it properly using target flags only.

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 2, 2020

I got counter proposal that fixes as well Gcc Arm checks: #13993

I provided information for the fix in the commit message. This is connected to project() and providing init values via toolchain file so compiler and linker work properly in the init phase (not expecting to have entire project configuration there (I would reference this answer as it provides useful tips: https://gitlab.kitware.com/cmake/cmake/-/issues/18356#note_454620).
I modified init linker flags to satisfy linker needs and checks should be now ok with the PR 13993.

We will still review this PR, I would like to test some of the changes here.

Copy link
Contributor

@0xc0170 0xc0170 left a comment

Choose a reason for hiding this comment

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

Left some suggestions but the concept looks fine to me.

tools/cmake/app.cmake Outdated Show resolved Hide resolved
endif()
endfunction()
if(${MBED_TOOLCHAIN} STREQUAL "GCC_ARM")
list(APPEND common_options
Copy link
Contributor

Choose a reason for hiding this comment

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

would it make sense to introduce own list for each FLAGS?

MBED_TOOLCHAIN_<LANG>_FLAGS so C/CXX/ASM/LD, and we would add these to CMake _INIT flags.

These could be cached variable, similar as _INIT flags.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's already how I have it set up. link_options is for linker flags, common_options is for all compilers, c_cxx_compile_options is for C and CXX compilers, and asm_compile_options is for ASM only.

Copy link
Contributor

@0xc0170 0xc0170 Dec 7, 2020

Choose a reason for hiding this comment

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

correct the use is as it should. we use mbed prefix ( MBED_TOOLCHAIN or so), if these could be prefixed as well but they might not, see my comment below

Copy link
Contributor

@0xc0170 0xc0170 Dec 7, 2020

Choose a reason for hiding this comment

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

As these are not global symbols, it does not need to be prefixed neither with capital letters

@mergify
Copy link

mergify bot commented Dec 3, 2020

This PR cannot be merged due to conflicts. Please rebase to resolve them.

@ladislas
Copy link
Contributor

ladislas commented Dec 4, 2020

@multiplemonomials thanks for the PR, I'm currently testing it.

First issue I have with multiple targets is that mbed_generate_options_for_linker tries to generate compile_time_defs.txt twice.

Applying the following patch will fix the issue:

diff --git a/tools/cmake/toolchain.cmake b/tools/cmake/toolchain.cmake
index faec42f281..d91fd196e8 100644
--- a/tools/cmake/toolchain.cmake
+++ b/tools/cmake/toolchain.cmake
@@ -19,8 +19,8 @@ function(mbed_generate_options_for_linker target definitions_file)
     set(_compile_definitions
         "$<$<BOOL:${_compile_definitions}>:-D$<JOIN:${_compile_definitions}, -D>>"
     )
-    file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/compile_time_defs.txt" CONTENT "${_compile_definitions}\n")
-    set(${definitions_file} @${CMAKE_BINARY_DIR}/compile_time_defs.txt PARENT_SCOPE)
+    file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/${target}_compile_time_defs.txt" CONTENT "${_compile_definitions}\n")
+    set(${definitions_file} @${CMAKE_BINARY_DIR}/${target}_compile_time_defs.txt PARENT_SCOPE)
 endfunction()
 # Set the system processor depending on the CPU core type
 if (MBED_CPU_CORE STREQUAL Cortex-A9)

With this fixed, I'm then facing the same issue about the linker script missing for one my targets.

EDIT: The number of files compiled is also around 735, with mbed-os being built multiple times.

@multiplemonomials
Copy link
Contributor Author

@ladislas Yeah I thought that those issues were outside the scope of this PR. I fixed them in my other branch: https://github.com/multiplemonomials/mbed-os/tree/cmake-object-libs

@ladislas
Copy link
Contributor

ladislas commented Dec 7, 2020

@0xc0170 https://github.com/cheshirekow/cmake_format looks like a nice tool

@multiplemonomials
Copy link
Contributor Author

Not sure why I can't reply to your comment @0xc0170 , but is it a requirement for contributions that local variables have to be lowercase? It's not the code style I used for any of the mbed-cmake submissions, and I don't believe it's what CMake themselves use for their scripts. But if so I can try to update it.

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 8, 2020

Not sure how I replied by via review. Anyway, all fine , just reverting changes to the style that are not consistent (@hugueskamba commented on those couple days back). If you can revert them, we shall proceed to get this in for the upcoming release.

Otherwise looks good to me.

@multiplemonomials
Copy link
Contributor Author

OK, all the formatting issues should hopefully be fixed.

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 8, 2020

ARMClang:

armclang: error: ARM Compiler does not support '-mcpu=Cortex-M4-mcpu=cortex-m4'
armclang: error: ARM Compiler does not support '-mcpu=Cortex-M4-mcpu=cortex-m4'
armclang: error: armasm does not support CPU 'cortex-m4-mcpu=cortex-m4'
armclang: error: armasm does not support FPU 'unknown'

GCC Arm all fine.

)
# Sets toolchain options
list(APPEND common_options
"-mthumb"
Copy link
Contributor

Choose a reason for hiding this comment

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

-c was removed as it's not required, just checking if it was intentionally removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep that was intentional, CMake will add -c as needed.

)
list(APPEND asm_compile_options
-masm=auto
--target=arm-arm-none-eabi
Copy link
Contributor

Choose a reason for hiding this comment

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

there's not CMAKE_ASM_COMPILER_TARGET as we do above for C/CXX ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't believe so... though it kinda depends on how ARM implemented the CMake scripts for ARM Compiler. You could try adding it (and removing the manual --target flag) and see if it works.

"-mfloat-abi=hard"
)
list(APPEND asm_compile_options
"-mcpu=Cortex-M4"
Copy link
Contributor

@0xc0170 0xc0170 Dec 8, 2020

Choose a reason for hiding this comment

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

this is probably causing ARMClang to fail as , the command for K64F startup file (asm file) contains -mcpu=Cortex-M4-mcpu=cortex-m4

@multiplemonomials
Copy link
Contributor Author

@0xc0170 I've seen that issue before but it should have been fixed in this commit. Are you sure you deleted and recreated your build directory after updating to the latest version of the code?

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 9, 2020

Just to make sure: I am on commit 36288029c1
running command: mbedtools compile -m DISCO_L475VG_IOT01A -t ARM. I removed mbedbuild and also cmake_build directories.

-mcpu=Cortex-M4-mcpu=cortex-m4 -c -o CMakeFiles\mbed-os-example-blinky.dir\mbed-os\targets\TARGET_STM\TARGET_STM32L4\TARGET_STM32L475xG\TOOLCHAIN_ARM\startup_stm32l475xx.o ..\mbed-os\targets\TARGET_STM\TARGET_STM32L4\TARGET_STM32L475xG\TOOLCHAIN_ARM\startup_stm32l475xx.S
armclang: error: ARM Compiler does not support '-mcpu=Cortex-M4-mcpu=cortex-m4'
armclang: error: ARM Compiler does not support '-mcpu=Cortex-M4-mcpu=cortex-m4'
armclang: error: armasm does not support CPU 'cortex-m4-mcpu=cortex-m4'
armclang: error: armasm does not support FPU 'unknown'

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 9, 2020

This is how my Cache looks like. I can see there are duplicates also for CXX flags (mcpu 2x).

//Flags used by the ASM compiler during all build types.
CMAKE_ASM_FLAGS:STRING=-mthumb -Wno-armcc-pragma-push-pop -Wno-armcc-pragma-anon-unions -Wno-reserved-user-defined-literal -Wno-deprecated-register -fdata-sections -fno-exceptions -fshort-enums -fshort-wchar -masm=auto --target=arm-arm-none-eabi -mcpu=Cortex-M4-mcpu=cortex-m4

//Flags used by the CXX compiler during all build types.
CMAKE_CXX_FLAGS:STRING=-mthumb -Wno-armcc-pragma-push-pop -Wno-armcc-pragma-anon-unions -Wno-reserved-user-defined-literal -Wno-deprecated-register -fdata-sections -fno-exceptions -fshort-enums -fshort-wchar -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mcpu=cortex-m4

Looking at CMAKE_ASM_FLAGS_INIT, it looks good

-mthumb -Wno-armcc-pragma-push-pop -Wno-armcc-pragma-anon-unions -Wno-reserved-user-defined-literal -Wno-deprecated-register -fdata-sections -fno-exceptions -fshort-enums -fshort-wchar -masm=auto --target=arm-arm-none-eabi -mcpu=Cortex-M4

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 9, 2020

Found it https://github.com/Kitware/CMake/blob/master/Modules/Compiler/ARMClang.cmake#L97, it is set as we set CMAKE_SYSTEM_PROCESSOR

@multiplemonomials
Copy link
Contributor Author

Oh, nice catch! That's actually kind of a bug in the line you linked, it should have a space before -mcpu=${CMAKE_SYSTEM_PROCESSOR} in the string constant. But the easy fix is to just make sure the init flags end with a space,

@multiplemonomials
Copy link
Contributor Author

OK @0xc0170 give my latest commit a shot, should be fixed.

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 10, 2020

CI started

@mergify mergify bot added needs: CI and removed needs: review labels Dec 10, 2020
@mbed-ci
Copy link

mbed-ci commented Dec 10, 2020

Jenkins CI Test : ✔️ SUCCESS

Build Number: 1 | 🔒 Jenkins CI Job | 🌐 Logs & Artifacts

CLICK for Detailed Summary

jobs Status
jenkins-ci/mbed-os-ci_unittests ✔️
jenkins-ci/mbed-os-ci_cmake-example-ARM ✔️
jenkins-ci/mbed-os-ci_cmake-example-GCC_ARM ✔️
jenkins-ci/mbed-os-ci_build-greentea-GCC_ARM ✔️
jenkins-ci/mbed-os-ci_build-greentea-ARM ✔️
jenkins-ci/mbed-os-ci_build-example-ARM ✔️
jenkins-ci/mbed-os-ci_build-cloud-example-ARM ✔️
jenkins-ci/mbed-os-ci_build-example-GCC_ARM ✔️
jenkins-ci/mbed-os-ci_build-cloud-example-GCC_ARM ✔️
jenkins-ci/mbed-os-ci_cmake-example-test ✔️
jenkins-ci/mbed-os-ci_greentea-test ✔️

@0xc0170 0xc0170 merged commit cca6652 into ARMmbed:master Dec 10, 2020
@mergify mergify bot removed the ready for merge label Dec 10, 2020
@mbedmain mbedmain added release-version: 6.6.0 Release-pending and removed release-type: patch Indentifies a PR as containing just a patch Release-pending labels Dec 11, 2020
@multiplemonomials multiplemonomials deleted the cmake-global-options branch May 17, 2023 06:54
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.

7 participants