1/** 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018-2025 Gavin D. Howard and contributors. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, this 10 * list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29PROG: str = path.realpath(sys.program); 30REAL: str = path.realpath(PROG +~ ".."); 31 32SCRIPTDIR: str = path.dirname(PROG); 33 34WINDOWS: bool = (host.os == "Windows"); 35 36DEFOPT: str = if WINDOWS { "/D"; } else { "-D"; }; 37C11OPT: str = if WINDOWS { "/std:c11"; } else { "-std=c11"; }; 38C99OPT: str = if WINDOWS { "/std:c99"; } else { "-std=c99"; }; 39 40/** 41 * Turns a string array into a string by joining all strings together with 42 * spaces. 43 * @param arr The array to join. 44 * @return The joined array. 45 */ 46fn strv2str(arr: []str) -> str 47{ 48 ret: !str = ""; 49 50 for item: arr 51 { 52 if ret == "" 53 { 54 ret! = item; 55 } 56 else 57 { 58 ret! = ret +~ " " +~ item; 59 } 60 } 61 62 return ret; 63} 64 65opts: Gaml = @(gaml){ 66 help: [ 67 "Runs the testing part of the release process.\n" 68 "\n" 69 "Usage: ", $PROG, " [-h|--help] [<options> \n" 70 ] 71 options: { 72 no64: { 73 help: "Turn off building and testing 64-bit builds." 74 long: @no-64 75 type: @NONE 76 } 77 no128: { 78 help: "Turn off building and testing builds with 128-bit integers." 79 long: @no-128 80 type: @NONE 81 } 82 C: { 83 help: "Turn off building under Clang." 84 short: @C 85 long: @no-clang 86 type: @NONE 87 } 88 C11: { 89 help: "Turn off building under C11." 90 long: @no-c11 91 type: @NONE 92 } 93 G: { 94 help: "Turn off building under GCC." 95 short: @G 96 long: @no-gcc 97 type: @NONE 98 } 99 GEN: { 100 help: "Turn off running the gen script." 101 short: @G 102 long: @no-gen-script 103 type: @NONE 104 } 105 MAKE: { 106 help: "Turn off running the build with `configure.sh` and `make`." 107 long: @no-make 108 type: @NONE 109 } 110 RIG: { 111 help: "Turn off running the build with Rig." 112 long: @no-rig 113 type: @NONE 114 } 115 T: { 116 help: "Turn off running tests." 117 short: @T 118 long: @no-tests 119 type: @NONE 120 } 121 computed-goto: { 122 help: "Whether to test with computed goto or not." 123 long: @computed-goto 124 type: @NONE 125 } 126 e: { 127 help: "Whether to test with editline or not." 128 short: @e 129 long: @editline 130 type: @NONE 131 } 132 g: { 133 help: "Whether generate tests that are generated or not." 134 short: @g 135 long: @generate 136 type: @NONE 137 } 138 history: { 139 help: "Whether to test with history or not." 140 long: @history 141 type: @NONE 142 } 143 k: { 144 help: "Whether to run the Karatsuba tests or not." 145 short: @k 146 long: @karatsuba 147 type: @NONE 148 } 149 p: { 150 help: "Whether to run problematic tests or not." 151 short: @p 152 long: @problematic-tests 153 type: @NONE 154 } 155 r: { 156 help: "Whether to test with readline or not." 157 short: @r 158 long: @readline 159 type: @NONE 160 } 161 s: { 162 help: "Whether to run tests under sanitizers or not." 163 short: @s 164 long: @sanitizers 165 type: @NONE 166 } 167 settings: { 168 help: "Whether to test settings or not." 169 long: @settings 170 type: @NONE 171 } 172 v: { 173 help: "Whether to run under Valgrind or not." 174 short: @v 175 long: @valgrind 176 type: @NONE 177 } 178 } 179}; 180 181// These are the booleans for the command-line flags. 182no64: !bool = false; 183no128: !bool = false; 184clang: !bool = true; 185c11: !bool = true; 186gcc: !bool = true; 187gen_host: !bool = true; 188run_make: !bool = !WINDOWS; 189run_rig: !bool = true; 190tests: !bool = true; 191computed_goto: !bool = false; 192editline: !bool = false; 193generated: !bool = false; 194history: !bool = false; 195karatsuba: !bool = false; 196problematic: !bool = false; 197readline: !bool = false; 198sanitizers: !bool = false; 199settings: !bool = false; 200valgrind: !bool = false; 201 202defcc: str = if clang { "clang"; } else if gcc { "gcc"; } else { "c99"; }; 203defbits: usize = if no64 { usize(32); } else { usize(64); }; 204 205cgoto_flags: []str = if !computed_goto { @[ "-DBC_NO_COMPUTED_GOTO" ]; }; 206 207// Set some strict warning flags. Clang's -Weverything can be way too strict, so 208// we actually have to turn off some things. 209CLANG_FLAGS: []str = @[ "-Weverything", "-Wno-padded", 210 "-Wno-unsafe-buffer-usage", 211 "-Wno-poison-system-directories", 212 "-Wno-switch-default", "-Wno-unknown-warning-option", 213 "-Wno-pre-c11-compat" ] +~ cgoto_flags; 214GCC_FLAGS: []str = @[ "-Wno-clobbered" ] +~ cgoto_flags; 215 216CLANG_FLAGS_STR: str = strv2str(CLANG_FLAGS); 217 218GCC_FLAGS_STR: str = strv2str(GCC_FLAGS); 219 220// Common CFLAGS. 221CFLAGS: []str = @[ "-Wall", "-Wextra", "-Werror", "-pedantic" ]; 222 223CFLAGS_STR: str = strv2str(CFLAGS); 224 225// Common debug and release flags. 226DEBUG_CFLAGS: []str = CFLAGS +~ @[ "-fno-omit-frame-pointer" ]; 227DEBUG_CFLAGS_STR: str = CFLAGS_STR +~ " -fno-omit-frame-pointer"; 228RELEASE_CFLAGS: []str = CFLAGS +~ @[ "-DNDEBUG" ]; 229RELEASE_CFLAGS_STR: str = CFLAGS_STR +~ " -DNDEBUG"; 230 231/** 232 * Print a header with a message. This is just to make it easy to track 233 * progress. 234 * @param msg The message to print in the header. 235 */ 236fn header(msg: str) -> void 237{ 238 io.eprint("\n*******************\n"); 239 io.eprint(msg); 240 io.eprint("\n*******************\n\n"); 241} 242 243/** 244 * An easy way to call `make`. 245 * @param args The arguments to pass to `make`, if any. 246 */ 247fn do_make(args: []str) -> void 248{ 249 $ make -j64 %(args); 250} 251 252/** 253 * An easy way to call Rig. 254 * @param args The arguments to pass to Rig, if any. 255 */ 256fn do_rig(args: []str) -> void 257{ 258 $ rig -j64 %(args); 259} 260 261/** 262 * Runs `configure.sh`. 263 * @param cflags The C compiler flags. 264 * @param cc The C compiler. 265 * @param flags The flags to pass to `configure.sh` itself. 266 * @param gen The setting for `GEN_HOST`. 267 * @param long_bit The number of bits in longs. 268 */ 269fn configure( 270 cflags: str, 271 cc: str, 272 flags: str, 273 gen: bool, 274 long_bit: usize 275) -> void 276{ 277 if !run_make 278 { 279 sys.panic("Cannot run `configure.sh` or make"); 280 } 281 282 extra_flags: str = 283 if !generated 284 { 285 if !problematic { "-GP"; } else { "-G"; } 286 } 287 else if !problematic 288 { 289 "-P"; 290 }; 291 292 extra_cflags: str = 293 if cc == "clang" 294 { 295 // We need to quiet this warning from Clang because the configure.sh 296 // docs have this warning, so people should know. Also, I want this 297 // script to work. 298 CLANG_FLAGS_STR +~ (if !gen_host { " -Wno-overlength-strings"; }); 299 } 300 else if cc == "gcc" 301 { 302 // We need to quiet this warning from GCC because the configure.sh docs 303 // have this warning, so people should know. Also, I want this script to 304 // work. 305 GCC_FLAGS_STR +~ (if !gen_host { "-Wno-overlength-strings"; }); 306 }; 307 308 all_flags: str = flags +~ " " +~ extra_flags; 309 all_cflags: str = cflags +~ " " +~ extra_cflags; 310 311 hdr := "Running configure.sh " +~ all_flags +~ 312 "..." +~ 313 "\n CC=\"" +~ cc +~ "\"\n" +~ 314 "\n CFLAGS=\"" +~ all_cflags +~ "\"\n" +~ 315 "\n LONG_BIT=" +~ str(long_bit) +~ 316 "\n GEN_HOST=" +~ str(gen); 317 318 // Print the header and do the job. 319 header(hdr); 320 321 env.set env.str("CFLAGS", str(cflags +~ extra_cflags)), 322 env.str("CC", cc), env.str("GEN_HOST", str(gen)), 323 env.str("LONG_BIT", str(long_bit)) 324 { 325 $ @(path.join(REAL, "configure.sh")) $flags $extra_flags > /dev/null 326 !> /dev/null; 327 } 328} 329 330/** 331 * Build with `make`. This function also captures and outputs any warnings if 332 * they exist because as far as I am concerned, warnings are not acceptable for 333 * release. 334 * @param cflags The C compiler flags. 335 * @param cc The C compiler. 336 * @param flags The flags to pass to `configure.sh` itself. 337 * @param gen The setting for `GEN_HOST`. 338 * @param long_bit The number of bits in longs. 339 */ 340fn build_make( 341 cflags: str, 342 cc: str, 343 flags: str, 344 gen: bool, 345 long_bit: usize 346) -> void 347{ 348 if !run_make 349 { 350 sys.panic("Cannot run `configure.sh` or make"); 351 } 352 353 configure(cflags, cc, flags, gen, long_bit); 354 355 hdr := "Building with `make`...\n CC=" +~ cc +~ 356 "\n CFLAGS=\"" +~ cflags +~ 357 "\n LONG_BIT=" +~ str(long_bit) +~ 358 "\n GEN_HOST=" +~ str(gen); 359 360 header(hdr); 361 362 res := $ make; 363 364 if res.stderr.len != 0 365 { 366 io.eprint(cc +~ "generated warning(s):\n\n"); 367 io.eprint(str(res.stderr)); 368 sys.exit(1); 369 } 370 371 if res.exitcode != 0 372 { 373 sys.exit(res.exitcode); 374 } 375} 376 377/** 378 * Build with Rig. This function also captures and outputs any warnings if they 379 * exist because as far as I am concerned, warnings are not acceptable for 380 * release. 381 * @param cflags The C compiler flags. 382 * @param cc The C compiler. 383 * @param flags The flags to pass to `configure.sh` itself. 384 * @param long_bit The number of bits in longs. 385 */ 386fn build_rig( 387 cflags: []str, 388 cc: str, 389 flags: []str, 390 long_bit: usize 391) -> void 392{ 393 if !run_rig 394 { 395 sys.panic("Cannot run Rig"); 396 } 397 398 cflags_str: str = strv2str(cflags); 399 400 hdr := "Building with Rig...\n CC=" +~ cc +~ 401 "\n CFLAGS=\"" +~ cflags_str +~ 402 "\n LONG_BIT=" +~ str(long_bit); 403 404 header(hdr); 405 406 res := $ rig; 407 408 if res.stderr.len != 0 409 { 410 io.eprint(cc +~ "generated warning(s):\n\n"); 411 io.eprint(str(res.stderr)); 412 sys.exit(1); 413 } 414 415 if res.exitcode != 0 416 { 417 sys.exit(res.exitcode); 418 } 419} 420 421/** 422 * Run tests with `make`. 423 * @param args Any arguments to pass to `make`, if any. 424 */ 425fn run_test_make(args: []str) -> void 426{ 427 if !run_make 428 { 429 sys.panic("Cannot run `configure.sh` or make"); 430 } 431 432 header("Running `make` tests"); 433 434 if args.len > 0 435 { 436 do_make(args); 437 } 438 else 439 { 440 do_make(@[ "test" ]); 441 442 if history 443 { 444 do_make(@[ "test_history" ]); 445 } 446 } 447} 448 449/** 450 * Run tests with Rig. 451 * @param args Any arguments to pass to Rig, if any. 452 */ 453fn run_test_rig(args: []str) -> void 454{ 455 if !run_rig 456 { 457 sys.panic("Cannot run Rig"); 458 } 459 460 header("Running Rig tests"); 461 462 if args.len > 0 463 { 464 do_rig(args); 465 } 466 else 467 { 468 do_rig(@[ "test" ]); 469 470 if history 471 { 472 do_rig(@[ "test_history" ]); 473 } 474 } 475} 476 477/** 478 * Builds and runs tests using `make` with both calculators, then bc only, then 479 * dc only. If `tests` is false, then it just does the builds. 480 * @param cflags The C compiler flags. 481 * @param cc The C compiler. 482 * @param flags The flags to pass to `configure.sh` itself. 483 * @param gen The setting for `GEN_HOST`. 484 * @param long_bit The number of bits in longs. 485 */ 486fn run_config_tests_make( 487 cflags: str, 488 cc: str, 489 flags: str, 490 gen: bool, 491 long_bit: usize, 492) -> void 493{ 494 if !run_make 495 { 496 sys.panic("Cannot run `configure.sh` or make"); 497 } 498 499 header_start: str = 500 if tests 501 { 502 "Running tests with configure flags and `make`"; 503 } 504 else 505 { 506 "Building with configure flags and `make`"; 507 }; 508 509 header("\"" +~ header_start +~ "\" ...\n" +~ 510 " CC=" +~ cc +~ "\n" +~ 511 " CFLAGS=\"" +~ cflags +~ "\"\n" +~ 512 " LONG_BIT=" +~ str(long_bit) +~ "\n" +~ 513 " GEN_HOST=" +~ str(gen)); 514 515 build_make(cflags, cc, flags, gen, long_bit); 516 517 if tests 518 { 519 run_test_make(@[]); 520 } 521 522 do_make(@[ "clean" ]); 523 524 build_make(cflags, cc, flags +~ " -b", gen, long_bit); 525 526 if tests 527 { 528 run_test_make(@[]); 529 } 530 531 do_make(@[ "clean" ]); 532 533 build_make(cflags, cc, flags +~ " -d", gen, long_bit); 534 535 if tests 536 { 537 run_test_make(@[]); 538 } 539 540 do_make(@[ "clean" ]); 541} 542 543/** 544 * Builds and runs tests using Rig with both calculators, then bc only, then dc 545 * only. If `tests` is false, then it just does the builds. 546 * @param cflags The C compiler flags. 547 * @param cc The C compiler. 548 * @param flags The flags to pass to Rig itself. 549 * @param long_bit The number of bits in longs. 550 */ 551fn run_config_tests_rig( 552 cflags: []str, 553 cc: str, 554 flags: []str, 555 long_bit: usize, 556) -> void 557{ 558 if !run_rig 559 { 560 sys.panic("Cannot run Rig"); 561 } 562 563 header_start: str = 564 if tests 565 { 566 "Running tests with Rig"; 567 } 568 else 569 { 570 "Building with Rig"; 571 }; 572 573 header("\"" +~ header_start +~ "\" ...\n" +~ 574 " CC=" +~ cc +~ "\n" +~ 575 " CFLAGS=\"" +~ strv2str(cflags) +~ "\"\n" +~ 576 " flags=\"" +~ strv2str(flags) +~ "\"\n" +~ 577 " LONG_BIT=" +~ str(long_bit)); 578 579 build_rig(cflags, cc, flags, long_bit); 580 581 if tests 582 { 583 run_test_rig(@[]); 584 } 585 586 do_rig(@[ "clean" ]); 587 588 build_rig(cflags, cc, flags +~ @[ "-Dbuild_mode=bc" ], long_bit); 589 590 if tests 591 { 592 run_test_rig(@[]); 593 } 594 595 do_rig(@[ "clean" ]); 596 597 build_rig(cflags, cc, flags +~ @[ "-Dbuild_mode=dc" ], long_bit); 598 599 if tests 600 { 601 run_test_rig(@[]); 602 } 603 604 do_rig(@[ "clean" ]); 605} 606 607/** 608 * Builds and runs tests using `run_config_tests_make()` with both calculators, 609 * then bc only, then dc only. If `tests` is false, then it just does the 610 * builds. 611 * @param cflags The C compiler flags. 612 * @param cc The C compiler. 613 * @param flags The flags to pass to `configure.sh` itself. 614 */ 615fn run_config_series_make( 616 cflags: str, 617 cc: str, 618 flags: str, 619) -> void 620{ 621 if !run_make 622 { 623 sys.panic("Cannot run `configure.sh` or make"); 624 } 625 626 if !no64 627 { 628 if !no128 629 { 630 run_config_tests_make(cflags, cc, flags, true, usize(64)); 631 } 632 633 if gen_host 634 { 635 run_config_tests_make(cflags, cc, flags, false, usize(64)); 636 } 637 638 run_config_tests_make(cflags +~ " " +~ DEFOPT +~ "BC_RAND_BUILTIN=0", 639 cc, flags, true, usize(64)); 640 641 // Test Editline if history is not turned off. 642 if editline && !(flags contains "H") 643 { 644 run_config_tests_make(cflags +~ " " +~ DEFOPT +~ 645 "BC_RAND_BUILTIN=0", 646 cc, flags +~ " -e", true, usize(64)); 647 } 648 649 // Test Readline if history is not turned off. 650 if readline && !(flags contains "H") 651 { 652 run_config_tests_make(cflags +~ " " +~ DEFOPT +~ 653 "BC_RAND_BUILTIN=0", 654 cc, flags +~ " -r", true, usize(64)); 655 } 656 } 657 658 run_config_tests_make(cflags, cc, flags, true, usize(32)); 659 660 if gen_host 661 { 662 run_config_tests_make(cflags, cc, flags, false, usize(32)); 663 } 664} 665 666/** 667 * Builds and runs tests using `run_config_tests_rig()` with both calculators, 668 * then bc only, then dc only. If `tests` is false, then it just does the 669 * builds. 670 * @param cflags The C compiler flags. 671 * @param cc The C compiler. 672 * @param flags The flags to pass to Rig itself. 673 */ 674fn run_config_series_rig( 675 cflags: []str, 676 cc: str, 677 flags: []str, 678) -> void 679{ 680 if !run_rig 681 { 682 sys.panic("Cannot run Rig"); 683 } 684 685 if !no64 686 { 687 if !no128 688 { 689 run_config_tests_rig(cflags, cc, flags, usize(64)); 690 } 691 692 run_config_tests_rig(cflags +~ @[ DEFOPT +~ "BC_RAND_BUILTIN=0" ], cc, 693 flags, usize(64)); 694 695 // Test Editline if history is not turned off. 696 if editline && !(flags contains "-Dhistory=none") 697 { 698 run_config_tests_rig(cflags +~ @[ DEFOPT +~ "BC_RAND_BUILTIN=0" ], 699 cc, flags +~ @[ "-Dhistory=editline" ], 700 usize(64)); 701 } 702 703 // Test Readline if history is not turned off. 704 if readline && !(flags contains "-Dhistory=none") 705 { 706 run_config_tests_rig(cflags +~ @[ DEFOPT +~ "BC_RAND_BUILTIN=0" ], 707 cc, flags +~ @[ "-Dhistory=readline" ], 708 usize(64)); 709 } 710 } 711 712 run_config_tests_rig(cflags, cc, flags, usize(32)); 713} 714 715/** 716 * Builds and runs tests with each setting combo running 717 * `run_config_series_make()`. If `tests` is false, it just does the builds. 718 * @param cflags The C compiler flags. 719 * @param cc The C compiler. 720 * @param flags The flags to pass to `configure.sh` itself. 721 */ 722fn run_settings_series_make( 723 cflags: str, 724 cc: str, 725 flags: str, 726) -> void 727{ 728 if !run_make 729 { 730 sys.panic("Cannot run `configure.sh` or make"); 731 } 732 733 if settings 734 { 735 settings_path: str = path.join(SCRIPTDIR, "release_settings_make.txt"); 736 settings_txt: str = io.read_file(settings_path); 737 lines: []str = settings_txt.split("\n"); 738 739 for line: lines 740 { 741 run_config_series_make(cflags, cc, flags +~ " " +~ line); 742 } 743 } 744 else 745 { 746 run_config_series_make(cflags, cc, flags); 747 } 748} 749 750/** 751 * Builds and runs tests with each setting combo running 752 * `run_config_series_rig()`. If `tests` is false, it just does the builds. 753 * @param cflags The C compiler flags. 754 * @param cc The C compiler. 755 * @param flags The flags to pass to Rig itself. 756 */ 757fn run_settings_series_rig( 758 cflags: []str, 759 cc: str, 760 flags: []str, 761) -> void 762{ 763 if !run_rig 764 { 765 sys.panic("Cannot run Rig"); 766 } 767 768 if settings 769 { 770 settings_path: str = path.join(SCRIPTDIR, "release_settings_rig.txt"); 771 settings_txt: str = io.read_file(settings_path); 772 lines: []str = settings_txt.split("\n"); 773 774 for line: lines 775 { 776 opts_list: []str = 777 for opt: line.split(" ") 778 { 779 DEFOPT +~ opt; 780 }; 781 782 run_config_series_rig(cflags, cc, flags +~ opts_list); 783 } 784 } 785 else 786 { 787 run_config_series_rig(cflags, cc, flags); 788 } 789} 790 791/** 792 * Builds and runs tests with each build type running 793 * `run_settings_series_make()`. If `tests` is false, it just does the builds. 794 * @param cflags The C compiler flags. 795 * @param cc The C compiler. 796 * @param flags The flags to pass to `configure.sh` itself. 797 */ 798fn run_test_series_make( 799 cflags: str, 800 cc: str, 801 flags: str, 802) -> void 803{ 804 if !run_make 805 { 806 sys.panic("Cannot run `configure.sh` or make"); 807 } 808 809 series_flags: []str = @[ "E", "H", "N", "EH", "EN", "HN", "EHN" ]; 810 811 run_settings_series_make(cflags, cc, flags); 812 813 for sflag: series_flags 814 { 815 run_settings_series_make(cflags, cc, flags +~ " -" +~ sflag); 816 } 817} 818 819/** 820 * Builds and runs tests with each build type running 821 * `run_settings_series_rig()`. If `tests` is false, it just does the builds. 822 * @param cflags The C compiler flags. 823 * @param cc The C compiler. 824 * @param flags The flags to pass to Rig itself. 825 */ 826fn run_test_series_rig( 827 cflags: []str, 828 cc: str, 829 flags: []str, 830) -> void 831{ 832 if !run_rig 833 { 834 sys.panic("Cannot run Rig"); 835 } 836 837 series_path: str = path.join(SCRIPTDIR, "release_flags_rig.txt"); 838 series_txt: str = io.read_file(series_path); 839 series_flags: []str = series_txt.split("\n"); 840 841 run_settings_series_rig(cflags, cc, flags); 842 843 for line: series_flags 844 { 845 opts_list: []str = 846 for opt: line.split(" ") 847 { 848 DEFOPT +~ opt; 849 }; 850 851 run_settings_series_rig(cflags, cc, flags +~ opts_list); 852 } 853} 854 855/** 856 * Builds and runs tests for `bcl` with `make`. If `tests` is false, it just 857 * does the builds. 858 * @param cflags The C compiler flags. 859 * @param cc The C compiler. 860 * @param flags The flags to pass to `configure.sh` itself. 861 */ 862fn run_lib_tests_make( 863 cflags: str, 864 cc: str, 865 flags: str, 866) -> void 867{ 868 if !run_make 869 { 870 sys.panic("Cannot run `configure.sh` or make"); 871 } 872 873 build_make(cflags +~ " -a", cc, flags, true, usize(64)); 874 875 if tests 876 { 877 run_test_make(@[ "test" ]); 878 } 879 880 build_make(cflags +~ " -a", cc, flags, true, usize(32)); 881 882 if tests 883 { 884 run_test_make(@[ "test" ]); 885 } 886} 887 888/** 889 * Builds and runs tests for `bcl` with Rig. If `tests` is false, it just does 890 * the builds. 891 * @param cflags The C compiler flags. 892 * @param cc The C compiler. 893 * @param flags The flags to pass to Rig itself. 894 */ 895fn run_lib_tests_rig( 896 cflags: []str, 897 cc: str, 898 flags: []str, 899) -> void 900{ 901 if !run_rig 902 { 903 sys.panic("Cannot run Rig"); 904 } 905 906 build_rig(cflags, cc, flags +~ @[ "-Dbuild_mode=library" ], usize(64)); 907 908 if tests 909 { 910 run_test_rig(@[ "test" ]); 911 } 912 913 build_rig(cflags, cc, flags +~ @[ "-Dbuild_mode=library" ], usize(32)); 914 915 if tests 916 { 917 run_test_rig(@[ "test" ]); 918 } 919} 920 921/** 922 * Builds and runs tests under C99, then C11, if requested, using 923 * `run_test_series_make()`. If run_tests is false, it just does the builds. 924 * @param cflags The C compiler flags. 925 * @param cc The C compiler. 926 * @param flags The flags to pass to Rig itself. 927 */ 928fn run_tests_make( 929 cflags: str, 930 cc: str, 931 flags: str, 932) -> void 933{ 934 if !run_make 935 { 936 sys.panic("Cannot run `configure.sh` or make"); 937 } 938 939 run_test_series_make(cflags +~ " " +~ C99OPT, cc, flags); 940 941 if c11 942 { 943 run_test_series_make(cflags +~ " " +~ C11OPT, cc, flags); 944 } 945} 946 947/** 948 * Builds and runs tests under C99, then C11, if requested, using 949 * `run_test_series_rig()`. If run_tests is false, it just does the builds. 950 * @param cflags The C compiler flags. 951 * @param cc The C compiler. 952 * @param flags The flags to pass to Rig itself. 953 */ 954fn run_tests_rig( 955 cflags: []str, 956 cc: str, 957 flags: []str, 958) -> void 959{ 960 if !run_rig 961 { 962 sys.panic("Cannot run Rig"); 963 } 964 965 run_test_series_rig(cflags +~ @[ C99OPT ], cc, flags); 966 967 if c11 968 { 969 run_test_series_rig(cflags +~ @[ C11OPT ], cc, flags); 970 } 971} 972 973/** 974 * Runs the Karatsuba tests with `make`. 975 */ 976fn karatsuba_make() -> void 977{ 978 if !run_make 979 { 980 sys.panic("Cannot run `configure.sh` or make"); 981 } 982 983 header("Running Karatsuba tests"); 984 985 do_make(@[ "karatsuba_test" ]); 986} 987 988/** 989 * Runs the Karatsuba tests with Rig. 990 */ 991fn karatsuba_rig() -> void 992{ 993 if !run_rig 994 { 995 sys.panic("Cannot run Rig"); 996 } 997 998 header("Running Karatsuba tests"); 999 1000 build_rig(RELEASE_CFLAGS, defcc, @[ "-O3" ], usize(64)); 1001 1002 do_rig(@[ "karatsuba_test" ]); 1003} 1004 1005/** 1006 * Builds with `make` and runs under valgrind. It runs both, bc only, then dc 1007 * only, then the library. 1008 */ 1009fn vg_make() -> void 1010{ 1011 if !run_make 1012 { 1013 sys.panic("Cannot run `configure.sh` or make"); 1014 } 1015 1016 header("Running Valgrind under `make`"); 1017 1018 build_make(DEBUG_CFLAGS_STR +~ " -std=c99", "gcc", "-O3 -gv", true, 1019 defbits); 1020 run_test_make(@[ "test" ]); 1021 1022 do_make(@[ "clean_config" ]); 1023 1024 build_make(DEBUG_CFLAGS_STR +~ " -std=c99", "gcc", "-O3 -gvb", true, 1025 defbits); 1026 run_test_make(@[ "test" ]); 1027 1028 do_make(@[ "clean_config" ]); 1029 1030 build_make(DEBUG_CFLAGS_STR +~ " -std=c99", "gcc", "-O3 -gvd", true, 1031 defbits); 1032 run_test_make(@[ "test" ]); 1033 1034 do_make(@[ "clean_config" ]); 1035 1036 build_make(DEBUG_CFLAGS_STR +~ " -std=c99", "gcc", "-O3 -gva", true, 1037 defbits); 1038 run_test_make(@[ "test" ]); 1039 1040 do_make(@[ "clean_config" ]); 1041} 1042 1043fn vg_rig() -> void 1044{ 1045 if !run_rig 1046 { 1047 sys.panic("Cannot run Rig"); 1048 } 1049 1050 header("Running Valgrind under Rig"); 1051 1052 build_rig(DEBUG_CFLAGS +~ @[ "-std=c99" ], "gcc", @[ "-O3", "-gv" ], 1053 defbits); 1054 run_test_rig(@[ "test" ]); 1055 1056 do_rig(@[ "clean_config" ]); 1057 1058 build_rig(DEBUG_CFLAGS +~ @[ "-std=c99" ], "gcc", @[ "-O3", "-gvb" ], 1059 defbits); 1060 run_test_rig(@[ "test" ]); 1061 1062 do_rig(@[ "clean_config" ]); 1063 1064 build_rig(DEBUG_CFLAGS +~ @[ "-std=c99" ], "gcc", @[ "-O3", "-gvd" ], 1065 defbits); 1066 run_test_rig(@[ "test" ]); 1067 1068 do_rig(@[ "clean_config" ]); 1069 1070 build_rig(DEBUG_CFLAGS +~ @[ "-std=c99" ], "gcc", @[ "-O3", "-gva" ], 1071 defbits); 1072 run_test_rig(@[ "test" ]); 1073 1074 do_rig(@[ "clean_config" ]); 1075} 1076 1077/** 1078 * Builds the debug series with `make` and runs the tests if `tests` allows. 1079 * @param cc The C compiler. 1080 */ 1081fn debug_make( 1082 cc: str, 1083) -> void 1084{ 1085 if !run_make 1086 { 1087 sys.panic("Cannot run `configure.sh` or make"); 1088 } 1089 1090 if cc == "clang" && sanitizers 1091 { 1092 run_tests_make(DEBUG_CFLAGS_STR +~ " -fsanitize=undefined", cc, "-mg"); 1093 } 1094 else 1095 { 1096 run_tests_make(DEBUG_CFLAGS_STR, cc, "-g"); 1097 } 1098} 1099 1100/** 1101 * Builds the release series with `make` and runs the tests if `tests` allows. 1102 * @param cc The C compiler. 1103 */ 1104fn release_make( 1105 cc: str, 1106) -> void 1107{ 1108 if !run_make 1109 { 1110 sys.panic("Cannot run `configure.sh` or make"); 1111 } 1112 1113 run_tests_make(RELEASE_CFLAGS_STR, cc, "-O3"); 1114 run_lib_tests_make(RELEASE_CFLAGS_STR, cc, "-O3"); 1115} 1116 1117/** 1118 * Builds the release debug series with `make` and runs the tests if `tests` 1119 * allows. 1120 * @param cc The C compiler. 1121 */ 1122fn reldebug_make( 1123 cc: str, 1124) -> void 1125{ 1126 if !run_make 1127 { 1128 sys.panic("Cannot run `configure.sh` or make"); 1129 } 1130 1131 if cc == "clang" && sanitizers 1132 { 1133 run_tests_make(DEBUG_CFLAGS_STR +~ " -fsanitize=address", cc, "-mgO3"); 1134 run_tests_make(DEBUG_CFLAGS_STR +~ " -fsanitize=memory", cc, "-mgO3"); 1135 } 1136 else 1137 { 1138 run_tests_make(DEBUG_CFLAGS_STR, cc, "-gO3"); 1139 } 1140 1141 if cc == "clang" && sanitizers 1142 { 1143 run_lib_tests_make(DEBUG_CFLAGS_STR +~ " -fsanitize=address", cc, 1144 "-mgO3"); 1145 run_lib_tests_make(DEBUG_CFLAGS_STR +~ " -fsanitize=memory", cc, 1146 "-mgO3"); 1147 } 1148 else 1149 { 1150 run_lib_tests_make(DEBUG_CFLAGS_STR, cc, "-gO3"); 1151 } 1152} 1153 1154/** 1155 * Builds the min size release with `make` and runs the tests if `tests` allows. 1156 * @param cc The C compiler. 1157 */ 1158fn minsize_make( 1159 cc: str, 1160) -> void 1161{ 1162 if !run_make 1163 { 1164 sys.panic("Cannot run `configure.sh` or make"); 1165 } 1166 1167 run_tests_make(RELEASE_CFLAGS_STR, cc, "-Os"); 1168 run_lib_tests_make(RELEASE_CFLAGS_STR, cc, "-Os"); 1169} 1170 1171/** 1172 * Builds all sets with `make`: debug, release, release debug, and min size, and 1173 * runs the tests if `tests` allows. 1174 * @param cc The C compiler. 1175 */ 1176fn build_set_make( 1177 cc: str, 1178) -> void 1179{ 1180 if !run_make 1181 { 1182 sys.panic("Cannot run `configure.sh` or make"); 1183 } 1184 1185 debug_make(cc); 1186 release_make(cc); 1187 reldebug_make(cc); 1188 minsize_make(cc); 1189 1190 if karatsuba 1191 { 1192 karatsuba_make(); 1193 } 1194 1195 if valgrind 1196 { 1197 vg_make(); 1198 } 1199} 1200 1201/** 1202 * Builds the debug series with Rig and runs the tests if `tests` allows. 1203 * @param cc The C compiler. 1204 */ 1205fn debug_rig( 1206 cc: str, 1207) -> void 1208{ 1209 if !run_rig 1210 { 1211 sys.panic("Cannot run Rig"); 1212 } 1213 1214 if cc == "clang" && sanitizers 1215 { 1216 run_tests_rig(DEBUG_CFLAGS +~ @[ " -fsanitize=undefined" ], cc, 1217 @[ "-Dmemcheck=1", "-Ddebug=1" ]); 1218 } 1219 else 1220 { 1221 run_tests_rig(DEBUG_CFLAGS, cc, @[ "-Ddebug=1" ]); 1222 } 1223} 1224 1225/** 1226 * Builds the release series with Rig and runs the tests if `tests` allows. 1227 * @param cc The C compiler. 1228 */ 1229fn release_rig( 1230 cc: str, 1231) -> void 1232{ 1233 if !run_rig 1234 { 1235 sys.panic("Cannot run Rig"); 1236 } 1237 1238 run_tests_rig(RELEASE_CFLAGS, cc, @[ "-Doptimization=3" ]); 1239 run_lib_tests_rig(RELEASE_CFLAGS, cc, @[ "-Doptimization=3" ]); 1240} 1241 1242/** 1243 * Builds the release debug series with Rig and runs the tests if `tests` 1244 * allows. 1245 * @param cc The C compiler. 1246 */ 1247fn reldebug_rig( 1248 cc: str, 1249) -> void 1250{ 1251 if !run_rig 1252 { 1253 sys.panic("Cannot run Rig"); 1254 } 1255 1256 if cc == "clang" && sanitizers 1257 { 1258 run_tests_rig(DEBUG_CFLAGS +~ @[ " -fsanitize=address" ], cc, 1259 @[ "-Dmemcheck=1", "-Ddebug=1", "-Doptimization=3" ]); 1260 run_tests_rig(DEBUG_CFLAGS +~ @[ " -fsanitize=memory" ], cc, 1261 @[ "-Dmemcheck=1", "-Ddebug=1", "-Doptimization=3" ]); 1262 } 1263 else 1264 { 1265 run_tests_rig(DEBUG_CFLAGS, cc, @[ "-gO3" ]); 1266 } 1267 1268 if cc == "clang" && sanitizers 1269 { 1270 run_lib_tests_rig(DEBUG_CFLAGS +~ @[ " -fsanitize=address" ], cc, 1271 @[ "-Dmemcheck=1", "-Ddebug=1", "-Doptimization=3" ]); 1272 run_lib_tests_rig(DEBUG_CFLAGS +~ @[ " -fsanitize=memory" ], cc, 1273 @[ "-Dmemcheck=1", "-Ddebug=1", "-Doptimization=3" ]); 1274 } 1275 else 1276 { 1277 run_lib_tests_rig(DEBUG_CFLAGS, cc, 1278 @[ "-Ddebug=1", "-Doptimization=3" ]); 1279 } 1280} 1281 1282/** 1283 * Builds the min size release with Rig and runs the tests if `tests` allows. 1284 * @param cc The C compiler. 1285 */ 1286fn minsize_rig( 1287 cc: str, 1288) -> void 1289{ 1290 if !run_rig 1291 { 1292 sys.panic("Cannot run Rig"); 1293 } 1294 1295 run_tests_rig(RELEASE_CFLAGS, cc, @[ "-Doptimization=s" ]); 1296 run_lib_tests_rig(RELEASE_CFLAGS, cc, @[ "-Doptimization=s" ]); 1297} 1298 1299/** 1300 * Builds all sets with Rig: debug, release, release debug, and min size, and 1301 * runs the tests if `tests` allows. 1302 * @param cc The C compiler. 1303 */ 1304fn build_set_rig( 1305 cc: str, 1306) -> void 1307{ 1308 if !run_rig 1309 { 1310 sys.panic("Cannot run Rig"); 1311 } 1312 1313 debug_rig(cc); 1314 release_rig(cc); 1315 reldebug_rig(cc); 1316 minsize_rig(cc); 1317 1318 if karatsuba 1319 { 1320 karatsuba_rig(); 1321 } 1322 1323 if valgrind 1324 { 1325 vg_rig(); 1326 } 1327} 1328 1329/** 1330 * Builds all sets with `make` under all compilers. 1331 */ 1332fn build_sets_make() -> void 1333{ 1334 header("Running math library under --standard with Rig"); 1335 1336 build_make(DEBUG_CFLAGS_STR +~ " -std=c99", defcc, "-g", true, 1337 defbits); 1338 1339 $ bin/bc -ls << @("quit\n"); 1340 1341 do_rig(@[ "clean_tests" ]); 1342 1343 if clang 1344 { 1345 build_set_make("clang"); 1346 } 1347 1348 if gcc 1349 { 1350 build_set_make("gcc"); 1351 } 1352} 1353 1354/** 1355 * Builds all sets with Rig under all compilers. 1356 */ 1357fn build_sets_rig() -> void 1358{ 1359 header("Running math library under --standard with Rig"); 1360 1361 build_rig(DEBUG_CFLAGS +~ @[ "-std=c99" ], defcc, @[ "-Ddebug=1" ], 1362 defbits); 1363 1364 $ build/bc -ls << @("quit\n"); 1365 1366 do_rig(@[ "clean_tests" ]); 1367 1368 if clang 1369 { 1370 build_set_rig("clang"); 1371 } 1372 1373 if gcc 1374 { 1375 build_set_rig("gcc"); 1376 } 1377} 1378 1379fn build_sets() -> void 1380{ 1381 if !run_make 1382 { 1383 build_sets_rig(); 1384 } 1385 else if !run_rig 1386 { 1387 build_sets_make(); 1388 } 1389 else 1390 { 1391 parallel.map @[ "rig", "make" ]: 1392 (builder: str) -> void 1393 { 1394 if builder == "rig" 1395 { 1396 build_sets_rig(); 1397 } 1398 else if builder == "make" 1399 { 1400 build_sets_make(); 1401 } 1402 else 1403 { 1404 sys.panic("Bad builder: " +~ builder +~ "\n"); 1405 } 1406 } 1407 } 1408 1409 io.eprint("\nTests successful.\n"); 1410} 1411