Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bc/build.rig
39475 views
/*
 * *****************************************************************************
 *
 * 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;