blob: f40c003700a844e06b4afe3b21b94db5b4c79e96 [file]
"""GNU Awk — Bazel build driven by rules_cc_autoconf.
`config.h` is generated by `autoconf_hdr` from upstream `configh.in`, probing
the real `cc_toolchain` instead of shipping per-OS pre-baked headers. Every
`AC_ARG_ENABLE` / `AC_ARG_WITH` option from upstream `configure.ac` surfaces
as a `bool_flag` or `label_flag` wired to a `config.h` macro via
`checks.AC_BUILD_SETTING`.
"""
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
load("@rules_cc_autoconf//autoconf:autoconf.bzl", "autoconf")
load("@rules_cc_autoconf//autoconf:autoconf_hdr.bzl", "autoconf_hdr")
load("@rules_cc_autoconf//autoconf:autoconf_srcs.bzl", "autoconf_srcs")
load("@rules_cc_autoconf//autoconf:checks.bzl", "checks", "macros", "utils")
load("@rules_cc_autoconf//autoconf:package_info.bzl", "package_info")
load(":gawk_minimal.bzl", "gawk_minimal")
exports_files([
"gawk_tool.sh.tpl",
"MODULE.bazel",
])
# ---------------------------------------------------------------------------
# User-facing build flags (mirror gawk's AC_ARG_ENABLE / AC_ARG_WITH options).
# ---------------------------------------------------------------------------
# Where configure says `--disable-FOO`, we declare a positively-named
# `:disable_foo` flag (default False). When True, the matching `#define` is
# emitted. This avoids the awkward "True means default behavior" inversion.
# Each entry declares a public `bool_flag` (default False) and, when
# `paired_setting = True`, a private `_<name>_setting` `config_setting`
# the rest of this file `select()`s on. `versioned_extension_dir` has
# no companion setting because no rule consumes it yet (declared for
# API parity with upstream's `--enable-versioned-extension-dir`).
_BOOL_FLAGS = [
("disable_lint", True),
("builtin_intdiv0", True),
("enable_mpfr", True),
("disable_pma", True),
("disable_extensions", True),
("enable_readline", True),
("versioned_extension_dir", False),
]
[
bool_flag(
name = name,
build_setting_default = False,
visibility = ["//visibility:public"],
)
for name, _ in _BOOL_FLAGS
]
[
config_setting(
name = "_{}_setting".format(name),
flag_values = {":" + name: "True"},
visibility = ["//:__subpackages__"],
)
for name, paired in _BOOL_FLAGS
if paired
]
# ---------------------------------------------------------------------------
# label_flag providers for MPFR / readline.
#
# We deliberately don't add `bazel_dep`s on `@mpfr` / `@readline` in
# MODULE.bazel — the readline BCR module pulls in `@ncurses`, which itself
# uses gawk to generate `term.h`, creating an unbreakable analysis-time
# cycle. Letting the user supply their own provider via these label_flags
# avoids that, and works even when the upstream BCR modules don't link
# cleanly in a given environment.
#
# When the matching `:enable_<lib>` bool_flag is True but the label_flag
# is left at its default `:_<lib>_unset` sentinel, the compile fails with
# a clear `#error` pointing the user at the right flag to set.
# ---------------------------------------------------------------------------
# Each entry declares a public `label_flag` whose default is a private
# `_<name>_unset` cc_library that emits a `#error` pointing the user at
# the right flag to set, so flipping the matching `:enable_<name>` flag
# without supplying a real provider fails with a clear message.
_LABEL_FLAGS = [
("mpfr", "enable_mpfr", "@mpfr//:mpfr"),
("readline", "enable_readline", "@readline//:readline"),
]
[
write_file(
name = "_{}_unset_c".format(name),
out = "_{}_unset.c".format(name),
content = [
"#error \"`//:{flag}` is True but `//:{name}` was left at its default sentinel. Set `--//:{name}=<your {name} provider>` (e.g. `--//:{name}={example}`) to enable {name} support.\"".format(
name = name,
example = example,
flag = flag,
),
],
)
for name, flag, example in _LABEL_FLAGS
]
[
cc_library(
name = "_{}_unset".format(name),
srcs = [":_{}_unset_c".format(name)],
tags = ["manual"],
)
for name, _, _ in _LABEL_FLAGS
]
[
label_flag(
name = name,
build_setting_default = ":_{}_unset".format(name),
tags = ["manual"],
visibility = ["//visibility:public"],
)
for name, _, _ in _LABEL_FLAGS
]
# ---------------------------------------------------------------------------
# AC_INIT — package_info.
# ---------------------------------------------------------------------------
package_info(
name = "gawk_package_info",
package_name = "GNU Awk",
aliases = {
"PACKAGE": "PACKAGE_TARNAME",
"VERSION": "PACKAGE_VERSION",
},
module_bazel = "MODULE.bazel",
package_bugreport = "bug-gawk@gnu.org",
package_tarname = "gawk",
package_url = "https://www.gnu.org/software/gawk/",
strip_bcr_version = True,
)
# ---------------------------------------------------------------------------
# Per-m4 autoconf targets — inlined into `:configure_ac` below.
#
# Bison's overlay maintains one `autoconf(name = "m4_<stem>")` target per
# upstream m4 file so other gnulib m4 modules can `dep` on whatever check
# each one produces. For gawk that machinery isn't load-bearing: we've
# disabled NLS, libtool, gettext, glibc-specific probes, and z/OS support,
# so the corresponding m4 files (arch, ax_check_compile_flag, glibc2,
# glibc21, intdiv0, intldir, intl, intmax, inttypes-pri, libtool,
# lt~obsolete, ltoptions, ltsugar, ltversion, triplet-transformation,
# noreturn) become no-ops, and the remaining ones (longdouble, signed,
# uintmax_t, wchar_t, socket, pma, mpfr, readline) only ever emit a
# handful of `AC_DEFINE` lines that nothing depends on transitively.
# Inlining them avoids 24 dead targets and a top-level dep list.
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
# Top-level configure.ac translation.
# ---------------------------------------------------------------------------
# AC_CHECK_HEADERS list from configure.ac:196-202 + AC_CHECK_HEADERS_ONCE.
# Plus the standard set autoconf includes via AC_USE_SYSTEM_EXTENSIONS / autoheader.
GAWK_HEADER_PROBES = [
"arpa/inet.h",
"fcntl.h",
"inttypes.h",
"libintl.h",
"locale.h",
"mcheck.h",
"memory.h",
"netdb.h",
"netinet/in.h",
"spawn.h",
"stdbool.h",
"stddef.h",
"stdint.h",
"stdio.h",
"stdlib.h",
"string.h",
"strings.h",
"stropts.h",
"sys/ioctl.h",
"sys/param.h",
"sys/personality.h",
"sys/procctl.h",
"sys/select.h",
"sys/socket.h",
"sys/stat.h",
"sys/sysctl.h",
"sys/time.h",
"sys/types.h",
"sys/wait.h",
"termios.h",
"uchar.h",
"unistd.h",
"wchar.h",
"wctype.h",
]
# AC_CHECK_FUNCS list from configure.ac:318-328.
GAWK_FUNCTION_PROBES = [
"__etoa_l",
"_NSGetExecutablePath",
"atexit",
"btowc",
"c32rtomb",
"clock_gettime",
"fmod",
"fwrite_unlocked",
"gai_strerror",
"getaddrinfo",
"getdtablesize",
"getgrent",
"getgroups",
"gettimeofday",
"grantpt",
"isascii",
"isblank",
"lstat",
"mbrtoc32",
"mtrace",
"personality",
"posix_openpt",
"posix_spawnp",
"procctl",
"setenv",
"setlocale",
"setsid",
"sigprocmask",
"strcasecmp",
"strcoll",
"strftime",
"strncasecmp",
"strsignal",
"sysctl",
"timegm",
"waitpid",
"wctype",
]
autoconf(
name = "configure_ac",
checks = (
# --- Standard header probes (~30 HAVE_*_H) ---
macros.AC_CHECK_HEADERS(GAWK_HEADER_PROBES) +
# --- Standard function probes (~35 HAVE_*) ---
macros.AC_CHECK_FUNCS(GAWK_FUNCTION_PROBES) +
# --- Struct member probes ---
macros.AC_CHECK_MEMBERS(
["struct stat.st_blksize"],
includes = [
"#include <sys/stat.h>",
"#include <sys/types.h>",
],
) + macros.AC_CHECK_MEMBERS(
["struct passwd.pw_passwd"],
includes = [
"#include <pwd.h>",
"#include <sys/types.h>",
],
) + macros.AC_CHECK_MEMBERS(
["struct group.gr_passwd"],
includes = [
"#include <grp.h>",
"#include <sys/types.h>",
],
) + macros.AC_CHECK_MEMBERS(
["struct tm.tm_zone"],
includes = ["#include <time.h>"],
) + [
# `HAVE_TM_ZONE` is the deprecated alias for
# `HAVE_STRUCT_TM_TM_ZONE` — emit it only when the member probe
# above succeeded.
checks.AC_DEFINE(
"HAVE_TM_ZONE",
1,
condition = "ac_cv_member_struct_tm_tm_zone",
),
# --- Type probes (replace baked-in assumptions with real checks) ---
# Upstream `configh.in` only has slots for these four; gawk
# source doesn't reference `HAVE_LONG_DOUBLE` / `HAVE_WCHAR_T`.
checks.AC_CHECK_TYPE(
"long long int",
define = "HAVE_LONG_LONG_INT",
),
checks.AC_CHECK_TYPE(
"unsigned long long int",
define = "HAVE_UNSIGNED_LONG_LONG_INT",
),
checks.AC_CHECK_TYPE(
"intmax_t",
define = "HAVE_INTMAX_T",
includes = ["#include <stdint.h>"],
),
checks.AC_CHECK_TYPE(
"uintmax_t",
define = "HAVE_UINTMAX_T",
includes = ["#include <stdint.h>"],
),
# --- Sizeof probes ---
checks.AC_CHECK_SIZEOF(
"unsigned int",
define = "SIZEOF_UNSIGNED_INT",
),
checks.AC_CHECK_SIZEOF(
"unsigned long",
define = "SIZEOF_UNSIGNED_LONG",
),
checks.AC_CHECK_SIZEOF(
"void *",
define = "SIZEOF_VOID_P",
),
# --- Custom compile probes from configure.ac:231-250 ---
checks.AC_TRY_COMPILE(
name = "gawk_cv_time_t_in_sys_types_h",
code = utils.AC_LANG_PROGRAM(
["#include <sys/types.h>"],
"time_t foo; foo = 0; (void)foo;",
),
define = "TIME_T_IN_SYS_TYPES_H",
),
checks.AC_TRY_COMPILE(
name = "gawk_cv_have_wctype_t",
code = utils.AC_LANG_PROGRAM(
["#include <wctype.h>"],
"wctype_t foo; foo = 0; (void)foo;",
),
define = "HAVE_WCTYPE_T",
),
checks.AC_TRY_COMPILE(
name = "gawk_cv_have_wint_t",
code = utils.AC_LANG_PROGRAM(
["#include <wctype.h>"],
"wint_t foo; foo = 0; (void)foo;",
),
define = "HAVE_WINT_T",
),
checks.AC_TRY_COMPILE(
name = "gawk_cv_have_sockaddr_storage",
code = utils.AC_LANG_PROGRAM(
[
"#include <sys/socket.h>",
"#include <sys/types.h>",
],
"struct sockaddr_storage foo; (void)foo;",
),
define = "HAVE_SOCKADDR_STORAGE",
),
# AC_C_RESTRICT
checks.AC_C_RESTRICT(),
# AC_FUNC_MBRTOWC (rules_cc_autoconf has no dedicated macro; probe directly)
checks.AC_TRY_LINK(
name = "gawk_cv_func_mbrtowc",
code = utils.AC_LANG_PROGRAM(
["#include <wchar.h>"],
"mbstate_t st; mbrtowc(0, \"\", 0, &st);",
),
define = "HAVE_MBRTOWC",
),
# AC_FUNC_GETPGRP probe — accepts `getpgrp()` with zero args
# (the POSIX-2001 form). Old BSD systems took a pid.
checks.AC_TRY_COMPILE(
name = "ac_cv_func_getpgrp_void",
code = utils.AC_LANG_PROGRAM(
["#include <unistd.h>"],
"(void)getpgrp();",
),
define = "GETPGRP_VOID",
),
] + select({
# AC_TYPE_GETGROUPS: POSIX uses gid_t, Windows doesn't ship
# getgroups at all — keeping this as a platform select avoids a
# probe that would otherwise need to compile a known-bad signature
# to discriminate.
"@platforms//os:windows": [checks.AC_DEFINE("GETGROUPS_T", "int")],
"//conditions:default": [checks.AC_DEFINE("GETGROUPS_T", "gid_t")],
}) + [
# AC_USE_SYSTEM_EXTENSIONS proxy. Upstream sets these
# unconditionally on every host (it's gnulib's `m4/extensions.m4`),
# not just glibc. `_GNU_SOURCE` in particular is what makes
# `support/regex.h` set its own `__USE_GNU` (lines 30-33), which
# in turn exposes `struct re_registers` — without it, gawk fails
# to compile against its own vendored regex on macOS as well as
# any other libc.
checks.AC_DEFINE("_GNU_SOURCE", 1),
checks.AC_DEFINE("_ALL_SOURCE", 1),
checks.AC_DEFINE("__EXTENSIONS__", 1),
checks.AC_DEFINE("_POSIX_PTHREAD_SEMANTICS", 1),
checks.AC_DEFINE("_TANDEM_SOURCE", 1),
] + select({
# macOS-specific feature toggle on top of the shared set.
"@platforms//os:macos": [checks.AC_DEFINE("_DARWIN_C_SOURCE", 1)],
"//conditions:default": [],
}) + select({
# Runtime probes (AC_RUN_IFELSE for printf %F / %a). Modern glibc and
# Apple libc support both formats; assume yes on POSIX.
"@platforms//os:windows": [],
"//conditions:default": [
checks.AC_DEFINE("PRINTF_HAS_F_FORMAT", 1),
checks.AC_DEFINE("PRINTF_HAS_A_FORMAT", 1),
],
}) + [
# --- Type fallbacks rules_cc_autoconf doesn't expose macros for ---
# AC_C_VARARRAYS, AC_C_STRINGIZE: universal in C99+ toolchains.
checks.AC_DEFINE("HAVE_C_VARARRAYS", 1),
checks.AC_DEFINE("HAVE_STRINGIZE", 1),
# AC_C_BOOL (gl_C_BOOL): probes the C23 native `bool` keyword. Under
# `-std=gnu11` the keyword is unavailable; leaving HAVE_C_BOOL undef
# makes configh.in fall back to `#include <stdbool.h>` (which our
# header probe sets HAVE_STDBOOL_H=1 for).
# STDC_HEADERS: legacy macro; always emit on hosted environments.
checks.AC_DEFINE("STDC_HEADERS", 1),
# --- Misc ---
# ssize_t exists on POSIX; configh.in falls back to `int` if undefined.
# AC_HEADER_SYS_WAIT: emit HAVE_SYS_WAIT_H via the header probe above.
# socklen_t: leave unset; configh.in has its own `#undef socklen_t` slot.
# AC_SUBST for pkgextensiondir / EXTENSIONDIR — Bazel-controlled at
# runtime via gawk_tool's runfiles layout; no autoconf wiring needed.
# `HAVE_SOCKETS` (m4_socket): mirror upstream `GAWK_AC_LIB_SOCKETS`,
# which gates on `getaddrinfo` availability. Already probed above
# via `AC_CHECK_FUNCS`, so reuse the cache var.
#
# Use `requires=` (not `condition=`) so the macro is either
# `#define HAVE_SOCKETS 1` or absent entirely. With `condition=`
# it would emit `#define HAVE_SOCKETS 0` when the probe failed,
# and gawk source does `#if defined(HAVE_SOCKETS)` (true for any
# defined value) — that would drag `missing_d/getaddrinfo.c`
# into the compile via `replace.c` on toolchains where the
# probe can't link `getaddrinfo` standalone (e.g. MSVC, where
# it lives in ws2_32 that isn't linked at probe time).
checks.AC_DEFINE(
"HAVE_SOCKETS",
1,
requires = ["ac_cv_func_getaddrinfo==1"],
),
] +
# --- Platform / flag-gated defines (formerly separate `m4_*` targets) ---
# `USE_PERSISTENT_MALLOC` (m4_pma): PMA is Linux-only upstream.
#
# We split this into two pieces — an `M4_VARIABLE` that's always
# emitted (so `autoconf_srcs` below can gate `support/pma.c` on it
# at analysis time on every platform) plus a conditional `AC_DEFINE`
# that only emits the actual `#define` when PMA is enabled. Without
# the always-present cache var, `autoconf_srcs` raises an analysis
# error on macOS / Windows complaining that the gate var doesn't
# exist.
select({
":_disable_pma_setting": [checks.M4_VARIABLE("gawk_cv_use_pma", 0)],
"@platforms//os:linux": [checks.M4_VARIABLE("gawk_cv_use_pma", 1)],
"//conditions:default": [checks.M4_VARIABLE("gawk_cv_use_pma", 0)],
}) + [
# `requires=` (not `condition=`) is what GATES whether the
# define is emitted at all. `condition=` would still emit
# `#define USE_PERSISTENT_MALLOC 0` when the gate var is 0,
# and gawk source does `#ifdef USE_PERSISTENT_MALLOC` (true
# for any defined value) — linking would then fail with
# undefined `pma_*` symbols on non-Linux because
# `support/pma.c` isn't built.
checks.AC_DEFINE(
"USE_PERSISTENT_MALLOC",
1,
requires = ["gawk_cv_use_pma==1"],
),
] +
# `HAVE_MPFR` (m4_mpfr): paired with the `:mpfr` label_flag.
select({
":_enable_mpfr_setting": [checks.AC_DEFINE("HAVE_MPFR", 1)],
"//conditions:default": [],
}) +
# `HAVE_LIBREADLINE` (m4_readline): paired with the `:readline` label_flag.
select({
":_enable_readline_setting": [checks.AC_DEFINE("HAVE_LIBREADLINE", 1)],
"//conditions:default": [],
}) +
# --- Boolean flag → define wiring via select() ---
# AC_BUILD_SETTING would render `False`/`True` literally; select() lets
# us emit a real `#define X 1` only when the flag is on.
select({
":_disable_lint_setting": [checks.AC_DEFINE("NO_LINT", 1)],
"//conditions:default": [],
}) +
select({
":_builtin_intdiv0_setting": [checks.AC_DEFINE("SUPPLY_INTDIV", 1)],
"//conditions:default": [],
}) +
select({
":_disable_extensions_setting": [],
# MSVC has no `<dlfcn.h>` and gawk's `pc/` MinGW-only dlopen
# shim uses GCC-isms we can't compile. Force-disable DYNAMIC
# on MSVC regardless of the `:disable_extensions` flag —
# extensions themselves are already gated incompatible with
# MSVC by `gawk_builtin_extension`'s `target_compatible_with`.
"@rules_cc//cc/compiler:msvc-cl": [],
"//conditions:default": [checks.AC_DEFINE("DYNAMIC", 1)],
})
),
deps = [":gawk_package_info"],
)
# ---------------------------------------------------------------------------
# Generate config.h from upstream configh.in.
# ---------------------------------------------------------------------------
autoconf_hdr(
name = "config_h",
# Place under a subdir so the matching `cc_library` can use
# `strip_include_prefix` — bazel forbids `includes = ["."]` when the
# overlay is loaded as the root workspace (BCR presubmit's setup), and
# `includes = ["gawk_config"]` adds the dir to the global include path
# where it would shadow / be shadowed by `config.h` files shipped by
# other modules (e.g. mpfr / gmp ship their own at their package root).
out = "gawk_config/config.h",
template = "configh.in",
deps = [":configure_ac"],
)
# ---------------------------------------------------------------------------
# Conditional sources gated on probe / flag results.
# ---------------------------------------------------------------------------
autoconf_srcs(
name = "gawk_conditional_srcs",
srcs = {
# Gate on the always-emitted `gawk_cv_use_pma` cache var rather
# than the conditionally-emitted `USE_PERSISTENT_MALLOC` define
# — autoconf_srcs evaluates the gate at analysis time before
# the per-platform `select()` for the define is resolved, so a
# gate var that doesn't exist on non-Linux raises an error.
"support/pma.c": "gawk_cv_use_pma",
},
deps = [":configure_ac"],
)
# ---------------------------------------------------------------------------
# cc_library / cc_binary targets.
# ---------------------------------------------------------------------------
# MSVC compatibility shims. Upstream gawk doesn't officially support MSVC,
# but with one targeted patch (`patches/awk_h_msvc_stdc_exempt.patch` —
# exempts `_MSC_VER` from `awk.h`'s `__STDC__` hard-error) plus two shim
# headers, the base interpreter compiles. Both shim headers are real
# `.h` files in the overlay (not `write_file`-generated) for IDE/syntax
# support; see [msvc_shim.h](msvc_shim.h) and
# [msvc_compat/langinfo.h](msvc_compat/langinfo.h) for the details.
cc_library(
name = "_msvc_shim",
hdrs = ["msvc_shim.h"],
visibility = ["//visibility:private"],
)
cc_library(
name = "_msvc_langinfo_stub",
hdrs = ["msvc_compat/langinfo.h"],
strip_include_prefix = "msvc_compat",
visibility = ["//visibility:private"],
)
# MSVC-style frontends (`msvc-cl` and `clang-cl`): use the `/`-style
# flags. `/w` silences all warnings, `/std:c11` enables C11. The shim
# is force-included so it lands before any other `#include` (in
# particular before `gawkapi.h` / `support/regex.h`).
_MSVC_STYLE_COPTS = [
"/w",
"/std:c11",
"/FImsvc_shim.h",
]
# GCC-style frontends (`gcc`, `clang`, `mingw-gcc`, `emscripten`,
# anything else): `-w` silences all warnings; `-std=gnu11` keeps
# clang's relaxed C99/C11 rules so implicit-function-declaration
# stays a warning rather than the hard error clang ≥ 16 emits in
# strict ISO mode (gawk's vendored regex relies on this for
# `_REGEX_NELTS`, conditionally defined via the include chain).
_GCC_STYLE_COPTS = [
"-w",
"-std=gnu11",
]
GAWK_COPTS = select({
"@rules_cc//cc/compiler:clang-cl": _MSVC_STYLE_COPTS,
"@rules_cc//cc/compiler:msvc-cl": _MSVC_STYLE_COPTS,
"//conditions:default": _GCC_STYLE_COPTS,
})
# Deps fragment for targets that pull in the MSVC shim. Add this to the
# `implementation_deps` of every cc_library / cc_binary that compiles
# `awk.h`-touching source on MSVC so `/FI msvc_shim.h` resolves.
MSVC_SHIM_DEPS = select({
"@rules_cc//cc/compiler:msvc-cl": [
":_msvc_shim",
":_msvc_langinfo_stub",
],
"//conditions:default": [],
})
LOCAL_DEFINES = [
"GAWK",
"HAVE_CONFIG_H",
] + select({
# FS-layout defines are OS-level (both MinGW and MSVC builds for Windows
# use the same target paths).
"@platforms//os:windows": [
'LOCALEDIR="\\\"c:/gnu/share/locale\\\""',
'DEFLIBPATH="\\\"c:/gnu/lib/gawk\\\""',
'SHLIBEXT="\\\"dll\\\""',
# `DEFPATH` is referenced from `posix/gawkmisc.c:51`, which MSVC
# falls through to (it has no `__MINGW32__` branch). Without it
# the compile errors out with "DEFPATH undeclared identifier".
'DEFPATH="\\\"c:/gnu/share/awk\\\""',
],
"//conditions:default": [
'LOCALEDIR="\\\"/usr/local/share/locale\\\""',
'DEFLIBPATH="\\\"/usr/local/lib/gawk\\\""',
'SHLIBEXT="\\\"so\\\""',
'DEFPATH="\\\".:/usr/local/share/awk\\\""',
],
}) + select({
# MinGW-specific runtime-library tweak; MSVC has its own stdio formatting.
"@rules_cc//cc/compiler:mingw-gcc": ["__USE_MINGW_ANSI_STDIO=1"],
"//conditions:default": [],
})
# Note: we used to predefine `__STDC__=1` on MSVC to satisfy `awk.h`'s
# hard-error check, but that made MSVC's `<sys/stat.h>` hide its POSIX
# `struct stat` alias and forced a cascade of `#define stat _stat` /
# `S_IF*` aliasing in the shim. `patches/awk_h_msvc_stdc_exempt.patch`
# exempts `_MSC_VER` from the check (mirroring the existing SunPro
# carve-out), so the predefine is no longer needed.
filegroup(
name = "missing_d",
srcs = [
"missing_d/strcoll.c",
"missing_d/strftime.c",
"missing_d/strncasecmp.c",
# `strsignal.c` is textually included by `replace.c` when
# `HAVE_STRSIGNAL` is not defined (true on MSVC; glibc and
# Apple libc both provide it). Listed unconditionally because
# this filegroup is the textual-headers set passed to `:awk`.
"missing_d/strsignal.c",
"missing_d/timegm.c",
],
visibility = ["//visibility:public"],
)
cc_library(
name = "gettext",
hdrs = ["gettext.h"],
visibility = ["//visibility:public"],
)
cc_library(
name = "gawkapi",
hdrs = ["gawkapi.h"],
visibility = ["//visibility:public"],
)
cc_library(
name = "nonposix",
hdrs = ["nonposix.h"],
visibility = ["//:__subpackages__"],
)
cc_library(
name = "custom",
hdrs = ["custom.h"],
visibility = ["//visibility:public"],
)
# Internal — consumers (`:support`, `:awk`, `:gawk`, extensions) wire this in
# via `implementation_deps` and set `HAVE_CONFIG_H` themselves with
# `local_defines`. This prevents `config.h` and its `HAVE_*` macros from
# leaking into transitive consumers (e.g. downstream `cc_binary`s that depend
# on `:awk`).
cc_library(
name = "config",
hdrs = [":config_h"],
# `strip_include_prefix` keeps the header inside a per-library
# `_virtual_includes/config/` directory so it can't be shadowed by
# `config.h` shipped by other modules (mpfr, gmp, ...).
strip_include_prefix = "gawk_config",
visibility = ["//visibility:public"],
deps = [":custom"],
)
cc_library(
name = "support_hdrs",
hdrs = glob([
"support/*.h",
"support/malloc/*.h",
]) + [
"support/malloc/dynarray-skeleton.c",
"support/regcomp.c",
"support/regex_internal.c",
"support/regexec.c",
],
strip_include_prefix = "support",
)
cc_library(
name = "support",
srcs = [
"support/dfa.c",
"support/getopt.c",
"support/getopt1.c",
"support/localeinfo.c",
"support/malloc/dynarray_at_failure.c",
"support/malloc/dynarray_emplace_enlarge.c",
"support/malloc/dynarray_finalize.c",
"support/malloc/dynarray_resize.c",
"support/malloc/dynarray_resize_clear.c",
"support/minrx.c",
"support/random.c",
"support/regex.c",
] + [":gawk_conditional_srcs"],
hdrs = glob([
"support/*.h",
"support/malloc/*.h",
]) + [
"support/malloc/dynarray-skeleton.c",
"support/regcomp.c",
"support/regex_internal.c",
"support/regexec.c",
],
copts = GAWK_COPTS,
implementation_deps = [
":config",
":support_hdrs",
] + MSVC_SHIM_DEPS,
includes = [
"support",
"support/malloc",
],
local_defines = LOCAL_DEFINES,
# `support/minrx.c` textually `#include`s `support/charset.c`; the
# included file must be visible to the compile action.
textual_hdrs = ["support/charset.c"],
deps = [":gettext"],
)
cc_library(
name = "awk",
srcs = glob(
["*.c"],
exclude = ["main.c"],
),
hdrs = glob(["*.h"]) + [":missing_d"],
copts = GAWK_COPTS,
implementation_deps = [":config"] + MSVC_SHIM_DEPS,
includes = ["./support"],
linkopts = select({
"@platforms//os:linux": ["-ldl"],
"@platforms//os:macos": ["-ldl"],
"//conditions:default": [],
}) + select({
# MinGW-only: `-lws2_32` for winsock (`io.c`'s socket paths are
# `__MINGW32__`-gated; MSVC has `HAVE_SOCKETS` disabled and needs
# nothing), plus `-Wl,-allow-multiple-definition` (GNU-ld-only
# papering over multi-def warnings carried from the pre-autoconf
# overlay). Both flags are rejected by MSVC's `link.exe`
# (`LNK4044: unrecognized option`).
"@rules_cc//cc/compiler:mingw-gcc": [
"-lws2_32",
"-Wl,-allow-multiple-definition",
],
"//conditions:default": [],
}),
local_defines = LOCAL_DEFINES,
# gawkmisc.c does `#include "posix/gawkmisc.c"` on POSIX and
# `#include "pc/gawkmisc.pc"` / `#include "pc/mbc32.c"` on MinGW. These
# are textually-included sources from the upstream tarball; bazel needs
# them declared somewhere to make them visible to the compile action.
# The pc/ implementations only compile under MinGW (gawkmisc.c gates on
# `__MINGW32__`); MSVC builds would need separate code paths that
# upstream gawk doesn't provide.
textual_hdrs = ["posix/gawkmisc.c"] + select({
"@rules_cc//cc/compiler:mingw-gcc": glob([
"pc/*.c",
"pc/*.h",
]) + ["pc/gawkmisc.pc"],
"//conditions:default": [],
}),
visibility = ["//visibility:public"],
# `:config` is an `implementation_deps` so `config.h` (and its `HAVE_*`
# macros) stay scoped to `:awk`'s own compilation and don't leak into
# transitive consumers. `awk.h` gates its `#include <config.h>` behind
# `#ifdef HAVE_CONFIG_H` and we only set that as a `local_defines` on
# this library, so downstream `cc_binary`s that depend on `:awk` never
# try to resolve `<config.h>` from their own include path — no chance
# of colliding with a `config.h` shipped by a sibling cc_library.
#
# Caveat: a user who turns on `:enable_mpfr` and points `:mpfr` at a
# provider that itself exposes `<config.h>` at its include root may see
# `<config.h>` resolve to the provider's instead of gawk's during
# `:awk`'s own compilation, because `implementation_deps` come AFTER
# `deps` in the resolved include path. Pick (or wrap) a provider that
# doesn't expose its own `config.h` to fix this on the user side.
#
# `:mpfr` and `:readline` are label_flags. When the matching
# `:enable_<lib>` bool_flag is False (the default) nothing is added;
# when True the user-supplied label is pulled in (or the `#error`
# sentinel cc_library, which fails the compile with a helpful
# message pointing at the flag to set).
deps = [":support"] + select({
":_enable_mpfr_setting": [":mpfr"],
"//conditions:default": [],
}) + select({
":_enable_readline_setting": [":readline"],
"//conditions:default": [],
}),
)
cc_binary(
name = "gawk",
srcs = ["main.c"],
copts = GAWK_COPTS,
local_defines = LOCAL_DEFINES,
visibility = ["//visibility:public"],
# `:config` is needed for `main.c`'s compile (awk.h's
# `#ifdef HAVE_CONFIG_H` arm). `cc_binary` has no `implementation_deps`
# so it lives here; this is the end of the dep chain so nothing
# transitively re-exports config.h.
deps = [
":awk",
":config",
] + MSVC_SHIM_DEPS,
)
# `:gawk` rebuilt under a transition that forces every optional `bool_flag`
# and `label_flag` back to its safe default. Downstream modules that need
# gawk at their own build time (e.g. `ncurses` generating `term.h` with it)
# should depend on this target rather than `:gawk` directly so a user's
# `--//:enable_mpfr=true` (or label override) can't drag MPFR / readline
# into a configuration that can't satisfy them.
gawk_minimal(
name = "gawk_minimal",
visibility = ["//visibility:public"],
)