/* * ***************************************************************************** * * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018-2025 Gavin D. Howard and contributors. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * ***************************************************************************** * * The build script file. * */ if OS == "Windows" && bool(config["lto"]) { error("Link-time optimization is not supported on Windows"); } if LIBRARY_ENABLED == "0" { if OS != "Windows" && NLS_ENABLED != "0" { io.eprint("Testing NLS...\n"); clang_flags: []str = if CC contains "clang" { @[ "-Wno_unreachable-code" ]; }; flags: []str = clang_flags +~ @[ DEFOPT +~ "BC_ENABLE_NLS=1", DEFOPT +~ "BC_ENABLED=" +~ BC_ENABLED, DEFOPT +~ "DC_ENABLED=" +~ DC_ENABLED, DEFOPT +~ "BC_ENABLE_HISTORY=0", DEFOPT +~ "BC_ENABLE_LIBRARY=0", DEFOPT +~ "BC_ENABLE_AFL=0", DEFOPT +~ "BC_ENABLE_EXTRA_MATH=" +~ EXTRA_MATH_ENABLED, DEFOPT +~ "BC_ENABLE_OSSFUZZ=0", DEFOPT +~ "_POSIX_C_SOURCE=200809L", DEFOPT +~ "_XOPEN_SOURCE=700", INCOPT, ]; res := $ $CC %(flags) -c @(path.join(src_dir, "src/vm.c")) -E; if res.exitcode != 0 { if FORCE { io.eprint("Forcing NLS...\n"); } else { error("NLS does not work\n"); } } else { if path.isfile("vm.o") { path.rm("vm.o"); } io.eprint("NLS works.\n\n"); io.eprint("Testing gencat...\n"); res2 := $ gencat ./en_US.cat @(path.join(src_dir, "locales/en_US.msg")); if res2.exitcode != 0 { if FORCE { io.eprint("Forcing NLS...\n"); } else { error("gencat does not work\n"); } } else { io.eprint("gencat works.\n\n"); if platform != host { error("Cross compiles will not work!\n\n"); } } } } if OS != "Windows" && sym(config["history"]) != @none { io.eprint("Testing history...\n"); flags: []str = @[ DEFOPT +~ "BC_ENABLE_HISTORY=1", DEFOPT +~ "BC_ENABLED=" +~ BC_ENABLED, DEFOPT +~ "DC_ENABLED=" +~ DC_ENABLED, DEFOPT +~ "BC_ENABLE_NLS=" +~ NLS_ENABLED, DEFOPT +~ "BC_ENABLE_LIBRARY=0", DEFOPT +~ "BC_ENABLE_AFL=0", DEFOPT +~ "BC_ENABLE_EDITLINE=" +~ EDITLINE_ENABLED, DEFOPT +~ "BC_ENABLE_READLINE=" +~ READLINE_ENABLED, DEFOPT +~ "BC_ENABLE_EXTRA_MATH=" +~ EXTRA_MATH_ENABLED, DEFOPT +~ "BC_ENABLE_OSSFUZZ=0", DEFOPT +~ "_POSIX_C_SOURCE=200809L", DEFOPT +~ "_XOPEN_SOURCE=700", INCOPT, ]; res := $ $CC %(flags) -c @(path.join(src_dir, "src/history.c")) -E; if res.exitcode != 0 { if FORCE { io.eprint("Forcing history...\n"); } else { error("History does not work\n"); } } else { if path.isfile("history.o") { path.rm("history.o"); } io.eprint("History works.\n\n"); } } } freebsd_flags: []str = if OS != "FreeBSD" { @[ DEFOPT +~ "_POSIX_C_SOURCE=200809L", DEFOPT +~ "_XOPEN_SOURCE=700" ]; }; macos: bool = (OS == "Darwin"); macos_flags: []str = if macos { @[ DEFOPT +~ "_DARWIN_C_SOURCE" ]; }; openbsd_flags: []str = if OS == "OpenBSD" { if READLINE_ENABLED != "0" { error("Cannot use readline on OpenBSD"); } @[ DEFOPT +~ "_BSD_SOURCE" ]; }; strip_flag: []str = if OS != "Windows" && !bool(config["debug"]) && !macos && bool(config["strip"]) { @[ "-s" ]; }; lto_flag: []str = if bool(config["lto"]) { @[ "-flto" ]; }; strict_flags: []str = if bool(config["strict"]) { // Strict build only works for GCC and Clang, so we do want to set that // here. if CC contains "gcc" || CC contains "clang" { // These are the standard strict build flags for both compilers. std_strict: []str = @[ "-Wall", "-Wextra", "-Werror", "-pedantic" ]; // Clang has -Weverything, which I ensure Yc builds under. // // I also want unlimited errors because Clang is my development // compiler; it caps at 20 by default. compiler_strict: []str = if CC contains "clang" { // Oh, and add the standard. @[ "-Weverything", "-ferror-limit=100000", "-Wno-padded", "-Wno-unknown-warning-option", "-Wno-unsafe-buffer-usage", "-Wno-documentation-unknown-command", "-Wno-pre-c11-compat", "-Wno-enum-enum-conversion", "-Wno-switch-default" ]; }; // Return the combination of the sets. std_strict +~ compiler_strict; } else if OS == "Windows" { // Return the combo of the strict options, the standard, and the // sanitizer defines. @[ "/W4", "/WX", "/wd\"4996\"", "/permissive-" ]; } }; version_contents: str = io.read_file(path.join(src_dir, "VERSION.txt")); version_lines: []str = version_contents.split("\n"); version: str = version_lines[0]; version_flag: []str = @[ DEFOPT +~ "VERSION=" +~ version ]; other_flags: []str = freebsd_flags +~ macos_flags +~ openbsd_flags +~ lto_flag +~ strict_flags +~ version_flag +~ if bool(config["debug"]) { @[ compiler_db["opt.debug"] ]; }; history_files: []str = if HISTORY != @none { HISTORY_C_FILES; }; c_files: []str = if BUILD_MODE == @both { COMMON_C_FILES +~ EXEC_C_FILES +~ BC_C_FILES +~ DC_C_FILES +~ history_files; } else if BUILD_MODE == @bc { COMMON_C_FILES +~ EXEC_C_FILES +~ BC_C_FILES +~ history_files; } else if BUILD_MODE == @dc { COMMON_C_FILES +~ EXEC_C_FILES +~ DC_C_FILES +~ history_files; } else { COMMON_C_FILES +~ LIBRARY_C_FILES; }; build_config: Gaml = @(gaml){ other_cflags: $other_flags strip_flag: $strip_flag }; targets: []str = push build_config: config_stack { gen_o_files: []str = if BUILD_MODE != @library { @[ txt2o("gen/lib.bc", "bc_lib", "bc_lib_name", "BC_ENABLED", true), txt2o("gen/lib2.bc", "bc_lib2", "bc_lib2_name", "BC_ENABLED && BC_ENABLE_EXTRA_MATH", true), txt2o("gen/bc_help.txt", "bc_help", "", "BC_ENABLED", false), txt2o("gen/dc_help.txt", "dc_help", "", "DC_ENABLED", false), ]; }; obj_files: []str = gen_o_files +~ for f: c_files { c2o(f); }; if BUILD_MODE == @both || BUILD_MODE == @bc { if OS != "Windows" && bool(config["install_manpages"]) { src: str = path.join("manuals/bc", BUILD_TYPE +~ ".1"); target BC_MANPAGE: src { $ cp -f @(file_dep) @(tgt); } } exe(BC_BIN, obj_files); } if BUILD_MODE == @both || BUILD_MODE == @dc { if OS != "Windows" && bool(config["install_manpages"]) { src: str = path.join("manuals/dc", BUILD_TYPE +~ ".1"); target DC_MANPAGE: src { $ cp -f @(file_dep) @(tgt); } } if BUILD_MODE == @both { ln(DC_BIN, BC_BIN); } else { exe(DC_BIN, obj_files); } } if BUILD_MODE == @library { lib(LIBRARY, obj_files); } if BUILD_MODE == @both { @[ BC_BIN, DC_BIN ]; } else if BUILD_MODE == @bc { @[ DC_BIN ]; } else if BUILD_MODE == @dc { @[ DC_BIN ]; } else { includedir: str = get_includedir(); libdir: str = get_libdir(); pc_config: Gaml = @(gaml){ INCLUDEDIR: $includedir LIBDIR: $libdir VERSION: $version }; push pc_config: config_stack { target PC_FILE: PC_FILE +~ ".in" { configure_file(file_dep, tgt, "%%"); } } @[ LIBRARY, PC_FILE ]; } }; if OS != "Windows" { if LIBRARY_ENABLED == "0" { target @install: targets { bindir: str = get_bindir(); if BC_ENABLED != "0" { $ $SAFE_INSTALL $EXEC_INSTALL_MODE $BC_BIN @(path.join(bindir, BC_BIN)); } if DC_ENABLED != "0" { if BC_ENABLED != "0" { $ ln -sf @("./" +~ BC_BIN) @(path.join(bindir, DC_BIN)); } else { $ $SAFE_INSTALL $EXEC_INSTALL_MODE $BC_BIN @(path.join(bindir, BC_BIN)); } } if NLS_ENABLED != "0" { locale_install_args: []str = if sym(config["locales"]) == @all { @[ "-l" ]; }; if DESTDIR != "" { $ @(path.join(src_dir, "scripts/locale_install.sh")) %(locale_install_args) @(str(config["nlspath"])) $MAINEXEC $DESTDIR; } else { $ @(path.join(src_dir, "scripts/locale_install.sh")) %(locale_install_args) @(str(config["nlspath"])) $MAINEXEC; } } if bool(config["install_manpages"]) { man1dir: str = get_man1dir(); if BC_ENABLED != "0" { $ rm -rf @(path.join(man1dir, BC_MANPAGE)); } if DC_ENABLED != "0" { $ rm -rf @(path.join(man1dir, DC_MANPAGE)); } } } target @uninstall { bindir: str = get_bindir(); if BC_ENABLED != "0" { $ rm -rf @(path.join(bindir, BC_BIN)); } if DC_ENABLED != "0" { $ rm -rf @(path.join(bindir, DC_BIN)); } if NLS_ENABLED != "0" { if DESTDIR != "" { $ @(path.join(src_dir, "scripts/locale_uninstall.sh")) @(str(config["nlspath"])) $MAINEXEC $DESTDIR; } else { $ @(path.join(src_dir, "scripts/locale_uninstall.sh")) @(str(config["nlspath"])) $MAINEXEC; } } if bool(config["install_manpages"]) { man1dir: str = get_man1dir(); $ rm -rf @(path.join(man1dir, BC_MANPAGE)) @(path.join(man1dir, DC_MANPAGE)); } } } else { target @install: targets, BCL_HEADER_PATH { full_libdir: str = get_libdir(); $ $SAFE_INSTALL $EXEC_INSTALL_MODE @(file_dep) @(path.join(full_libdir, file_dep)); full_pc_path: str = get_pc_path(); bcl_pc: str = file_deps[1]; $ $SAFE_INSTALL $MANPAGE_INSTALL_MODE $bcl_pc @(path.join(full_pc_path, bcl_pc)); full_includedir: str = get_includedir(); $ $SAFE_INSTALL $MANPAGE_INSTALL_MODE @(file_deps[2]) @(path.join(full_includedir, BCL_HEADER)); if bool(config["install_manpages"]) { $ $SAFE_INSTALL $MANPAGE_INSTALL_MODE @(path.join(src_dir, path.join("manuals", BCL_MANPAGE))) @(path.join(get_man3dir(), BCL_MANPAGE)); } } target @uninstall { $ rm -rf @(path.join(get_libdir(), LIBRARY)) @(path.join(get_pc_path(), PC_FILE)) @(path.join(get_includedir(), BCL_HEADER)); if bool(config["install_manpages"]) { $ rm -rf @(path.join(get_man3dir(), BCL_MANPAGE)); } } } } // If the platform matches the host, we can run the test suite. if platform == host { // If we have the library, build and run that test. if BUILD_MODE == @library { libtesto: str = c2o("tests/bcl.c"); libtest: str = "bcl"; exe(libtest, @[ libtesto, targets[0] ]); test @bcl: libtest { $ @(str(tgt_name)); } } else { if BUILD_MODE != @dc { exe_tests("bc"); } if BUILD_MODE != @bc { exe_tests("dc"); } target @clean_tests { for f: path.find_ext(build_dir, "txt") { path.rm(f); } } } } target "bitfuncgen" { error("TODO: Make this"); } target @bitfuncgen: "bitfuncgen" { error("TODO: Make this"); } target "ministat" { error("TODO: Make this"); } target @ministat: "ministat" { error("TODO: Make this"); } target @all: targets;