1/* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2025 Gavin D. Howard and contributors. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * * Redistributions of source code must retain the above copyright notice, this 12 * list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 * ***************************************************************************** 31 * 32 * The build script file. 33 * 34 */ 35 36if OS == "Windows" && bool(config["lto"]) 37{ 38 error("Link-time optimization is not supported on Windows"); 39} 40 41if LIBRARY_ENABLED == "0" 42{ 43 if OS != "Windows" && NLS_ENABLED != "0" 44 { 45 io.eprint("Testing NLS...\n"); 46 47 clang_flags: []str = 48 if CC contains "clang" 49 { 50 @[ "-Wno_unreachable-code" ]; 51 }; 52 53 flags: []str = clang_flags +~ @[ 54 DEFOPT +~ "BC_ENABLE_NLS=1", 55 DEFOPT +~ "BC_ENABLED=" +~ BC_ENABLED, 56 DEFOPT +~ "DC_ENABLED=" +~ DC_ENABLED, 57 DEFOPT +~ "BC_ENABLE_HISTORY=0", 58 DEFOPT +~ "BC_ENABLE_LIBRARY=0", 59 DEFOPT +~ "BC_ENABLE_AFL=0", 60 DEFOPT +~ "BC_ENABLE_EXTRA_MATH=" +~ EXTRA_MATH_ENABLED, 61 DEFOPT +~ "BC_ENABLE_OSSFUZZ=0", 62 DEFOPT +~ "_POSIX_C_SOURCE=200809L", 63 DEFOPT +~ "_XOPEN_SOURCE=700", 64 INCOPT, 65 ]; 66 67 res := $ $CC %(flags) -c @(path.join(src_dir, "src/vm.c")) -E; 68 69 if res.exitcode != 0 70 { 71 if FORCE 72 { 73 io.eprint("Forcing NLS...\n"); 74 } 75 else 76 { 77 error("NLS does not work\n"); 78 } 79 } 80 else 81 { 82 if path.isfile("vm.o") 83 { 84 path.rm("vm.o"); 85 } 86 87 io.eprint("NLS works.\n\n"); 88 io.eprint("Testing gencat...\n"); 89 90 res2 := $ gencat ./en_US.cat 91 @(path.join(src_dir, "locales/en_US.msg")); 92 93 if res2.exitcode != 0 94 { 95 if FORCE 96 { 97 io.eprint("Forcing NLS...\n"); 98 } 99 else 100 { 101 error("gencat does not work\n"); 102 } 103 } 104 else 105 { 106 io.eprint("gencat works.\n\n"); 107 108 if platform != host 109 { 110 error("Cross compiles will not work!\n\n"); 111 } 112 } 113 } 114 } 115 116 if OS != "Windows" && sym(config["history"]) != @none 117 { 118 io.eprint("Testing history...\n"); 119 120 flags: []str = @[ 121 DEFOPT +~ "BC_ENABLE_HISTORY=1", 122 DEFOPT +~ "BC_ENABLED=" +~ BC_ENABLED, 123 DEFOPT +~ "DC_ENABLED=" +~ DC_ENABLED, 124 DEFOPT +~ "BC_ENABLE_NLS=" +~ NLS_ENABLED, 125 DEFOPT +~ "BC_ENABLE_LIBRARY=0", 126 DEFOPT +~ "BC_ENABLE_AFL=0", 127 DEFOPT +~ "BC_ENABLE_EDITLINE=" +~ EDITLINE_ENABLED, 128 DEFOPT +~ "BC_ENABLE_READLINE=" +~ READLINE_ENABLED, 129 DEFOPT +~ "BC_ENABLE_EXTRA_MATH=" +~ EXTRA_MATH_ENABLED, 130 DEFOPT +~ "BC_ENABLE_OSSFUZZ=0", 131 DEFOPT +~ "_POSIX_C_SOURCE=200809L", 132 DEFOPT +~ "_XOPEN_SOURCE=700", 133 INCOPT, 134 ]; 135 136 res := $ $CC %(flags) -c @(path.join(src_dir, "src/history.c")) -E; 137 138 if res.exitcode != 0 139 { 140 if FORCE 141 { 142 io.eprint("Forcing history...\n"); 143 } 144 else 145 { 146 error("History does not work\n"); 147 } 148 } 149 else 150 { 151 if path.isfile("history.o") 152 { 153 path.rm("history.o"); 154 } 155 156 io.eprint("History works.\n\n"); 157 } 158 } 159} 160 161freebsd_flags: []str = 162if OS != "FreeBSD" 163{ 164 @[ DEFOPT +~ "_POSIX_C_SOURCE=200809L", DEFOPT +~ "_XOPEN_SOURCE=700" ]; 165}; 166 167macos: bool = (OS == "Darwin"); 168 169macos_flags: []str = 170if macos 171{ 172 @[ DEFOPT +~ "_DARWIN_C_SOURCE" ]; 173}; 174 175openbsd_flags: []str = 176if OS == "OpenBSD" 177{ 178 if READLINE_ENABLED != "0" 179 { 180 error("Cannot use readline on OpenBSD"); 181 } 182 183 @[ DEFOPT +~ "_BSD_SOURCE" ]; 184}; 185 186strip_flag: []str = 187if OS != "Windows" && !bool(config["debug"]) && !macos && bool(config["strip"]) 188{ 189 @[ "-s" ]; 190}; 191 192lto_flag: []str = 193if bool(config["lto"]) 194{ 195 @[ "-flto" ]; 196}; 197 198strict_flags: []str = 199if bool(config["strict"]) 200{ 201 // Strict build only works for GCC and Clang, so we do want to set that 202 // here. 203 if CC contains "gcc" || CC contains "clang" 204 { 205 // These are the standard strict build flags for both compilers. 206 std_strict: []str = @[ "-Wall", "-Wextra", "-Werror", "-pedantic" ]; 207 208 // Clang has -Weverything, which I ensure Yc builds under. 209 // 210 // I also want unlimited errors because Clang is my development 211 // compiler; it caps at 20 by default. 212 compiler_strict: []str = 213 if CC contains "clang" 214 { 215 // Oh, and add the standard. 216 @[ "-Weverything", "-ferror-limit=100000", "-Wno-padded", 217 "-Wno-unknown-warning-option", "-Wno-unsafe-buffer-usage", 218 "-Wno-documentation-unknown-command", "-Wno-pre-c11-compat", 219 "-Wno-enum-enum-conversion", "-Wno-switch-default" ]; 220 }; 221 222 // Return the combination of the sets. 223 std_strict +~ compiler_strict; 224 } 225 else if OS == "Windows" 226 { 227 // Return the combo of the strict options, the standard, and the 228 // sanitizer defines. 229 @[ "/W4", "/WX", "/wd\"4996\"", "/permissive-" ]; 230 } 231}; 232 233version_contents: str = io.read_file(path.join(src_dir, "VERSION.txt")); 234version_lines: []str = version_contents.split("\n"); 235version: str = version_lines[0]; 236 237version_flag: []str = @[ DEFOPT +~ "VERSION=" +~ version ]; 238 239other_flags: []str = freebsd_flags +~ macos_flags +~ openbsd_flags +~ 240 lto_flag +~ strict_flags +~ version_flag +~ 241if bool(config["debug"]) 242{ 243 @[ compiler_db["opt.debug"] ]; 244}; 245 246history_files: []str = 247if HISTORY != @none 248{ 249 HISTORY_C_FILES; 250}; 251 252c_files: []str = 253if BUILD_MODE == @both 254{ 255 COMMON_C_FILES +~ EXEC_C_FILES +~ BC_C_FILES +~ DC_C_FILES +~ history_files; 256} 257else if BUILD_MODE == @bc 258{ 259 COMMON_C_FILES +~ EXEC_C_FILES +~ BC_C_FILES +~ history_files; 260} 261else if BUILD_MODE == @dc 262{ 263 COMMON_C_FILES +~ EXEC_C_FILES +~ DC_C_FILES +~ history_files; 264} 265else 266{ 267 COMMON_C_FILES +~ LIBRARY_C_FILES; 268}; 269 270build_config: Gaml = @(gaml){ 271 other_cflags: $other_flags 272 strip_flag: $strip_flag 273}; 274 275targets: []str = 276push build_config: config_stack 277{ 278 gen_o_files: []str = 279 if BUILD_MODE != @library 280 { 281 @[ 282 txt2o("gen/lib.bc", "bc_lib", "bc_lib_name", "BC_ENABLED", true), 283 txt2o("gen/lib2.bc", "bc_lib2", "bc_lib2_name", 284 "BC_ENABLED && BC_ENABLE_EXTRA_MATH", true), 285 txt2o("gen/bc_help.txt", "bc_help", "", "BC_ENABLED", false), 286 txt2o("gen/dc_help.txt", "dc_help", "", "DC_ENABLED", false), 287 ]; 288 }; 289 290 obj_files: []str = gen_o_files +~ 291 for f: c_files 292 { 293 c2o(f); 294 }; 295 296 if BUILD_MODE == @both || BUILD_MODE == @bc 297 { 298 if OS != "Windows" && bool(config["install_manpages"]) 299 { 300 src: str = path.join("manuals/bc", BUILD_TYPE +~ ".1"); 301 302 target BC_MANPAGE: src 303 { 304 $ cp -f @(file_dep) @(tgt); 305 } 306 } 307 308 exe(BC_BIN, obj_files); 309 } 310 311 if BUILD_MODE == @both || BUILD_MODE == @dc 312 { 313 if OS != "Windows" && bool(config["install_manpages"]) 314 { 315 src: str = path.join("manuals/dc", BUILD_TYPE +~ ".1"); 316 317 target DC_MANPAGE: src 318 { 319 $ cp -f @(file_dep) @(tgt); 320 } 321 } 322 323 if BUILD_MODE == @both 324 { 325 ln(DC_BIN, BC_BIN); 326 } 327 else 328 { 329 exe(DC_BIN, obj_files); 330 } 331 } 332 333 if BUILD_MODE == @library 334 { 335 lib(LIBRARY, obj_files); 336 } 337 338 if BUILD_MODE == @both 339 { 340 @[ BC_BIN, DC_BIN ]; 341 } 342 else if BUILD_MODE == @bc 343 { 344 @[ DC_BIN ]; 345 } 346 else if BUILD_MODE == @dc 347 { 348 @[ DC_BIN ]; 349 } 350 else 351 { 352 includedir: str = get_includedir(); 353 libdir: str = get_libdir(); 354 355 pc_config: Gaml = @(gaml){ 356 INCLUDEDIR: $includedir 357 LIBDIR: $libdir 358 VERSION: $version 359 }; 360 361 push pc_config: config_stack 362 { 363 target PC_FILE: PC_FILE +~ ".in" 364 { 365 configure_file(file_dep, tgt, "%%"); 366 } 367 } 368 369 @[ LIBRARY, PC_FILE ]; 370 } 371}; 372 373if OS != "Windows" 374{ 375 if LIBRARY_ENABLED == "0" 376 { 377 target @install: targets 378 { 379 bindir: str = get_bindir(); 380 381 if BC_ENABLED != "0" 382 { 383 $ $SAFE_INSTALL $EXEC_INSTALL_MODE $BC_BIN 384 @(path.join(bindir, BC_BIN)); 385 } 386 387 if DC_ENABLED != "0" 388 { 389 if BC_ENABLED != "0" 390 { 391 $ ln -sf @("./" +~ BC_BIN) @(path.join(bindir, DC_BIN)); 392 } 393 else 394 { 395 $ $SAFE_INSTALL $EXEC_INSTALL_MODE $BC_BIN 396 @(path.join(bindir, BC_BIN)); 397 } 398 } 399 400 if NLS_ENABLED != "0" 401 { 402 locale_install_args: []str = 403 if sym(config["locales"]) == @all 404 { 405 @[ "-l" ]; 406 }; 407 408 if DESTDIR != "" 409 { 410 $ @(path.join(src_dir, "scripts/locale_install.sh")) 411 %(locale_install_args) @(str(config["nlspath"])) 412 $MAINEXEC $DESTDIR; 413 } 414 else 415 { 416 $ @(path.join(src_dir, "scripts/locale_install.sh")) 417 %(locale_install_args) @(str(config["nlspath"])) 418 $MAINEXEC; 419 } 420 } 421 422 if bool(config["install_manpages"]) 423 { 424 man1dir: str = get_man1dir(); 425 426 if BC_ENABLED != "0" 427 { 428 $ rm -rf @(path.join(man1dir, BC_MANPAGE)); 429 } 430 431 if DC_ENABLED != "0" 432 { 433 $ rm -rf @(path.join(man1dir, DC_MANPAGE)); 434 } 435 } 436 } 437 438 target @uninstall 439 { 440 bindir: str = get_bindir(); 441 442 if BC_ENABLED != "0" 443 { 444 $ rm -rf @(path.join(bindir, BC_BIN)); 445 } 446 447 if DC_ENABLED != "0" 448 { 449 $ rm -rf @(path.join(bindir, DC_BIN)); 450 } 451 452 if NLS_ENABLED != "0" 453 { 454 if DESTDIR != "" 455 { 456 $ @(path.join(src_dir, "scripts/locale_uninstall.sh")) 457 @(str(config["nlspath"])) $MAINEXEC $DESTDIR; 458 } 459 else 460 { 461 $ @(path.join(src_dir, "scripts/locale_uninstall.sh")) 462 @(str(config["nlspath"])) $MAINEXEC; 463 } 464 } 465 466 if bool(config["install_manpages"]) 467 { 468 man1dir: str = get_man1dir(); 469 $ rm -rf @(path.join(man1dir, BC_MANPAGE)) 470 @(path.join(man1dir, DC_MANPAGE)); 471 } 472 } 473 } 474 else 475 { 476 target @install: targets, BCL_HEADER_PATH 477 { 478 full_libdir: str = get_libdir(); 479 480 $ $SAFE_INSTALL $EXEC_INSTALL_MODE @(file_dep) 481 @(path.join(full_libdir, file_dep)); 482 483 full_pc_path: str = get_pc_path(); 484 bcl_pc: str = file_deps[1]; 485 486 $ $SAFE_INSTALL $MANPAGE_INSTALL_MODE $bcl_pc 487 @(path.join(full_pc_path, bcl_pc)); 488 489 full_includedir: str = get_includedir(); 490 491 $ $SAFE_INSTALL $MANPAGE_INSTALL_MODE @(file_deps[2]) 492 @(path.join(full_includedir, BCL_HEADER)); 493 494 if bool(config["install_manpages"]) 495 { 496 $ $SAFE_INSTALL $MANPAGE_INSTALL_MODE 497 @(path.join(src_dir, path.join("manuals", BCL_MANPAGE))) 498 @(path.join(get_man3dir(), BCL_MANPAGE)); 499 } 500 } 501 502 target @uninstall 503 { 504 $ rm -rf @(path.join(get_libdir(), LIBRARY)) 505 @(path.join(get_pc_path(), PC_FILE)) 506 @(path.join(get_includedir(), BCL_HEADER)); 507 508 if bool(config["install_manpages"]) 509 { 510 $ rm -rf @(path.join(get_man3dir(), BCL_MANPAGE)); 511 } 512 } 513 } 514} 515 516// If the platform matches the host, we can run the test suite. 517if platform == host 518{ 519 // If we have the library, build and run that test. 520 if BUILD_MODE == @library 521 { 522 libtesto: str = c2o("tests/bcl.c"); 523 524 libtest: str = "bcl"; 525 526 exe(libtest, @[ libtesto, targets[0] ]); 527 528 test @bcl: libtest 529 { 530 $ @(str(tgt_name)); 531 } 532 } 533 else 534 { 535 if BUILD_MODE != @dc 536 { 537 exe_tests("bc"); 538 } 539 540 if BUILD_MODE != @bc 541 { 542 exe_tests("dc"); 543 } 544 545 target @clean_tests 546 { 547 for f: path.find_ext(build_dir, "txt") 548 { 549 path.rm(f); 550 } 551 } 552 } 553} 554 555target "bitfuncgen" 556{ 557 error("TODO: Make this"); 558} 559 560target @bitfuncgen: "bitfuncgen" 561{ 562 error("TODO: Make this"); 563} 564 565target "ministat" 566{ 567 error("TODO: Make this"); 568} 569 570target @ministat: "ministat" 571{ 572 error("TODO: Make this"); 573} 574 575target @all: targets; 576