-
Notifications
You must be signed in to change notification settings - Fork 18
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
Introduce CMake toolchain #76
base: main
Are you sure you want to change the base?
Conversation
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.
"We need to verify CMAKE_CXX_COMPILER_ID for g++ on macos is AppleClang."
Confirm what the compiler identification is for the default false g++ on Darwin is.
Marking "Request changes" so this doesn't get landed prematurely.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
So, yes: |
Not sure if picking the toolchain for Darwin better, or making the generic toolchain smarter would work better, but either should work? |
Wait, that can't work!
|
I am leaning on having separate tool chain files and having like a central tool chain dispatch logic based on compiler and platform. But then I realized there's not that much variance in building across platforms and compilers, at least in exemplar, to warrant separate files. |
That is why often I use the project_options |
That's project looks fantastic! I can bring this up in weekly sync and see if we want to use this. |
Ah I think tool chain file is executed before |
5f20499
to
117fcd9
Compare
a3f18b3
to
b000f40
Compare
Okay I can try to go back to implement toolchain file |
@camio I implemented this using toolchain files, is this more what you are looking for? |
cmake/gnu-toolchain.cmake
Outdated
set(CMAKE_C_COMPILER gcc) | ||
set(CMAKE_CXX_COMPILER g++) | ||
|
||
if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") |
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.
Modeling sanitizers as a build type works better, either that or an entirely distinct toolchain so Thread and Memory can be uniformly applied to all packages. If everything in an address space aren't using msan or tsan the reports they provide are broken, so you have to rebuild and relink the whole world consistently.
UB sanitizer and address, don't suffer the same problems.
So something like (not tested!):
set(CMAKE_CXX_FLAGS_ASAN
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fsanitize=address,undefined,leak"
CACHE STRING
"C++ ASAN Flags"
FORCE
)
Also at -O0 there's often no undefined behavior emitted for the sanitizer to see, for the same reasons that debug builds seg fault less often.
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.
(optional26 doesn't use the _INIT variables because it's copied from ancient sources before that rule was clarified. Above should be using the *_INIT vars)
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 write-up.
Separate ASAN as build targets seems a bit like overkill for the exemplars use case.
The design goal here isn't to have a full fledged instrumentation based analysis build system but just a quick hand for "enable all flags for sanitizers".
Given there's no dependency for exemplar, and the current recommendation for dependency management is to build with dependency's source code instead of including the dependent library at link time. I don't think there's value in complications here.
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.
Remember, though, exemplar doesn't do anything. It's entire purpose is to serve as a starting point and reference point for further work. Everything we've done is entirely overkill for providing ... checks notes ... std::identity
.
Recommending building as part of the dependers source tree is a huge overstatement. We're making that possible, but it's still a terrible idea and does not scale to large systems. Getting to the point where we play well with package systems with public visibility is still on the todo list. (I haven't made it work with my internal one, but I know exactly how to.)
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.
Ah I see where u r coming from, I didn't think about exemplar as a dependency for other libraries (being a dependent) and were only commenting on its use of dependency and a standalone development library / CI test target.
I think you are right, there should be an ASAN target to produce an ASAN enabled library so someone could link us as a dependency to use. I get what you are talking about. But I think this is more of a package/ export issue, outside of scope for this PR for now and to be honest outside of my skill tree for now.
Again again again, the main motivation here is just to simply CI/ workflow.
Honestly I am tentatively waiting for someone to implement package export, do a quick write up, evaluate it and yonk it over (just like code coverage).
Could we delegate this suggestion to another PR? Let me know if I should add something/ structure this tool chain in anticipation of this feature.
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.
Modeling sanitizers as a build type works better, either that or an entirely distinct toolchain so Thread and Memory can be uniformly applied to all packages.
How so? This isn't obvious for me.
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.
Tools like IDEs usually treat selecting the build type as a first class UI operation, where setting custom options is much more buried, so if running sanitizers is a build type, it's much easier to run them reliably that way.
The alternative of using a distinct toolchain where e.g. memory sanitizer is part of the default build types makes it easier to apply the same options across many packages. That's particularly useful if you're using a package manager and getting pre-built libraries from them if they're available. Mixing thread or memory sanitizer libraries with ones without produces far too many false positives as the sanitizer can't do the tracking for memory initialization or lock acquisition/release in the libraries that aren't instrumented.
Address and undefined behavior sanitizers don't have that tracing/tracking problem, so they're reasonably accurate if just the code under test is instrumented.
Figuring out better ergonomics for handling sanitizers (and fuzzers, coverage, and the rest of the laundry list) can be ongoing work. Getting sanitizers in CI is an immediate improvement. I would base the sanitizers on the release or relwithdebinfo profile in CI, as debug tends to not exercise any of the runtime problems that the sanitizers detect. |
cmake/llvm-toolchain.cmake
Outdated
@@ -0,0 +1,21 @@ | |||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
|
|||
include_guard(GLOBAL) |
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.
Did you consider omitting this include guard?
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 will verify this afterwards.
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.
Cmake will process the toolchain file a random number of times if it isn't guarded. If you are careful and all the string operations are idempotent this is harmless, but it's a common source of bugs, as well as overhead in configuration.
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.
@steve-downey I think I've seen what you've described in a previous iteration, where the toolchain gets executed multiple times adding duplicated flags. If we assign string in this style: set(CMAKE_CXX_FLAGS_DEBUG_INIT "${CMAKE_CXX_FLAGS_DEBUG_INIT} ${OTHER_FLAGS}")
, we may have trouble with the toolchain getting executed multiple times.
This doesn't happen on this PR as the previous values of XXX_INIT doesn't get carried over.
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.
Looks like this is not needed. I have omitted include guard for current toolchain file, we can include this in the future if needed.
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.
That it doesn't produce incorrect results this time doesn't mean the template should drop it. It still adds overhead on reconfigure and can produce confusing bugs if it's not idempotent.
Begin as you mean to proceed in the example we are providing as the basis for a project.
cmake/llvm-toolchain.cmake
Outdated
set(CMAKE_C_COMPILER clang) | ||
set(CMAKE_CXX_COMPILER clang++) | ||
|
||
if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") |
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.
ASan already has a well-known meaning in the community: address sanitizer. Using the same word to mean "all sanitizers" is confusing.
What about "MaxSan" (maximum sanitizers) which would mean getting as many sanitizers enabled as possible.
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.
👌 good suggestion
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.
This is my fault, to the extent this is coming from optional26. Address composes with many others, and I didn't try to find a better name for the collection. MaxSan is at least not wrong, and I don't have a better idea.
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.
Adopted!
cmake/llvm-toolchain.cmake
Outdated
set(CMAKE_CXX_FLAGS_DEBUG_INIT | ||
"-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" | ||
) | ||
set(CMAKE_C_FLAGS_DEBUG_INIT | ||
"-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" | ||
) |
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.
Would this not also apply to release builds?
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.
Addressed, nice catch
cmake/msvc-toolchain.cmake
Outdated
set(CMAKE_CXX_FLAGS_DEBUG_INIT "/fsanitize=address /Zi") | ||
set(CMAKE_C_FLAGS_DEBUG_INIT "/fsanitize=address /Zi") |
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 /Zi
is related to ASan? Should it be enabled in all build modes?
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.
Yes.
Do I need to include documentation for this?
Omitting this flag will cause warning C5072.
MSVC side documentation:
https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-c5072?view=msvc-170
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 they fix it, we could remove the flag? "Why" comments are useful.
@camio this PR is ready for another round of review. |
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 left a couple minor naming suggestions, but otherwise this looks ready to ship.
set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") | ||
set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") | ||
|
||
set(RELEASE_FLAG "-O3 ${SANITIZER_FLAGS}") |
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 variable should be prefixed with BEMAN_BUILDSYS_
to avoid conflicts with project variables.
set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") | ||
set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") | ||
|
||
set(RELEASE_FLAG "-O3 ${SANITIZER_FLAGS}") |
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.
FLAG -> FLAGS to match the existing CMake conventions.
This PR adopts @bretbrownjr 's suggestion in #44 (review).
This PR introduces toolchain files for supported platforms:
Updated CI and preset to use the new toolchain files.
Race with #82