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

Idea: semantic target compile settings #272

Open
mbeutel opened this issue Aug 16, 2019 · 0 comments
Open

Idea: semantic target compile settings #272

mbeutel opened this issue Aug 16, 2019 · 0 comments

Comments

@mbeutel
Copy link
Contributor

mbeutel commented Aug 16, 2019

Modern CMake has introduced abstractions for many compiler options to make it easier to write compiler-agnostic build scripts. For example, when compiling for C++17, instead of writing

if(MSVC)
    target_compile_options(MyTarget PUBLIC /std:c++17)
else()
    # let's just hope that every other compiler in the world imitates GCC's command-line interface
    target_compile_options(MyTarget PUBLIC -std=c++17)
endif()

we can now focus on the semantics and have CMake supply the compiler-specific switch:

target_compile_features(MyTarget PUBLIC cxx_std_17)

Unfortunately, no such abstraction currently exists for most other compiler switches. And some of them are (or rather, should be) very commonplace, e.g. compiling with high warning level (such as -Wall -Wextra -pedantic) or disabling various legacy quirks (/permissive- for VC++), and having to resort to compiler-specific CMake code for such simple things is very unpleasant.

I have a rough prototype for a CMake function called target_compile_settings() which looks similar to target_compile_features() and exposes semantic settings for many compiler switches. Example:

target_compile_settings(MyTarget
    PRIVATE
        default # enables non-controversial defaults such as `/permissive-`
        diagnostics.pedantic # equivalent of `-Wall -Wextra -pedantic`
        $<$<CONFIG:Debug>:runtime-checks>) # in debug builds, enable most runtime checks (e.g. ASan, UBSan, stack guard)

Most of my projects use these settings.

As you can see, we can express conditional settings with generator expressions; runtime checks are enabled only if the config is "Debug". (Ideally, CMake would have a dedicated "is it a debug config?" generator expression that respects the DEBUG_CONFIGURATIONS variable, but that is a separate issue.)

Now assume that we want runtime checks but we rely on 3rd-party code that has unfixed issues with UB, so we want to disable UBSan. Settings are structured hierarchically, and "runtime-checks" is comprised of the settings "runtime-checks.asan", "runtime-checks.ubsan", and "runtime-checks.stack". So what if we only want to opt out of a single nested setting?

target_compile_settings(MyTarget
    PRIVATE
        $<$<CONFIG:Debug>:runtime-checks> # in debug builds, enable most runtime checks
        no-runtime-checks.ubsan) # ...but opt out of UBSan

Now, let's say we want to use a relaxed FP model so the compiler has more freedom optimizing FP code. Unlike -Wall -Wextra which is relatively portable on non-Windows platforms, the FP model flags wildly vary among MSVC, GCC, Clang, ICC, NVCC. Hence we introduce a simple monotonic sequence of settings [strict, consistent, precise, fast, fastest] that mostly covers the spectrum of existing FP model settings:

target_compile_settings(MyTarget
    PRIVATE
        fp-model=precise) # maintain value safety, but permit contractions

Sometimes we don't want a setting in the build script but instead want to configure it in the CMake cache. An example would be enabling the debug version of the standard library (checked iterators and such): this definitely needs explicit opt-in because it has a significant perf impact and alters class layouts. So if we wanted the debug version, we could say

# in CMakeCache.txt
# PUBLIC_COMPILE_SETTINGS sets both COMPILE_SETTINGS and INTERFACE_COMPILE_SETTINGS
PUBLIC_COMPILE_SETTINGS:STRING=debug-stdlib

Or if we wanted to compile the project for a particular target architecture:

# in CMakeCache.txt
COMPILE_SETTINGS:STRING=cpu-target-architecture=skylake-server;cuda-architecture=gm_61

Some individual settings could have a dedicated option:

# in CMakeCache.txt
CPU_ARCHITECTURE:STRING=skylake-server

I hope that such a feature finds its way into CMake someday; but it might be sensible to prototype it in a CMake script library first.

Do you think such a module would be a good fit for YCM? If so, I'd open a branch in my fork and open a WIP pull request so we can work out the details.

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

No branches or pull requests

1 participant