Skip to content
Open
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
54 changes: 54 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,60 @@ jobs:
retention-days: 1
if-no-files-found: error

# -----------------------------------------------------------------------
# build-windows: the same build under MSVC.
#
# Everything else in this file is ubuntu-only, so nothing here has ever
# compiled with MSVC, and portability breaks land silently: __attribute__,
# naming an automatic constexpr from a captureless lambda, and POSIX-only
# calls all build clean on gcc and stop MSVC on the first file.
#
# CPU only, no model downloads — this guards the compile, not the numbers,
# which the ubuntu smoke-test job already covers. GGML_NATIVE=ON matches the
# ubuntu build job: CI only has to run on its own runner.
# -----------------------------------------------------------------------
build-windows:
name: Build & unit tests (MSVC)
runs-on: windows-2022
timeout-minutes: 30
steps:
- name: Checkout (with submodules)
uses: actions/checkout@v4
with:
submodules: recursive

# The CMake configure-time hook shells out to bash, which is not on PATH
# in the MSVC environment; run it explicitly first.
- name: Apply ggml patches (Git Bash)
shell: bash
run: bash scripts/apply_ggml_patches.sh

- name: MSVC environment
uses: ilammy/msvc-dev-cmd@v1

- name: Configure CMake
shell: bash
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DRFDETR_BUILD_TESTS=ON \
-DRFDETR_BUILD_CLI=ON \
-DGGML_NATIVE=ON

- name: Build
shell: bash
run: cmake --build build -j

- name: Run unit tests
shell: bash
run: ctest --test-dir build --output-on-failure

- name: Usage banner
shell: bash
run: |
out=$(./build/bin/rfdetr-cli.exe 2>&1 || true)
grep -qi usage <<<"$out"

# -----------------------------------------------------------------------
# smoke-test: download nano (all 4 quants) + base-f16 from HF, run detect
# on a committed test image, compare JSON output against committed refs.
Expand Down
18 changes: 11 additions & 7 deletions examples/cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <system_error>
#include <sstream>
#include <string>
#include <sys/stat.h>
Expand Down Expand Up @@ -131,13 +133,15 @@ static int cmd_detect(const rfdetr_cli::DetectArgs& a) {

/* 7. Optional per-detection mask PNGs (seg models only). */
if (!a.masks_dir.empty()) {
/* Create the masks directory if it doesn't exist. */
struct stat st_buf;
if (::stat(a.masks_dir.c_str(), &st_buf) != 0) {
if (::mkdir(a.masks_dir.c_str(), 0755) != 0) {
std::fprintf(stderr, "failed to create masks dir '%s'\n",
a.masks_dir.c_str());
}
/* Create the masks directory if it doesn't exist. std::filesystem
* rather than stat + ::mkdir: MSVC has no POSIX mkdir (only _mkdir,
* in <direct.h>), and create_directories already succeeds silently
* when the directory is there, so the stat probe goes with it. */
std::error_code mkdir_ec;
std::filesystem::create_directories(a.masks_dir, mkdir_ec);
if (mkdir_ec) {
std::fprintf(stderr, "failed to create masks dir '%s'\n",
a.masks_dir.c_str());
}
size_t n_written = 0;
for (size_t i = 0; i < n; ++i) {
Expand Down
13 changes: 12 additions & 1 deletion src/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,19 @@
* in tests without needing to include this header. */
void rfdetr_internal_log(rfdetr_log_level lvl, const char* msg);

/* Format-string checking where the compiler offers it. MSVC does not
* understand __attribute__, and MinGW's printf is the gnu_printf dialect —
* the same three cases ggml.h handles with GGML_ATTRIBUTE_FORMAT. */
#ifndef __GNUC__
# define RFDETR_ATTRIBUTE_FORMAT(...)
#elif defined(__MINGW32__) && !defined(__clang__)
# define RFDETR_ATTRIBUTE_FORMAT(...) __attribute__((format(gnu_printf, __VA_ARGS__)))
#else
# define RFDETR_ATTRIBUTE_FORMAT(...) __attribute__((format(printf, __VA_ARGS__)))
#endif

/* printf-style wrapper. Builds the string then dispatches. */
void rfdetr_logf(rfdetr_log_level lvl, const char* fmt, ...)
__attribute__((format(printf, 2, 3)));
RFDETR_ATTRIBUTE_FORMAT(2, 3);

#endif
5 changes: 4 additions & 1 deletion src/model_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ bool get_bool(gguf_context* g, const char* key, bool& out) {
* with A = -0.5 for antialias=True. */
void bicubic_resample_patch_grid(const float* src, int src_side, int dim,
float* dst, int dst_side) {
constexpr float A = -0.5f; // antialias=True path uses Keys, not Catmull-Rom
/* `static` so the captureless lambda below can name it: MSVC rejects an
* automatic constexpr there (C3493) where gcc/clang accept it. Static
* storage duration needs no capture, and is portable. */
static constexpr float A = -0.5f; // antialias=True path uses Keys, not Catmull-Rom
auto kernel = [](float x) -> float {
const float ax = std::fabs(x);
if (ax < 1.0f) {
Expand Down
5 changes: 4 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ rfdetr_add_test(test_visualize)

rfdetr_add_test(test_cli_smoke)

if(TARGET rfdetr-cli)
# test_cli_integration drives the CLI as a child process through <sys/wait.h>,
# so it is POSIX-only. Everything else in this directory is portable; excluding
# just this one keeps the rest of the suite running under MSVC.
if(TARGET rfdetr-cli AND NOT WIN32)
rfdetr_add_test(test_cli_integration)
target_compile_definitions(test_cli_integration PRIVATE
RFDETR_CLI_BINARY="$<TARGET_FILE:rfdetr-cli>")
Expand Down
Loading