From bd94de4aa01d285de65ec9e4ef98ec7c9f42578c Mon Sep 17 00:00:00 2001 From: Nikola Radakovic Date: Thu, 10 Sep 2026 17:39:57 +0100 Subject: [PATCH] Add support for C99 --- docs/features.md | 10 ++++++- features/custom/linux/make_cc_features.bzl | 1 + features/custom/qnx/make_cc_features.bzl | 1 + features/native/default_compile_flags/BUILD | 18 +++++++++++- features/native/markers/BUILD | 6 ++++ tests/BUILD | 1 + tests/language_and_standards/BUILD | 11 +++++++ .../language_and_standards/c99_feature_test.c | 29 +++++++++++++++++++ 8 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/language_and_standards/c99_feature_test.c diff --git a/docs/features.md b/docs/features.md index bb20348..318a29a 100644 --- a/docs/features.md +++ b/docs/features.md @@ -27,12 +27,20 @@ enabled by default. - **`supports_header_path_normalization`** (Linux) — Suppresses absolute-path warnings for system headers. - **`dbg`** / **`opt`** (both) — Well-known build-mode markers used to select flags. +- **`gnu11`** (Linux) *opt-in* — Switches C compilation from the default + `-std=c11` to `-std=gnu11`. +- **`c99`** (both) *opt-in* — Switches C compilation from the default + `-std=c11` to `-std=c99`. ## Compilation - **`unfiltered_compile_flags`** (both) — Redacts `__DATE__`/`__TIME__`/`__TIMESTAMP__` for reproducible builds. - **`default_compile_flags`** (both) — Core compile flags plus `dbg`/`opt` - build-mode variants (exact flags differ per target). + build-mode variants (exact flags differ per target). C compilation defaults + to `-std=c11`; request `--features=gnu11` (Linux) or `--features=c99` (both) + to switch the C standard. Only one of `c11`/`gnu11`/`c99` should be active + at a time — requesting `gnu11` and `c99` together applies both `-std=` flags, + with the compiler honoring the last one seen. - **`pic`** (Linux) — Emits `-fPIC` when the `pic` build variable is available. QNX declares the `supports_pic` capability marker but does not add `-fPIC` in the default compile flags. diff --git a/features/custom/linux/make_cc_features.bzl b/features/custom/linux/make_cc_features.bzl index 6e64324..9727c5d 100644 --- a/features/custom/linux/make_cc_features.bzl +++ b/features/custom/linux/make_cc_features.bzl @@ -17,6 +17,7 @@ _LINUX_FEATURES = [ ("@score_bazel_cpp_toolchains//features/native/markers:dbg", False), # Bazel auto-toggles via -c dbg ("@score_bazel_cpp_toolchains//features/native/unfiltered_compile_flags", True), ("@score_bazel_cpp_toolchains//features/native/markers:gnu11", False), # opt-in + ("@score_bazel_cpp_toolchains//features/native/markers:c99", False), # opt-in ("@score_bazel_cpp_toolchains//features/native/default_compile_flags", True), ("@score_bazel_cpp_toolchains//features/native/random_seed", True), ("@score_bazel_cpp_toolchains//features/native/include_paths", True), diff --git a/features/custom/qnx/make_cc_features.bzl b/features/custom/qnx/make_cc_features.bzl index 3f5196f..511ae8a 100644 --- a/features/custom/qnx/make_cc_features.bzl +++ b/features/custom/qnx/make_cc_features.bzl @@ -38,6 +38,7 @@ _QNX_FEATURES = [ ("@score_bazel_cpp_toolchains//features/native/markers:no_legacy_features", True), ("@score_bazel_cpp_toolchains//features/native/unfiltered_compile_flags", True), ("@score_bazel_cpp_toolchains//features/custom/qnx/gcc_version_flags", True), + ("@score_bazel_cpp_toolchains//features/native/markers:c99", False), # opt-in ("@score_bazel_cpp_toolchains//features/native/default_compile_flags", True), ("@score_bazel_cpp_toolchains//features/native/random_seed", True), ("@score_bazel_cpp_toolchains//features/native/include_paths", True), diff --git a/features/native/default_compile_flags/BUILD b/features/native/default_compile_flags/BUILD index 45c0eb2..6700e39 100644 --- a/features/native/default_compile_flags/BUILD +++ b/features/native/default_compile_flags/BUILD @@ -53,7 +53,10 @@ cc_args( cc_feature_constraint( name = "not_gnu11", - none_of = ["//features/native/markers:gnu11"], + none_of = [ + "//features/native/markers:gnu11", + "//features/native/markers:c99", + ], ) cc_feature_constraint( @@ -61,6 +64,11 @@ cc_feature_constraint( all_of = ["//features/native/markers:gnu11"], ) +cc_feature_constraint( + name = "is_c99", + all_of = ["//features/native/markers:c99"], +) + cc_args( name = "c_std_c11_args", actions = ["@rules_cc//cc/toolchains/actions:c_compile_actions"], @@ -75,6 +83,13 @@ cc_args( requires_any_of = [":is_gnu11"], ) +cc_args( + name = "c_std_c99_args", + actions = ["@rules_cc//cc/toolchains/actions:c_compile_actions"], + args = ["-std=c99"], + requires_any_of = [":is_c99"], +) + cc_args( name = "default_cxx_compile_flags_args", actions = ["@rules_cc//cc/toolchains/actions:cpp_compile_actions"], @@ -152,6 +167,7 @@ cc_feature( ":target_cpu_flags_args", ":c_std_c11_args", ":c_std_gnu11_args", + ":c_std_c99_args", ":default_cxx_compile_flags_args", ":dbg_compile_flags_args", ":opt_compile_flags_args", diff --git a/features/native/markers/BUILD b/features/native/markers/BUILD index 29691d7..6993d3e 100644 --- a/features/native/markers/BUILD +++ b/features/native/markers/BUILD @@ -75,6 +75,12 @@ cc_feature( visibility = ["//visibility:public"], ) +cc_feature( + name = "c99", + feature_name = "c99", + visibility = ["//visibility:public"], +) + ## QNX only cc_feature( name = "dependency_file_named_implicitly", diff --git a/tests/BUILD b/tests/BUILD index 501e233..401dc9c 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -23,6 +23,7 @@ Root test suite definition combining all test categories. test_suite( name = "language_and_standards_tests", tests = [ + "//language_and_standards:c99_feature_test", "//language_and_standards:c_lang_test", "//language_and_standards:cpp11_test", "//language_and_standards:cpp14_test", diff --git a/tests/language_and_standards/BUILD b/tests/language_and_standards/BUILD index 0cc4b59..e42f3b5 100644 --- a/tests/language_and_standards/BUILD +++ b/tests/language_and_standards/BUILD @@ -38,6 +38,17 @@ cc_test( copts = ["-std=c99"], ) +# Test for: the `c99` toolchain feature (as opposed to explicit -std= copts) +# Verifies: enabling the `c99` feature switches the compiler onto -std=c99; +# a negative-array-size typedef gated on __STDC_VERSION__ only +# compiles under c99, so it fails to build if the feature didn't +# take effect +cc_test( + name = "c99_feature_test", + srcs = ["c99_feature_test.c"], + features = ["c99"], +) + # ============================================================================ # C++ Standard Version Tests # ============================================================================ diff --git a/tests/language_and_standards/c99_feature_test.c b/tests/language_and_standards/c99_feature_test.c new file mode 100644 index 0000000..e67d2a7 --- /dev/null +++ b/tests/language_and_standards/c99_feature_test.c @@ -0,0 +1,29 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +// Test for: the `c99` toolchain feature (enabled via the `features` attribute +// below, mirroring `--features=c99`). Unlike the other tests in this package, +// this does not pass `-std=` via copts: it relies entirely on the toolchain +// feature to select the C standard. +// +// GCC accepts C11-only keywords (_Generic, _Noreturn, ...) as an extension +// under -std=c99 too, so they don't actually depend on the active standard +// here. Instead this uses the standard-mandated `__STDC_VERSION__` macro in a +// real constraint: an array with a negative size is an ISO C constraint +// violation, so the typedef below only compiles when the active standard is +// exactly C99. +typedef char standard_must_be_c99[(__STDC_VERSION__ == 199901L) ? 1 : -1]; + +int main(void) { + return sizeof(standard_must_be_c99) - 1; +}