Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ everywhere and reports a by-value out-parameter whose write nobody can read.

**Minimize `unsafe`:** most `unsafe(reinterpret<T?>)` in macro code exists to strip `const` from raw-pointer field access - fix the root cause by making the function parameter `var`, so field access returns non-const pointers. Reserve `unsafe` for genuinely unsafe operations (pointer arithmetic, `reinterpret` across unrelated types).

**`print` is for user-facing scripts only.** In `tests/`, `daslib/`, `utils/` use `to_log(LOG_INFO|LOG_WARNING|LOG_ERROR)` - same stdout, but level-tagged and filterable. Canonical example: `utils/detect-dupe/main.das`.
**`print` is for user-facing scripts only.** In `tests/`, `daslib/`, `utils/` use `to_log(LOG_INFO|LOG_WARNING|LOG_ERROR)` - level-tagged and filtered by `DAS_LOG_LEVEL` (default `warning`, so `LOG_INFO` lines print only under `DAS_LOG_LEVEL=info`). Canonical example: `utils/detect-dupe/main.das`.

**Complexity/length lint (STYLE037/STYLE038): new code meets both limits from the start.** On a hit in existing code, the suppress-vs-split resolution policy is `skills/style_lint.md` - never force a split on an honest shape.

Expand Down
18 changes: 17 additions & 1 deletion ci/test_render_manifests.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ def fake_sha(asset):
return hashlib.sha256(asset.encode()).hexdigest()


def git_bash():
"""The bash the release workflows' `shell: bash` runs - Git's on Windows, where a bare
`bash` from Python resolves to System32's WSL launcher first."""
if os.name != "nt":
return shutil.which("bash")
git = shutil.which("git")
root = os.path.dirname(git) if git else ""
while root and os.path.dirname(root) != root:
candidate = os.path.join(root, "bin", "bash.exe")
if os.path.isfile(candidate):
return candidate
root = os.path.dirname(root)
return None


class RenderManifestsTest(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.mkdtemp()
Expand Down Expand Up @@ -105,14 +120,15 @@ def test_malformed_sha_is_fatal(self):
with self.assertRaises(SystemExit):
rm.render_package("daslang", "v0.6.5", self.sha, self.out)

@unittest.skipUnless(git_bash(), "no bash to run checksum_assets.sh")
def test_checksum_script_writes_what_the_render_reads(self):
here = os.path.join(os.path.dirname(os.path.abspath(__file__)), "packaging")
for a in ASSETS["dasllama"]:
with open(os.path.join(self.sha, a), "w") as f:
f.write(a)
with open(os.path.join(self.sha, "stale.sha256"), "w") as f:
f.write("left alone\n")
subprocess.run(["bash", os.path.join(here, "checksum_assets.sh"), self.sha], check=True, capture_output=True)
subprocess.run([git_bash(), os.path.join(here, "checksum_assets.sh"), self.sha], check=True, capture_output=True)
self.assertFalse(os.path.exists(os.path.join(self.sha, "stale.sha256.sha256")), "a .sha256 is never summed")
rm.render_package("dasllama", "v0.6.5", self.sha, self.out)
bucket = json.loads(self.read("scoop-daslang/bucket/dasllama.json"))
Expand Down
2 changes: 2 additions & 0 deletions modules/dasHV/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,14 @@ IF ((NOT DAS_HV_INCLUDED) AND ((NOT ${DAS_HV_DISABLED}) OR (NOT DEFINED DAS_HV_D
URL https://github.com/ithewei/libhv/archive/5da5fc22cdfd1b59ba2b0520abb34f95d050975c.tar.gz
URL_HASH SHA256=b4f774936ccd6981df74b23f9e033e0b3ab584f6682d889490377dc9450b5f54
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
PATCH_COMMAND ${CMAKE_COMMAND} -DLIBHV_SRC_DIR=<SOURCE_DIR> -P ${DAS_HV_DIR}/patch_libhv.cmake
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libhv
CMAKE_ARGS ${HV_CMAKE_FLAGS}
BUILD_BYPRODUCTS ${HV_LIBRARIES}
BUILD_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --config $<CONFIG>
INSTALL_COMMAND ${CMAKE_COMMAND} --install <BINARY_DIR> --config $<CONFIG> --prefix ${DAS_HV_DIR}/hv/$<CONFIG>
)
ExternalProject_Add_StepDependencies(LIBHV patch ${DAS_HV_DIR}/patch_libhv.cmake)
# Copy cert files from downloaded libhv source (not stored in repo to avoid pushing private keys)
SET(LIBHV_SRC_DIR ${CMAKE_CURRENT_BINARY_DIR}/libhv/src/LIBHV)
ExternalProject_Add_Step(LIBHV copy_certs
Expand Down
85 changes: 85 additions & 0 deletions modules/dasHV/patch_libhv.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Apply the libhv fixes this tree carries on top of the pinned tarball; each one is dropped when the
# pin moves past its upstream merge. The first run saves each file as <file>.das_pristine, and every
# run patches from that copy - so re-running, or editing a hunk here, rebuilds the file from the
# tarball's text. A pristine anchor that is missing fails the build: a pin bump that touched the
# patched code re-decides the patch, it never builds unpatched.
#
# base/hlog.c - logger_set_file closes the open log file, so a later hlog_set_file switches files
# instead of writing to the old one until the date changes (ithewei/libhv#892).
#
# Usage: cmake -DLIBHV_SRC_DIR=<libhv source dir> -P patch_libhv.cmake

if(NOT LIBHV_SRC_DIR)
message(FATAL_ERROR "patch_libhv.cmake: pass -DLIBHV_SRC_DIR=<libhv source dir>")
endif()

function(das_hv_patch_begin file)
set(path "${LIBHV_SRC_DIR}/${file}")
if(NOT EXISTS "${path}.das_pristine")
configure_file("${path}" "${path}.das_pristine" COPYONLY)
endif()
file(READ "${path}.das_pristine" src)
set(das_hv_file "${file}" PARENT_SCOPE)
set(das_hv_src "${src}" PARENT_SCOPE)
endfunction()

function(das_hv_hunk pristine patched)
string(FIND "${das_hv_src}" "${pristine}" at)
if(at EQUAL -1)
string(REGEX MATCH "^[^\n]*" first_line "${pristine}")
string(STRIP "${first_line}" first_line)
message(FATAL_ERROR "patch_libhv.cmake: ${das_hv_file} no longer carries the pristine anchor "
"'${first_line}' - the libhv pin changed this code; re-decide the patch in modules/dasHV/patch_libhv.cmake")
endif()
string(REPLACE "${pristine}" "${patched}" src "${das_hv_src}")
set(das_hv_src "${src}" PARENT_SCOPE)
endfunction()

function(das_hv_patch_end)
file(WRITE "${LIBHV_SRC_DIR}/${das_hv_file}" "${das_hv_src}")
message(STATUS "patch_libhv.cmake: patched ${das_hv_file}")
endfunction()

das_hv_patch_begin("base/hlog.c")
das_hv_hunk([=[
logger_set_file(logger, DEFAULT_LOG_FILE);
logger->last_logfile_ts = 0;
logger->can_write_cnt = -1;
hmutex_init(&logger->mutex_);
]=] [=[
logger->last_logfile_ts = 0;
logger->can_write_cnt = -1;
hmutex_init(&logger->mutex_);
logger_set_file(logger, DEFAULT_LOG_FILE);
]=])
das_hv_hunk([=[
void logger_set_file(logger_t* logger, const char* filepath) {
strncpy(logger->filepath, filepath, sizeof(logger->filepath) - 1);
// remove suffix .log
char* suffix = strrchr(logger->filepath, '.');
if (suffix && strcmp(suffix, ".log") == 0) {
*suffix = '\0';
}
}
]=] [=[
void logger_set_file(logger_t* logger, const char* filepath) {
hmutex_lock(&logger->mutex_);
strncpy(logger->filepath, filepath, sizeof(logger->filepath) - 1);
logger->filepath[sizeof(logger->filepath) - 1] = '\0';
// remove suffix .log
char* suffix = strrchr(logger->filepath, '.');
if (suffix && strcmp(suffix, ".log") == 0) {
*suffix = '\0';
}
// close the current logfile, the next write opens the new one
if (logger->fp_) {
fclose(logger->fp_);
logger->fp_ = NULL;
}
logger->cur_logfile[0] = '\0';
logger->last_logfile_ts = 0;
logger->can_write_cnt = -1;
hmutex_unlock(&logger->mutex_);
}
]=])
das_hv_patch_end()
2 changes: 1 addition & 1 deletion modules/dasLLAMA/dasllama/dasllama_fat_start.das
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module dasllama_fat_start shared private

require dasllama/dasllama_lint public
require dasllama/dasllama_common
require dasllama/dasllama_env // dasllama_home_dir - where a fat exe keeps its sidecar
require dasllama/dasllama_env // nolint:STYLE030 - dasllama_home_dir, used only inside the llvm_tune static_if half
require daslib/fio
require dasllama/dasllama_math // the runtime knob getters the snapshot records
require dasllama/dasllama_par // get_total_hw_jobs - the advisory "threads" entry
Expand Down
2 changes: 1 addition & 1 deletion skills/internal/writing_cpp_tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Rebuild - `cmake --build build`. The new test appears in `ctest -N` automaticall

## Adding a big test

A "big" test is anything the single doctest exe can't host: a custom `int main()` (C++ or C), custom link deps, multiple link variants (static + dynamic), or no compiled source at all - `big/style_lint/` is just a `CMakeLists.txt` that registers ctest entries running a daslang script with a `PASS_REGULAR_EXPRESSION`. What makes it "big" is owning its own CMakeLists. The ctest LABEL, not the folder, decides which lane runs it: the default is `LABELS "big"` with `add_dependencies(test-big <exe>)`. A dir that must run on every PR carries `LABELS "small"` with `add_dependencies(test-small <exe>)` instead, so the local small run builds it. Ledgered small-labelled dir: `big/vecmath_backend/` - its scalar arm compiles vecmath with a different `vec4f` than libDaScript was built with, so it cannot link libDaScript and cannot join the small glob exe. The canonical C++ example is `tests-cpp/big/concurrent_init/` - it has a thread-startup-barrier harness and is built as both `test_concurrent_init` (static) and `test_concurrent_init_dyn` (dynamic).
A "big" test is anything the single doctest exe can't host: a custom `int main()` (C++ or C), custom link deps, multiple link variants (static + dynamic), or no compiled source at all - `big/style_lint/` is just a `CMakeLists.txt` that registers ctest entries running a daslang script with a `PASS_REGULAR_EXPRESSION`. What makes it "big" is owning its own CMakeLists. The ctest LABEL, not the folder, decides which lane runs it: the default is `LABELS "big"` with `add_dependencies(test-big <exe>)`. A dir that must run on every PR carries `LABELS "small"` with `add_dependencies(test-small <exe>)` instead, so the local small run builds it; a dir whose tests only run `${CMAKE_COMMAND}` or `${CMAKE_CTEST_COMMAND}` and that declares no target builds nothing and wires nothing (`big/dashv_patch_libhv/`). Ledgered small-labelled dir: `big/vecmath_backend/` - its scalar arm compiles vecmath with a different `vec4f` than libDaScript was built with, so it cannot link libDaScript and cannot join the small glob exe. The canonical C++ example is `tests-cpp/big/concurrent_init/` - it has a thread-startup-barrier harness and is built as both `test_concurrent_init` (static) and `test_concurrent_init_dyn` (dynamic).

To add one:

Expand Down
27 changes: 22 additions & 5 deletions tests-cpp/REVIEW.das
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,22 @@ def private check_source_property_paths(f : string; text : string) {
}
}

// Every lane a file labels tests into is a lane that file also builds for.
//! true only when every test runs cmake or ctest itself and the file declares no target or custom command - nothing a lane could leave stale
def private builds_nothing_for_its_tests(text : string) : bool {
var inscope commands <- cmake_test_commands(text)
var inscope tests <- cmake_command_blocks(text, "add_test")
return false if (empty(commands) || length(commands) != length(tests))
for (c in commands) {
return false if (c != "$\{CMAKE_COMMAND\}" && c != "$\{CMAKE_CTEST_COMMAND\}")
}
for (kind in ["add_executable", "add_library", "add_custom_target", "add_custom_command"]) {
var inscope declared <- cmake_command_blocks(text, kind)
return false if (!empty(declared))
}
return true
}

// A file whose tests run something it builds wires every lane it labels them into.
def private check_lane_wiring {
let top_cmake = "tests-cpp/CMakeLists.txt"
var inscope aggregate_lanes <- lanes_of(fread(top_cmake), "add_custom_target")
Expand All @@ -88,10 +103,12 @@ def private check_lane_wiring {
// a file that defines an aggregate wires its dependencies at the definition site
wired_lanes |> push_from(lanes_of(text, "add_custom_target"))
var inscope labels <- cmake_test_labels(text)
for (lab in labels) {
// a label with no test-<lane> target is a ctest filter — nothing to wire to
continue if (find_index(aggregate_lanes, lab) < 0 || find_index(wired_lanes, lab) >= 0)
gate_finding(f, "labels a test \"{lab}\" but wires nothing into test-{lab} — wire it with add_dependencies(test-{lab} <target>), or the lane runs a binary it never built")
if (!builds_nothing_for_its_tests(text)) {
for (lab in labels) {
// a label with no test-<lane> target is a ctest filter — nothing to wire to
continue if (find_index(aggregate_lanes, lab) < 0 || find_index(wired_lanes, lab) >= 0)
gate_finding(f, "labels a test \"{lab}\" but wires nothing into test-{lab} — wire it with add_dependencies(test-{lab} <target>), or the lane runs a binary it never built")
}
}
check_test_targets(f, text)
check_source_property_paths(f, text)
Expand Down
7 changes: 7 additions & 0 deletions tests-cpp/REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ subfolder's checklist as well as this one.**
builds, registers, or runs - a doctest skip, a `#if` a configuration leaves undefined, a CMake
gate on a build option - names in the PR one configuration that does run that test: its
configure flags and its ctest command.**

**A diff to `check_lane_wiring` or `builds_nothing_for_its_tests` in `REVIEW.das` keeps the gate
reporting every `CMakeLists.txt` under this folder that labels a test into a `test-<lane>` target
the top `CMakeLists.txt` defines, neither defines that target nor names it in
`add_dependencies(test-<lane> ...)`, and builds something for its tests - a test whose command is
not `${CMAKE_COMMAND}` or `${CMAKE_CTEST_COMMAND}`, or an `add_executable`, `add_library`,
`add_custom_target` or `add_custom_command`.**
11 changes: 11 additions & 0 deletions tests-cpp/big/dashv_patch_libhv/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# modules/dasHV/patch_libhv.cmake over a fixture of the two hlog.c passages it anchors on. Labelled
# small: one cmake -P over a two-passage fixture, so every per-PR ctest runs it.

add_test(
NAME dashv_patch_libhv
COMMAND ${CMAKE_COMMAND}
-DPATCH_SCRIPT=${PROJECT_SOURCE_DIR}/modules/dasHV/patch_libhv.cmake
-DFIXTURE=${CMAKE_CURRENT_SOURCE_DIR}/pristine_hlog.c
-DWORK_DIR=${CMAKE_CURRENT_BINARY_DIR}/work
-P ${CMAKE_CURRENT_SOURCE_DIR}/test_patch_libhv.cmake)
set_tests_properties(dashv_patch_libhv PROPERTIES LABELS "small")
16 changes: 16 additions & 0 deletions tests-cpp/big/dashv_patch_libhv/pristine_hlog.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
static void logger_init(logger_t* logger) {
logger->enable_fsync = 1;
logger_set_file(logger, DEFAULT_LOG_FILE);
logger->last_logfile_ts = 0;
logger->can_write_cnt = -1;
hmutex_init(&logger->mutex_);
}

void logger_set_file(logger_t* logger, const char* filepath) {
strncpy(logger->filepath, filepath, sizeof(logger->filepath) - 1);
// remove suffix .log
char* suffix = strrchr(logger->filepath, '.');
if (suffix && strcmp(suffix, ".log") == 0) {
*suffix = '\0';
}
}
78 changes: 78 additions & 0 deletions tests-cpp/big/dashv_patch_libhv/test_patch_libhv.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Drives modules/dasHV/patch_libhv.cmake over pristine_hlog.c: a fresh run patches and saves the
# pristine copy, a re-run rebuilds from that copy, a drifted anchor and a missing source dir fail.
#
# Usage: cmake -DPATCH_SCRIPT=<patch_libhv.cmake> -DFIXTURE=<pristine_hlog.c> -DWORK_DIR=<dir> -P test_patch_libhv.cmake

function(stage case_dir fixture_text)
file(REMOVE_RECURSE "${case_dir}")
file(WRITE "${case_dir}/base/hlog.c" "${fixture_text}")
endfunction()

function(run_patch src_dir out_rc out_log)
if(src_dir STREQUAL "")
execute_process(COMMAND ${CMAKE_COMMAND} -P ${PATCH_SCRIPT}
RESULT_VARIABLE rc OUTPUT_VARIABLE out ERROR_VARIABLE err)
else()
execute_process(COMMAND ${CMAKE_COMMAND} -DLIBHV_SRC_DIR=${src_dir} -P ${PATCH_SCRIPT}
RESULT_VARIABLE rc OUTPUT_VARIABLE out ERROR_VARIABLE err)
endif()
set(${out_rc} "${rc}" PARENT_SCOPE)
set(${out_log} "${out}${err}" PARENT_SCOPE)
endfunction()

function(fail message)
message(FATAL_ERROR "test_patch_libhv: ${message}")
endfunction()

file(READ "${FIXTURE}" pristine)

set(fresh "${WORK_DIR}/fresh")
stage("${fresh}" "${pristine}")
run_patch("${fresh}" rc log)
if(NOT rc EQUAL 0)
fail("a fresh run fails: ${log}")
endif()
file(READ "${fresh}/base/hlog.c" patched)
file(READ "${fresh}/base/hlog.c.das_pristine" saved)
if(NOT saved STREQUAL pristine)
fail("the saved copy is not the file the run found")
endif()
string(FIND "${patched}" "hmutex_init(&logger->mutex_);\n logger_set_file(logger, DEFAULT_LOG_FILE);" at_init)
if(at_init EQUAL -1)
fail("logger_init does not initialize the mutex before logger_set_file")
endif()
string(FIND "${patched}" "fclose(logger->fp_);" at_close)
if(at_close EQUAL -1)
fail("logger_set_file does not close the open log file")
endif()

run_patch("${fresh}" rc log)
file(READ "${fresh}/base/hlog.c" rerun)
if(NOT rc EQUAL 0 OR NOT rerun STREQUAL patched)
fail("a re-run fails or changes the patched file: ${log}")
endif()

file(WRITE "${fresh}/base/hlog.c" "a file an older patch left behind\n")
run_patch("${fresh}" rc log)
file(READ "${fresh}/base/hlog.c" rebuilt)
if(NOT rc EQUAL 0 OR NOT rebuilt STREQUAL patched)
fail("a re-run does not rebuild from the saved pristine copy: ${log}")
endif()

set(drift "${WORK_DIR}/drift")
string(REPLACE "hmutex_init(&logger->mutex_);" "hmutex_init(&logger->lock_);" drifted "${pristine}")
stage("${drift}" "${drifted}")
run_patch("${drift}" rc log)
string(FIND "${log}" "no longer carries the pristine anchor" at_msg)
if(rc EQUAL 0 OR at_msg EQUAL -1)
fail("a drifted anchor builds, or fails without naming it: ${log}")
endif()

run_patch("" rc log)
string(FIND "${log}" "-DLIBHV_SRC_DIR" at_usage)
if(rc EQUAL 0 OR at_usage EQUAL -1)
fail("a run with no source dir succeeds, or fails without its usage: ${log}")
endif()

file(REMOVE_RECURSE "${WORK_DIR}")
message(STATUS "test_patch_libhv: all cases passed")
5 changes: 5 additions & 0 deletions tests-cpp/small/test_seqbox_concurrent_writers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,13 @@ TEST_CASE("seq box survives concurrent writers") {
}
});

const auto landingDeadline = std::chrono::steady_clock::now() + std::chrono::seconds(10);
start.store(true, std::memory_order_release);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
while ((published.load(std::memory_order_relaxed) == 0 || reads.load(std::memory_order_relaxed) == 0)
&& std::chrono::steady_clock::now() < landingDeadline) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
stop.store(true, std::memory_order_relaxed);
publisherA.join(); publisherB.join(); clearer.join(); reader.join();

Expand Down
12 changes: 12 additions & 0 deletions utils/common/log_floor.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
options gen2

module log_floor

require daslib/fio

def public default_log_floor_to_info() {
//! to_log drops records below DAS_LOG_LEVEL (default warning); an unset floor becomes info, for this process and the programs it starts
if (empty(get_env_variable("DAS_LOG_LEVEL"))) {
set_env_variable("DAS_LOG_LEVEL", "info")
}
}
4 changes: 3 additions & 1 deletion utils/internal/make-pr/main.das
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require daslib/defer
require daslib/strings_boost
require daslib/json_boost
require gates
require ../../common/log_floor.das

[CommandLineArgs]
struct Config {
Expand Down Expand Up @@ -293,6 +294,7 @@ def private want(gate : string) : bool {

[export]
def main() : int {
default_log_floor_to_info()
let rc = parse_args_with_help(g_cfg, "make-pr")
return rc if (rc >= 0)
let bad <- unknown_gate_names(g_cfg.only, g_cfg.skip)
Expand Down Expand Up @@ -321,7 +323,7 @@ def main() : int {
var out = ""
let code = run([daslang, "utils/internal/preflight/main.das", "--", "--full"], out, 7200.0)
if (code != 0) {
to_log(LOG_ERROR, out) //! the run's own gate lines, at the level the default log floor lets through
to_log(LOG_ERROR, out)
to_log(LOG_ERROR, "preflight --full failed - fix each, validate with the TARGETED gate, never a second full run\n")
return 2
}
Expand Down
Loading
Loading