licenses(["reciprocal"])

load(
    ":mpn.bzl",
    "architecture_includes",
    "config_include_from_architecture",
    "current_directory",
    "file_from_architecture",
    "mparam_path",
    "mpn_cc_library",
    "mpn_m4_cc_library",
)
load("@//tools/build_rules:select.bzl", "address_size_select", "cpu_select")

architecture_paths = {
    "@//tools:cpu_k8": [
        "x86_64",
        "generic",
    ],
    "@//tools:cpu_roborio": [
        "arm/v7a/cora9",
        "arm/v6t2",
        "arm/v6",
        "arm/v5",
        "arm",
        "generic",
    ],
    "@//tools:cpu_armhf": [
        "arm/v7a/cora9",
        "arm/v6t2",
        "arm/v6",
        "arm/v5",
        "arm",
        "generic",
    ],
    "@//tools:cpu_cortex_m4f": [
        "arm",
        "generic",
    ],
    # TODO(phil): Support this properly.
    #"@//tools:cpu_cortex_m4f_k22": [
    #    "arm",
    #    "generic",
    #],
}

# gmp's tools leak memory on purpose. Just skip asan for them.
tool_features = ["-asan"]

genrule(
    name = "gmp_h_copy",
    srcs = file_from_architecture(architecture_paths, "gmp.h"),
    outs = ["gmp.h"],
    cmd = "cp $< $@",
    target_compatible_with = ["@platforms//os:linux"],
)

genrule(
    name = "config_m4_copy",
    srcs = file_from_architecture(architecture_paths, "config.m4"),
    outs = ["config.m4"],
    cmd = "cp $< $@",
    target_compatible_with = ["@platforms//os:linux"],
)

copts_common = [
    "-Wno-error",
    "-Wno-format-nonliteral",
    "-Wno-unused-parameter",
    "-Wno-missing-field-initializers",
    "-DHAVE_CONFIG_H",
    "-I" + current_directory(),
    "-I$(GENDIR)/" + current_directory(),
    "-I" + current_directory() + "/mpn",
    "-I$(GENDIR)/" + current_directory() + "/mpn",
    "-Wno-cast-align",
    "-Wno-dangling-else",
    "-Wno-cast-qual",
    "-Wno-sign-compare",
    "-Wno-unused-function",
    "-Wno-unused-value",
    "-Wno-unknown-warning-option",
    "-Wno-unused-variable",
] + architecture_includes(architecture_paths) + cpu_select({
    "arm": [
        "-Wno-old-style-declaration",
        "-Wno-maybe-uninitialized",
        "-Wno-empty-body",
        "-Wno-unused-but-set-variable",
        "-Wno-implicit-fallthrough",
    ],
    "amd64": [],
}) + config_include_from_architecture(architecture_paths)

ccopts = copts_common + [
    "-D__GMP_WITHIN_GMPXX",
    "-Wno-unused-label",
]

copts = copts_common + [
    "-D__GMP_WITHIN_GMP",
]

cc_library(
    name = "bootstrap",
    target_compatible_with = ["@platforms//os:linux"],
    textual_hdrs = [
        "bootstrap.c",
        "mini-gmp/mini-gmp.c",
        "mini-gmp/mini-gmp.h",
    ],
)

cc_binary(
    name = "gen-fac",
    srcs = ["gen-fac.c"],
    copts = copts,
    features = tool_features,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":bootstrap"],
)

nail_bits = "0"

limb_bits = address_size_select({
    "64": "64",
    "32": "32",
})

genrule(
    name = "fac_table_h",
    outs = ["fac_table.h"],
    cmd = "$(location :gen-fac) " + limb_bits + " " + nail_bits + " > $@",
    target_compatible_with = ["@platforms//os:linux"],
    tools = [":gen-fac"],
)

cc_binary(
    name = "gen-fib",
    srcs = ["gen-fib.c"],
    copts = copts,
    features = tool_features,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":bootstrap"],
)

genrule(
    name = "fib_table_h",
    outs = ["fib_table.h"],
    cmd = "$(location :gen-fib) header " + limb_bits + " " + nail_bits + " > $@",
    target_compatible_with = ["@platforms//os:linux"],
    tools = [":gen-fib"],
)

genrule(
    name = "fib_table_c",
    outs = ["mpn/fib_table.c"],
    cmd = "$(location :gen-fib) table " + limb_bits + " " + nail_bits + " > $@",
    target_compatible_with = ["@platforms//os:linux"],
    tools = [":gen-fib"],
)

cc_binary(
    name = "gen-bases",
    srcs = ["gen-bases.c"],
    copts = copts,
    features = tool_features,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":bootstrap"],
)

genrule(
    name = "mp_bases_h",
    outs = ["mp_bases.h"],
    cmd = "$(location :gen-bases) header " + limb_bits + " " + nail_bits + " > $@",
    target_compatible_with = ["@platforms//os:linux"],
    tools = [":gen-bases"],
)

genrule(
    name = "mp_bases_c",
    outs = ["mpn/mp_bases.c"],
    cmd = "$(location :gen-bases) table " + limb_bits + " " + nail_bits + " > $@",
    target_compatible_with = ["@platforms//os:linux"],
    tools = [":gen-bases"],
)

cc_binary(
    name = "gen-trialdivtab",
    srcs = ["gen-trialdivtab.c"],
    copts = copts,
    features = tool_features,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":bootstrap"],
)

genrule(
    name = "trialdivtab_h",
    outs = ["trialdivtab.h"],
    cmd = "$(location :gen-trialdivtab) " + limb_bits + " 8000 > $@",
    target_compatible_with = ["@platforms//os:linux"],
    tools = [":gen-trialdivtab"],
)

cc_binary(
    name = "gen-jacobitab",
    srcs = ["gen-jacobitab.c"],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":bootstrap"],
)

genrule(
    name = "jacobitab_h",
    outs = ["mpn/jacobitab.h"],
    cmd = "$(location :gen-jacobitab) > $@",
    target_compatible_with = ["@platforms//os:linux"],
    tools = [":gen-jacobitab"],
)

cc_binary(
    name = "gen-psqr",
    srcs = ["gen-psqr.c"],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":bootstrap"],
)

genrule(
    name = "perfsqr_h",
    outs = ["mpn/perfsqr.h"],
    cmd = "$(location :gen-psqr) " + limb_bits + " " + nail_bits + " > $@",
    target_compatible_with = ["@platforms//os:linux"],
    tools = [":gen-psqr"],
)

extra_functions = ["invert_limb_table"]

gmp_mpn_functions_optional = extra_functions + [
    "umul",
    "udiv",
    "invert_limb",
    "sqr_diagonal",
    "sqr_diag_addlsh1",
    "mul_2",
    "mul_3",
    "mul_4",
    "mul_5",
    "mul_6",
    "addmul_2",
    "addmul_3",
    "addmul_4",
    "addmul_5",
    "addmul_6",
    "addmul_7",
    "addmul_8",
    "addlsh1_n",
    "sublsh1_n",
    "rsblsh1_n",
    "rsh1add_n",
    "rsh1sub_n",
    "addlsh2_n",
    "sublsh2_n",
    "rsblsh2_n",
    "addlsh_n",
    "sublsh_n",
    "rsblsh_n",
    "add_n_sub_n",
    "addaddmul_1msb0",
]

gmp_mpn_functions = [
    "add",
    "add_1",
    "add_n",
    "sub",
    "sub_1",
    "sub_n",
    "cnd_add_n",
    "cnd_sub_n",
    "cnd_swap",
    "neg",
    "com",
    "mul_1",
    "addmul_1",
    "submul_1",
    "add_err1_n",
    "add_err2_n",
    "add_err3_n",
    "sub_err1_n",
    "sub_err2_n",
    "sub_err3_n",
    "lshift",
    "rshift",
    "dive_1",
    "diveby3",
    "divis",
    "divrem",
    "divrem_1",
    "divrem_2",
    "fib2_ui",
    "fib2m",
    "mod_1",
    "mod_34lsub1",
    "mode1o",
    # TODO(austin): Why is this not getting included by configure?  It looks like it should...
    #"pre_divrem_1",
    "pre_mod_1",
    "dump",
    "mod_1_1",
    "mod_1_2",
    "mod_1_3",
    "mod_1_4",
    "lshiftc",
    "mul",
    "mul_fft",
    "mul_n",
    "sqr",
    "mul_basecase",
    "sqr_basecase",
    "nussbaumer_mul",
    "mulmid_basecase",
    "toom42_mulmid",
    "mulmid_n",
    "mulmid",
    "random",
    "random2",
    "pow_1",
    "rootrem",
    "sqrtrem",
    "sizeinbase",
    "get_str",
    "set_str",
    "compute_powtab",
    "scan0",
    "scan1",
    "popcount",
    "hamdist",
    "cmp",
    "zero_p",
    "perfsqr",
    "perfpow",
    "strongfibo",
    "gcd_11",
    "gcd_22",
    "gcd_1",
    "gcd",
    "gcdext_1",
    "gcdext",
    "gcd_subdiv_step",
    "gcdext_lehmer",
    "div_q",
    "tdiv_qr",
    "jacbase",
    "jacobi_2",
    "jacobi",
    "get_d",
    "matrix22_mul",
    "matrix22_mul1_inverse_vector",
    "hgcd_matrix",
    "hgcd2",
    "hgcd_step",
    "hgcd_reduce",
    "hgcd",
    "hgcd_appr",
    "hgcd2_jacobi",
    "hgcd_jacobi",
    "mullo_n",
    "mullo_basecase",
    "sqrlo",
    "sqrlo_basecase",
    "toom22_mul",
    "toom32_mul",
    "toom42_mul",
    "toom52_mul",
    "toom62_mul",
    "toom33_mul",
    "toom43_mul",
    "toom53_mul",
    "toom54_mul",
    "toom63_mul",
    "toom44_mul",
    "toom6h_mul",
    "toom6_sqr",
    "toom8h_mul",
    "toom8_sqr",
    "toom_couple_handling",
    "toom2_sqr",
    "toom3_sqr",
    "toom4_sqr",
    "toom_eval_dgr3_pm1",
    "toom_eval_dgr3_pm2",
    "toom_eval_pm1",
    "toom_eval_pm2",
    "toom_eval_pm2exp",
    "toom_eval_pm2rexp",
    "toom_interpolate_5pts",
    "toom_interpolate_6pts",
    "toom_interpolate_7pts",
    "toom_interpolate_8pts",
    "toom_interpolate_12pts",
    "toom_interpolate_16pts",
    "invertappr",
    "invert",
    "binvert",
    "mulmod_bnm1",
    "sqrmod_bnm1",
    "div_qr_1",
    "div_qr_1n_pi1",
    "div_qr_2",
    "div_qr_2n_pi1",
    "div_qr_2u_pi1",
    "sbpi1_div_q",
    "sbpi1_div_qr",
    "sbpi1_divappr_q",
    "dcpi1_div_q",
    "dcpi1_div_qr",
    "dcpi1_divappr_q",
    "mu_div_qr",
    "mu_divappr_q",
    "mu_div_q",
    "bdiv_q_1",
    "sbpi1_bdiv_q",
    "sbpi1_bdiv_qr",
    "sbpi1_bdiv_r",
    "dcpi1_bdiv_q",
    "dcpi1_bdiv_qr",
    "mu_bdiv_q",
    "mu_bdiv_qr",
    "bdiv_q",
    "bdiv_qr",
    "broot",
    "brootinv",
    "bsqrt",
    "bsqrtinv",
    "divexact",
    "bdiv_dbm1c",
    "redc_1",
    "redc_2",
    "redc_n",
    "powm",
    "powlo",
    "sec_powm",
    "sec_mul",
    "sec_sqr",
    "sec_div_qr",
    "sec_div_r",
    "sec_pi1_div_qr",
    "sec_pi1_div_r",
    "sec_add_1",
    "sec_sub_1",
    "sec_invert",
    "trialdiv",
    "remove",
    "and_n",
    "andn_n",
    "nand_n",
    "ior_n",
    "iorn_n",
    "nior_n",
    "xor_n",
    "xnor_n",
    "copyi",
    "copyd",
    "zero",
    "sec_tabselect",
    "comb_tables",
] + gmp_mpn_functions_optional

[
    mpn_m4_cc_library(
        name = x,
        architecture_paths = architecture_paths,
        target_compatible_with = ["@platforms//os:linux"],
    )
    for x in gmp_mpn_functions
]

cc_library(
    name = "mpn_core",
    srcs = gmp_mpn_functions + [
        "assert.c",
        "compat.c",
        "errno.c",
        "extract-dbl.c",
        "invalid.c",
        "memory.c",
        "mp_bpl.c",
        "mp_clz_tab.c",
        "mp_dv_tab.c",
        "mp_get_fns.c",
        "mp_minv_tab.c",
        "mp_set_fns.c",
        "nextprime.c",
        "primesieve.c",
        "tal-reent.c",
        "version.c",
    ],
    hdrs = [
        "gmp.h",
        "gmp-impl.h",
        "fac_table.h",
        "mp_bases.h",
        "fib_table.h",
        "longlong.h",
        "trialdivtab.h",
        "mpn/perfsqr.h",
        "mpn/jacobitab.h",
        "gmpxx.h",
    ] + mparam_path(architecture_paths) + file_from_architecture(architecture_paths, "config.h"),
    copts = copts + [
        "-Wno-unused-command-line-argument",
        "-Wa,--noexecstack",
    ],
    target_compatible_with = ["@platforms//os:linux"],
)

# TODO(austin): Can we run these through the mpn_m4_cc_library and get operation baked in without work?
mpn_cc_library(
    name = "fib_table",
    srcs = [
        "mpn/fib_table.c",
    ],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":mpn_core"],
)

mpn_cc_library(
    name = "mp_bases",
    srcs = [
        "mpn/mp_bases.c",
    ],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":mpn_core"],
)

cc_library(
    name = "mpn",
    target_compatible_with = ["@platforms//os:linux"],
    deps = [
        ":fib_table",
        ":mp_bases",
        ":mpn_core",
    ],
)

cc_library(
    name = "mpz",
    srcs = [
        "mpz/2fac_ui.c",
        "mpz/abs.c",
        "mpz/add.c",
        "mpz/add_ui.c",
        "mpz/and.c",
        "mpz/aors.h",
        "mpz/aors_ui.h",
        "mpz/aorsmul.c",
        "mpz/aorsmul_i.c",
        "mpz/array_init.c",
        "mpz/bin_ui.c",
        "mpz/bin_uiui.c",
        "mpz/cdiv_q.c",
        "mpz/cdiv_q_ui.c",
        "mpz/cdiv_qr.c",
        "mpz/cdiv_qr_ui.c",
        "mpz/cdiv_r.c",
        "mpz/cdiv_r_ui.c",
        "mpz/cdiv_ui.c",
        "mpz/cfdiv_q_2exp.c",
        "mpz/cfdiv_r_2exp.c",
        "mpz/clear.c",
        "mpz/clears.c",
        "mpz/clrbit.c",
        "mpz/cmp.c",
        "mpz/cmp_d.c",
        "mpz/cmp_si.c",
        "mpz/cmp_ui.c",
        "mpz/cmpabs.c",
        "mpz/cmpabs_d.c",
        "mpz/cmpabs_ui.c",
        "mpz/com.c",
        "mpz/combit.c",
        "mpz/cong.c",
        "mpz/cong_2exp.c",
        "mpz/cong_ui.c",
        "mpz/dive_ui.c",
        "mpz/divegcd.c",
        "mpz/divexact.c",
        "mpz/divis.c",
        "mpz/divis_2exp.c",
        "mpz/divis_ui.c",
        "mpz/dump.c",
        "mpz/export.c",
        "mpz/fac_ui.c",
        "mpz/fdiv_q.c",
        "mpz/fdiv_q_ui.c",
        "mpz/fdiv_qr.c",
        "mpz/fdiv_qr_ui.c",
        "mpz/fdiv_r.c",
        "mpz/fdiv_r_ui.c",
        "mpz/fdiv_ui.c",
        "mpz/fib2_ui.c",
        "mpz/fib_ui.c",
        "mpz/fits_s.h",
        "mpz/fits_sint.c",
        "mpz/fits_slong.c",
        "mpz/fits_sshort.c",
        "mpz/fits_uint.c",
        "mpz/fits_ulong.c",
        "mpz/fits_ushort.c",
        "mpz/gcd.c",
        "mpz/gcd_ui.c",
        "mpz/gcdext.c",
        "mpz/get_d.c",
        "mpz/get_d_2exp.c",
        "mpz/get_si.c",
        "mpz/get_str.c",
        "mpz/get_ui.c",
        "mpz/getlimbn.c",
        "mpz/hamdist.c",
        "mpz/import.c",
        "mpz/init.c",
        "mpz/init2.c",
        "mpz/inits.c",
        "mpz/inp_raw.c",
        "mpz/inp_str.c",
        "mpz/invert.c",
        "mpz/ior.c",
        "mpz/iset.c",
        "mpz/iset_d.c",
        "mpz/iset_si.c",
        "mpz/iset_str.c",
        "mpz/iset_ui.c",
        "mpz/jacobi.c",
        "mpz/kronsz.c",
        "mpz/kronuz.c",
        "mpz/kronzs.c",
        "mpz/kronzu.c",
        "mpz/lcm.c",
        "mpz/lcm_ui.c",
        "mpz/limbs_finish.c",
        "mpz/limbs_modify.c",
        "mpz/limbs_read.c",
        "mpz/limbs_write.c",
        "mpz/lucmod.c",
        "mpz/lucnum2_ui.c",
        "mpz/lucnum_ui.c",
        "mpz/mfac_uiui.c",
        "mpz/millerrabin.c",
        "mpz/mod.c",
        "mpz/mul.c",
        "mpz/mul_2exp.c",
        "mpz/mul_i.h",
        "mpz/mul_si.c",
        "mpz/mul_ui.c",
        "mpz/n_pow_ui.c",
        "mpz/neg.c",
        "mpz/nextprime.c",
        "mpz/oddfac_1.c",
        "mpz/out_raw.c",
        "mpz/out_str.c",
        "mpz/perfpow.c",
        "mpz/perfsqr.c",
        "mpz/popcount.c",
        "mpz/pow_ui.c",
        "mpz/powm.c",
        "mpz/powm_sec.c",
        "mpz/powm_ui.c",
        "mpz/pprime_p.c",
        "mpz/primorial_ui.c",
        "mpz/prodlimbs.c",
        "mpz/random.c",
        "mpz/random2.c",
        "mpz/realloc.c",
        "mpz/realloc2.c",
        "mpz/remove.c",
        "mpz/roinit_n.c",
        "mpz/root.c",
        "mpz/rootrem.c",
        "mpz/rrandomb.c",
        "mpz/scan0.c",
        "mpz/scan1.c",
        "mpz/set.c",
        "mpz/set_d.c",
        "mpz/set_f.c",
        "mpz/set_q.c",
        "mpz/set_si.c",
        "mpz/set_str.c",
        "mpz/set_ui.c",
        "mpz/setbit.c",
        "mpz/size.c",
        "mpz/sizeinbase.c",
        "mpz/sqrt.c",
        "mpz/sqrtrem.c",
        "mpz/stronglucas.c",
        "mpz/sub.c",
        "mpz/sub_ui.c",
        "mpz/swap.c",
        "mpz/tdiv_q.c",
        "mpz/tdiv_q_2exp.c",
        "mpz/tdiv_q_ui.c",
        "mpz/tdiv_qr.c",
        "mpz/tdiv_qr_ui.c",
        "mpz/tdiv_r.c",
        "mpz/tdiv_r_2exp.c",
        "mpz/tdiv_r_ui.c",
        "mpz/tdiv_ui.c",
        "mpz/tstbit.c",
        "mpz/ui_pow_ui.c",
        "mpz/ui_sub.c",
        "mpz/urandomb.c",
        "mpz/urandomm.c",
        "mpz/xor.c",
    ],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [
        ":mpn",
    ],
)

cc_library(
    name = "mpq",
    srcs = [
        "mpq/abs.c",
        "mpq/aors.c",
        "mpq/canonicalize.c",
        "mpq/clear.c",
        "mpq/clears.c",
        "mpq/cmp.c",
        "mpq/cmp_si.c",
        "mpq/cmp_ui.c",
        "mpq/div.c",
        "mpq/equal.c",
        "mpq/get_d.c",
        "mpq/get_den.c",
        "mpq/get_num.c",
        "mpq/get_str.c",
        "mpq/init.c",
        "mpq/inits.c",
        "mpq/inp_str.c",
        "mpq/inv.c",
        "mpq/md_2exp.c",
        "mpq/mul.c",
        "mpq/neg.c",
        "mpq/out_str.c",
        "mpq/set.c",
        "mpq/set_d.c",
        "mpq/set_den.c",
        "mpq/set_f.c",
        "mpq/set_num.c",
        "mpq/set_si.c",
        "mpq/set_str.c",
        "mpq/set_ui.c",
        "mpq/set_z.c",
        "mpq/swap.c",
    ],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [
        ":mpn",
    ],
)

cc_library(
    name = "mpf",
    srcs = [
        "mpf/abs.c",
        "mpf/add.c",
        "mpf/add_ui.c",
        "mpf/ceilfloor.c",
        "mpf/clear.c",
        "mpf/clears.c",
        "mpf/cmp.c",
        "mpf/cmp_d.c",
        "mpf/cmp_si.c",
        "mpf/cmp_ui.c",
        "mpf/cmp_z.c",
        "mpf/div.c",
        "mpf/div_2exp.c",
        "mpf/div_ui.c",
        "mpf/dump.c",
        "mpf/eq.c",
        "mpf/fits_s.h",
        "mpf/fits_sint.c",
        "mpf/fits_slong.c",
        "mpf/fits_sshort.c",
        "mpf/fits_u.h",
        "mpf/fits_uint.c",
        "mpf/fits_ulong.c",
        "mpf/fits_ushort.c",
        "mpf/get_d.c",
        "mpf/get_d_2exp.c",
        "mpf/get_dfl_prec.c",
        "mpf/get_prc.c",
        "mpf/get_si.c",
        "mpf/get_str.c",
        "mpf/get_ui.c",
        "mpf/init.c",
        "mpf/init2.c",
        "mpf/inits.c",
        "mpf/inp_str.c",
        "mpf/int_p.c",
        "mpf/iset.c",
        "mpf/iset_d.c",
        "mpf/iset_si.c",
        "mpf/iset_str.c",
        "mpf/iset_ui.c",
        "mpf/mul.c",
        "mpf/mul_2exp.c",
        "mpf/mul_ui.c",
        "mpf/neg.c",
        "mpf/out_str.c",
        "mpf/pow_ui.c",
        "mpf/random2.c",
        "mpf/reldiff.c",
        "mpf/set.c",
        "mpf/set_d.c",
        "mpf/set_dfl_prec.c",
        "mpf/set_prc.c",
        "mpf/set_prc_raw.c",
        "mpf/set_q.c",
        "mpf/set_si.c",
        "mpf/set_str.c",
        "mpf/set_ui.c",
        "mpf/set_z.c",
        "mpf/size.c",
        "mpf/sqrt.c",
        "mpf/sqrt_ui.c",
        "mpf/sub.c",
        "mpf/sub_ui.c",
        "mpf/swap.c",
        "mpf/trunc.c",
        "mpf/ui_div.c",
        "mpf/ui_sub.c",
        "mpf/urandomb.c",
    ],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [
        ":mpn",
    ],
)

cc_library(
    name = "printf",
    srcs = [
        "printf/asprintf.c",
        "printf/asprntffuns.c",
        "printf/doprnt.c",
        "printf/doprntf.c",
        "printf/doprnti.c",
        "printf/fprintf.c",
        "printf/obprintf.c",
        "printf/obprntffuns.c",
        "printf/obvprintf.c",
        "printf/printf.c",
        "printf/printffuns.c",
        "printf/repl-vsnprintf.c",
        "printf/snprintf.c",
        "printf/snprntffuns.c",
        "printf/sprintf.c",
        "printf/sprintffuns.c",
        "printf/vasprintf.c",
        "printf/vfprintf.c",
        "printf/vprintf.c",
        "printf/vsnprintf.c",
        "printf/vsprintf.c",
    ],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [
        ":mpn",
    ],
)

cc_library(
    name = "scanf",
    srcs = [
        "scanf/doscan.c",
        "scanf/fscanf.c",
        "scanf/fscanffuns.c",
        "scanf/scanf.c",
        "scanf/sscanf.c",
        "scanf/sscanffuns.c",
        "scanf/vfscanf.c",
        "scanf/vscanf.c",
        "scanf/vsscanf.c",
    ],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [
        ":mpn",
    ],
)

cc_library(
    name = "rand",
    srcs = [
        "rand/rand.c",
        "rand/randbui.c",
        "rand/randclr.c",
        "rand/randdef.c",
        "rand/randiset.c",
        "rand/randlc2s.c",
        "rand/randlc2x.c",
        "rand/randmt.c",
        "rand/randmt.h",
        "rand/randmts.c",
        "rand/randmui.c",
        "rand/rands.c",
        "rand/randsd.c",
        "rand/randsdui.c",
    ],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [
        ":mpn",
    ],
)

cc_library(
    name = "cxx",
    srcs = [
        "cxx/isfuns.cc",
        "cxx/ismpf.cc",
        "cxx/ismpq.cc",
        "cxx/ismpz.cc",
        "cxx/ismpznw.cc",
        "cxx/limits.cc",
        "cxx/osdoprnti.cc",
        "cxx/osfuns.cc",
        "cxx/osmpf.cc",
        "cxx/osmpq.cc",
        "cxx/osmpz.cc",
    ],
    copts = ccopts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [
        ":mpn",
    ],
)

cc_library(
    name = "gmp",
    includes = ["."],
    target_compatible_with = ["@platforms//os:linux"],
    visibility = ["//visibility:public"],
    deps = [
        ":cxx",
        ":mpf",
        ":mpn",
        ":mpq",
        ":mpz",
        ":printf",
        ":rand",
        ":scanf",
    ],
)

genrule(
    name = "call_m4",
    srcs = glob([
        "**/*.m4",
        "**/*.asm",
    ]) + ["config.m4"],
    outs = ["tests/call.s"],
    cmd = "ROOT=$$(pwd); cd ./" + current_directory() + "/tests; LD_LIBRARY_PATH=$${ROOT}/external/m4_v1.4.18/usr/lib/x86_64-linux-gnu/ $${ROOT}/$(location @m4_v1.4.18//:bin) -I $${ROOT}/$(GENDIR)/" + current_directory() + "/tests -DHAVE_CONFIG_H -DPIC " + cpu_select({
              "arm": "arm32call.asm",
              "amd64": "amd64call.asm",
          }) +
          " > $${ROOT}/$@",
    target_compatible_with = ["@platforms//os:linux"],
    tools = [
        "@m4_v1.4.18//:bin",
        "@m4_v1.4.18//:lib",
    ],
)

cc_library(
    name = "testlib",
    srcs =
        cpu_select({
            "arm": ["tests/arm32check.c"],
            "amd64": [
                "tests/amd64check.c",
            ],
        }) + [
            "tests/memory.c",
            "tests/misc.c",
            "tests/refmpf.c",
            "tests/refmpn.c",
            "tests/refmpq.c",
            "tests/refmpz.c",
            "tests/spinner.c",
            "tests/trace.c",
            ":call_m4",
        ],
    hdrs = [
        "tests/cxx/t-ops2.h",
        "tests/mpn/toom-shared.h",
        "tests/mpn/toom-sqr-shared.h",
        "tests/tests.h",
    ],
    copts = copts + ["-Wno-unused-command-line-argument"],
    includes = [
        ".",
        "tests",
    ] + ["mpn/" + p for p in architecture_paths],
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":gmp"],
)

[cc_test(
    name = "tests/" + x,
    srcs = ["tests/" + x + ".c"],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":testlib"],
) for x in [
    "t-bswap",
    "t-constants",
    "t-count_zeros",
    "t-hightomask",
    "t-modlinv",
    "t-popc",
    "t-parity",
    "t-sub",
]]

[cc_test(
    name = "tests/mpn/" + x,
    srcs = ["tests/mpn/" + x + ".c"],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":testlib"],
) for x in [
    "t-asmtype",
    "t-aors_1",
    "t-divrem_1",
    "t-mod_1",
    "t-fat",
    "t-get_d",
    "t-instrument",
    "t-iord_u",
    "t-mp_bases",
    "t-perfsqr",
    "t-scan",
    "logic",
    "t-toom22",
    "t-toom32",
    "t-toom33",
    "t-toom42",
    "t-toom43",
    "t-toom44",
    "t-toom52",
    "t-toom53",
    "t-toom54",
    "t-toom62",
    "t-toom63",
    "t-toom6h",
    "t-toom8h",
    "t-toom2-sqr",
    "t-toom3-sqr",
    "t-toom4-sqr",
    "t-toom6-sqr",
    "t-toom8-sqr",
    "t-div",
    "t-mul",
    "t-mullo",
    "t-sqrlo",
    "t-mulmod_bnm1",
    "t-sqrmod_bnm1",
    "t-mulmid",
    "t-hgcd",
    "t-hgcd_appr",
    "t-matrix22",
    "t-invert",
    "t-bdiv",
    "t-fib2m",
    "t-broot",
    "t-brootinv",
    "t-minvert",
    "t-sizeinbase",
    "t-gcd_11",
    "t-gcd_22",
    "t-gcdext_1",
]]

[cc_test(
    name = "tests/mpz/" + x,
    srcs = ["tests/mpz/" + x + ".c"],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":testlib"],
) for x in [
    "reuse",
    "t-addsub",
    "t-cmp",
    "t-mul",
    "t-mul_i",
    "t-tdiv",
    "t-tdiv_ui",
    "t-fdiv",
    "t-fdiv_ui",
    "t-cdiv_ui",
    "t-gcd",
    "t-gcd_ui",
    "t-lcm",
    "t-invert",
    "dive",
    "dive_ui",
    "t-sqrtrem",
    "convert",
    "io",
    "t-inp_str",
    "logic",
    "bit",
    "t-powm",
    "t-powm_ui",
    "t-pow",
    "t-div_2exp",
    "t-root",
    "t-perfsqr",
    "t-perfpow",
    "t-jac",
    "t-bin",
    "t-get_d",
    "t-get_d_2exp",
    "t-get_si",
    "t-set_d",
    "t-set_si",
    "t-lucm",
    "t-fac_ui",
    "t-mfac_uiui",
    "t-primorial_ui",
    "t-fib_ui",
    "t-lucnum_ui",
    "t-scan",
    "t-fits",
    "t-divis",
    "t-divis_2exp",
    "t-cong",
    "t-cong_2exp",
    "t-sizeinbase",
    "t-set_str",
    "t-aorsmul",
    "t-cmp_d",
    "t-cmp_si",
    "t-hamdist",
    "t-oddeven",
    "t-popcount",
    "t-set_f",
    "t-io_raw",
    "t-import",
    "t-export",
    "t-pprime_p",
    "t-nextprime",
    "t-remove",
    "t-limbs",
]]

[cc_test(
    name = "tests/mpq/" + x,
    srcs = ["tests/mpq/" + x + ".c"],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":testlib"],
) for x in [
    "t-aors",
    "t-cmp",
    "t-cmp_ui",
    "t-cmp_si",
    "t-equal",
    "t-get_d",
    "t-get_str",
    "t-inp_str",
    "t-inv",
    "t-md_2exp",
    "t-set_f",
    "t-set_str",
    "io",
    "reuse",
    "t-cmp_z",
]]

[cc_test(
    name = "tests/mpf/" + x,
    srcs = ["tests/mpf/" + x + ".c"],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":testlib"],
) for x in [
    "t-dm2exp",
    "t-conv",
    "t-add",
    "t-sub",
    "t-sqrt",
    "t-sqrt_ui",
    "t-muldiv",
    "reuse",
    "t-cmp_d",
    "t-cmp_si",
    "t-div",
    "t-fits",
    "t-get_d",
    "t-get_d_2exp",
    "t-get_si",
    "t-get_ui",
    "t-gsprec",
    "t-inp_str",
    "t-int_p",
    "t-mul_ui",
    "t-set",
    "t-set_q",
    "t-set_si",
    "t-set_ui",
    "t-trunc",
    "t-ui_div",
    "t-eq",
    "t-pow_ui",
]]

[cc_test(
    name = "tests/rand/" + x,
    srcs = ["tests/rand/" + x + ".c"],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":testlib"],
) for x in [
    "t-iset",
    "t-lc2exp",
    "t-mt",
    "t-rand",
    "t-urbui",
    "t-urmui",
    "t-urndmm",
]]

[cc_test(
    name = "tests/misc/" + x,
    srcs = ["tests/misc/" + x + ".c"],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":testlib"],
) for x in [
    "t-printf",
    "t-scanf",
    "t-locale",
]]

[cc_test(
    name = "tests/cxx/" + x,
    srcs = ["tests/cxx/" + x + ".cc"],
    copts = copts,
    target_compatible_with = ["@platforms//os:linux"],
    deps = [":testlib"],
) for x in [
    "t-binary",
    "t-cast",
    "t-cxx11",
    "t-headers",
    "t-iostream",
    "t-istream",
    "t-locale",
    "t-misc",
    "t-mix",
    "t-ops",
    "t-ops2qf",
    "t-ops2f",
    "t-ops3",
    "t-ostream",
    "t-prec",
    "t-ternary",
    "t-unary",
    "t-do-exceptions-work-at-all-with-this-compiler",
    "t-ops2z",
    "t-assign",
    "t-constr",
    "t-rand",
]]
