/** * ***** BEGIN LICENSE BLOCK ***** * * Copyright 2017-2023 Yzena, LLC * * Licensed under the Yzena Viral User License, Version 0.1 (the "Yzena Viral * User License" or "YVUL"), the GNU Affero General Public License (the "GNU * AGPL"), Version 3.0, and the Server Side Public License (the "SSPL"), * Version 1. You may not use this file except in compliance with all of those * licenses. * * You may obtain a copy of the Yzena Viral User License at * * https://yzena.com/yzena-viral-user-license/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Yzena Viral User License is distributed under the * following disclaimer: * * As far as the law allows, this software comes as is, without any * warranty or condition, and no contributor will be liable to anyone for * any damages related to this software or this license, under any kind of * legal claim. * * You may obtain a copy of the GNU Affero General Public License at * * https://www.gnu.org/licenses/agpl-3.0.html * * Unless required by applicable law or agreed to in writing, software * distributed under the GNU Affero General Public License is distributed under * the following disclaimer: * * This software is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero * General Public License for more details. * * You may obtain a copy of the Server Side Public License at * * https://www.mongodb.com/licensing/server-side-public-license * * Unless required by applicable law or agreed to in writing, software * distributed under the Server Side Public License is distributed under the * following disclaimer: * * This software is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Server * Side Public License for more details. * * ****** END LICENSE BLOCK ****** * * ***************************************************************** * * ******* BEGIN FILE DESCRIPTION ******* * * Package build script file. * * ******** END FILE DESCRIPTION ******** */ fn exe_name(exe: str) -> str { return if platform.os == "Windows" { exe +~ ".exe"; } else { exe; }; } fn add_exe(exe: str, dep_list: []str) -> str { ret: str = exe_name(exe); target ret: dep_list { $ @(config["exe_cmd_line"]) @tgt %deps; } return ret; } fn add_exe_by_name(exe: str, dep_list: []str) -> str { ret: str = exe_name(exe); file: str = exe +~ ".c"; target ret: file, dep_list { $ @(config["exe_cmd_line"]) @tgt %deps; } return ret; } fn add_link_exe(exe: str, dep: str) -> str { ret: str = exe_name(exe); target ret: dep { if platform.os != "Windows" { $ ln -sf @("./" +~ deps[0]) @tgt; } else { // I don't want to deal with symlinks on Windows. $ copy @("./" +~ deps[0]) @tgt; } } return ret; } fn add_lib(lib: str, dep_list: []str) -> str { libtgt: str = if platform.os == "Windows" { "lib" +~ lib +~ ".lib"; } else { "lib" +~ lib +~ ".a"; }; target libtgt: dep_list { if platform.os == "Windows" { $ @(config["cmd_line"]) @tgt %deps; } else { $ ar -r -cu @tgt %deps; } } return libtgt; } fn add_config_file(out: str, file: str) -> str { return configure_file out, file; } fn option(defopt: str, name: str, opt: str) -> []str { opt: str = defopt +~ name +~ (if config[opt] { "=1"; } else { "=0"; }); return #[ opt ]; } fn add_c_file(f: str) -> str { ext: str = if platform.os == "Windows" { "obj" } else { "o" }; obj: str = replace_ext f, "c", ext; // TODO: Check for includes and add them as dynamic dependencies. target obj: f { $ @(config["cmd_line"]) @tgt %deps; } return obj; } fn walk_src_dir() -> []str { files: ![]str = #[ ]; src_files: []str = find "*.c", "src"; foreach f: src_files { // Skip these two files for now. if f contains "main.c" || f contains "stdio.c" { continue; } files! +~= f; } dirs: []str = find_dirs "src"; foreach d: dirs { d_files: []str = find "*.c", d; foreach f: d_files { files! +~= f; } dos: str = d +~ "/os"; if exists dos { if platform.os == "Windows" { win_files: []str = find "*.c", dos +~ "/windows"; foreach f: win_files { files! +~= f; } } else if platform.os == "Mac OSX" && exists (dos +~ "/darwin") { darwin_files: []str = find "*.c", dos +~ "/darwin"; foreach f: darwin_files { files! +~= f; } } else { posix_files: []str = find "*.c", dos +~ "/posix"; foreach f: posix_files { if f contains "semaphore" { if (platform.os == "Mac OSX" && !(f contains "semaphore_darwin")) || (platform.os != "Mac OSX" && f contains "semaphore_darwin") { continue; } } files! +~= f; } } } } obj_files: []str = foreach f: files { add_c_file(f); }; return obj_files; } fn add_standalone_c_test(name: str, dep_list: []str) -> void { tst: str = add_exe(name, #[ name +~ ".c" ] +~ dep_list); test tst, #[ tst ]; } fn add_test_lib(name: str, dep_list: []str) -> str { obj: str = add_c_file(name +~ ".c"); return add_lib(name, dep_list +~ obj); } fn walk_test_dir(lib: str) -> []str { exes: ![]str = #[ ]; // TODO: Make this more efficient by creating lists that are common, like // lib by itself or lib and libcommon together. if config["extra_long_tests"] { add_standalone_c_test("tests/yc_memcpy", #[ lib ]); } // This keyword creates a target with the given name that copies a file from // the source directory to the build directory. It returns the name of the // target to use later. // // I did it this way so that targets that have the same name as both a // source and a target won't clash. // // `configure_file` does something similar, but it configures a file as // well. There will also be a `copy_dir` keyword. words: str = copy_file "tests/words.txt"; strgen: str = add_exe("tests/strgen.c", #[ lib ]); libiterator: str = add_test_lib("tests/iterator_tests", #[ lib ]); libcommon: str = add_test_lib("tests/common", #[ lib ]); dirs: []str = find_dirs "tests"; foreach d: dirs { if d contains "container" { if config["long_tests"] { kjvbiblec: str = "kjvbible.c"; target kjvbiblec: strgen, "kjvbible.txt" { $ @(deps[0]) @(deps[1]) @tgt "kjvbible_array" 1; } kjvbible: str = add_lib(d +~ "/" +~ "kjvbible", #[ ]); add_standalone_c_test(d +~ "/map_countwords", #[ kjvbible, lib, libcommon ]); add_standalone_c_test(d +~ "/map_stress", #[ lib, libcommon ]); add_standalone_c_test(d +~ "/nvec_stress", #[ lib, libcommon ]); } plain_tests: []str = #[ "map_all", "array_all", "vec_push", "vec_npush", "vec_pop", "vec_npop", "vec_add", "vec_nadd", "vec_remove", "vec_nremove", "vec_setcap", "vec_setlen", "vec_stress", "vec_copy", "svec_push", "svec_npush", "svec_pop", "svec_npop", "stack_all", "treevec_all", ]; foreach t: plain_tests { if t == "vec_stress" || t == "map_all" { add_standalone_c_test(d +~ "/" +~ t, #[ lib, libcommon, words ]); } else { add_standalone_c_test(d +~ "/" +~ t, #[ lib, libcommon ]); } } nvec_tests: []str = #[ "nvec_push", "nvec_npush", "nvec_pop", "nvec_npop", "nvec_add", "nvec_nadd", "nvec_remove", "nvec_nremove", "nvec_setcap", "nvec_setlen", "nvec_copy", ]; libnvec: str = add_test_lib(d +~ "/nvec_tests", #[ lib, libcommon ]); foreach t: nvec_tests { add_standalone_c_test(d +~ "/" +~ t, #[ lib, libcommon, libnvec ]); } tree_tests: []str = #[ "tree_add", "tree_remove", "tree_removeAll", "tree_copy", "tree_empty", "tree_iterator", ]; libtree: str = add_test_lib(d +~ "/tree_tests", #[ lib ]); foreach t: tree_tests { if t == "tree_iterator" { add_standalone_c_test(d +~ "/" +~ t, #[ lib, libcommon, libtree, libiterator ]); } else { add_standalone_c_test(d +~ "/" +~ t, #[ lib, libcommon, libtree ]); } } ntree_tests: [] str = #[ "ntree_add", "ntree_remove", "ntree_copy", "ntree_empty", "ntree_iterator", ]; libntree: str = add_test_lib(d +~ "/ntree_tests", #[ lib ]); foreach t: ntree_tests { if t == "ntree_iterator" { add_standalone_c_test(d +~ "/" +~ t, #[ lib, libcommon, libntree, libiterator ]); } else { add_standalone_c_test(d +~ "/" +~ t, #[ lib, libcommon, libntree ]); } } } else if d contains "arith" { if config["long_tests"] { add_standalone_c_test(d +~ "/arith_sn", #[ lib, libcommon ]); add_standalone_c_test(d +~ "/arith_slt", #[ lib, libcommon ]); add_standalone_c_test(d +~ "/arith_sle", #[ lib, libcommon ]); add_standalone_c_test(d +~ "/arith_sgt", #[ lib, libcommon ]); add_standalone_c_test(d +~ "/arith_sge", #[ lib, libcommon ]); } add_standalone_c_test(d +~ "/arith_sshr", #[ lib, libcommon ]); add_standalone_c_test(d +~ "/arith_ushr", #[ lib, libcommon ]); } else if d contains "str" { add_standalone_c_test(d +~ "/string_all", #[ lib, libcommon ]); } else if d contains "io" { add_standalone_c_test(d +~ "/fs_open", #[ lib, libcommon ]); add_standalone_c_test(d +~ "/fs_read", #[ lib, libcommon, words ]); add_standalone_c_test(d +~ "/fs_unicode", #[ lib, libcommon ]); } else if d contains "gaml" { exes! +~= add_exe_by_name(d +~ "/gaml_fuzz_parse", #[ lib, libcommon ]); exes! +~= add_exe_by_name(d +~ "/gaml_fuzz_edit", #[ lib, libcommon ]); } else if d contains "alloc" { add_standalone_c_test(d +~ "/mappool_all", #[ lib, libcommon ]); } else if d contains "util" { libhashobj: str = add_c_file(d +~ "/hash_tests.c"); libhash: str = add_lib(d +~ "/hash_tests", #[ libhashobj, lib]); add_standalone_c_test(d +~ "/hash_results", #[ lib, libcommon, libhash ]); add_standalone_c_test(d +~ "/hash_alignment", #[ lib, libcommon, libhash ]); add_standalone_c_test(d +~ "/hash_pieces", #[ lib, libcommon, libhash ]); if config["extra_long_tests"] { add_standalone_c_test(d +~ "/hash_deltas", #[ lib, libcommon, libhash ]); } } else { error "Unhandled test directory: " +~ d; } } return exes; }