Skip to content

Add rawspeed-cli utility with MSVC build support and tag-based publish CI - #1

Merged
Abas-Tim merged 24 commits into
developfrom
msvc-win
Sep 6, 2026
Merged

Abas-Tim merged 24 commits into
developfrom
msvc-win

Conversation

@Abas-Tim

@Abas-Tim Abas-Tim commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Summary

Consolidates the fork's MSVC/Windows work from the msvc-win branch into develop:

  • MSVC compatibility
    • MSVC versions of the RAWSPEED_* attribute macros; guard printf-format attribute on writeLog
    • explicit Array1DRef template arguments in LJpegDecompressor / DNG slice handling
  • Offline in-tree builds
    • vendor pugixml and zlib (madler zlib 1.3.1, replacing zlib-ng) for offline in-tree builds
    • tolerate zlib-ng alias targets in the bundled zlib module; stop tracking generated zconf.h
  • New rawspeed-cli utility
    • decodes a raw file via librawspeed, demosaics 16-bit Bayer CFA images
      (multithreaded weighted-average interpolation, gray-world white balance),
      writes a PPM (16-bit default; optional 8 flag for 8-bit)
    • msvc_compat.h (force-included via /FI) shims GCC-only builtins
      (__attribute__, __PRETTY_FUNCTION__, __builtin_unreachable,
      __builtin_{sadd,mul}_overflow) for MSVC
    • compiler-flags.cmake: /EHsc on MSVC; -O0/-O3 appends limited to non-MSVC
    • debug-info.cmake: /Zi + /DEBUG on MSVC; GCC-only debug flags guarded
    • gated by the existing BUILD_TOOLS option like the other utilities
  • Publish CI (.github/workflows/rawspeed-cli.yml)
    • triggers on rawspeed-cli-v* tags; builds from this repository
    • stricter smoke test (requires exit code 2 + usage output)
    • release tag validation; packages exe + DLLs into a zip with SHA256 checksum;
      replaces existing release assets idempotently via the REST API

Verification

  • Configured and built the rawspeed-cli target with MSVC (VS 18, Release): OK
  • Smoke test (no args -> usage printed, exit code 2): OK

Notes

  • Prepared with AI assistance (opencode), per AGENTS.md disclosure rules

RAWSPEED_UNLIKELY_FUNCTION, RAWSPEED_NOINLINE, RAWSPEED_READONLY,
RAWSPEED_READNONE and RAWSPEED_ALWAYS_INLINE map to __declspec/__forceinline
on MSVC instead of GCC attributes.
__attribute__((format(printf, 2, 3))) is not supported by MSVC; keep the
plain prototype when compiling with MSVC and not clang.
MSVC cannot deduce the element type from the braced expression in
Array1DRef(slices.data(), size) for the multi-threaded decompress paths.
Same MSVC deduction issue as AbstractDngDecompressor; name the element
type explicitly.
Third-party archive downloads are blocked on some networks, so the
build cannot rely on fetches. Vendor pugixml 1.14 (amalgamated sources,
minimal CMakeLists) and zlib-ng 2.2.1 under third_party/ and default
USE_BUNDLED_PUGIXML/USE_BUNDLED_ZLIB to ON so rawspeed's in-tree build
path points at PUGIXML_PATH/ZLIB_PATH = these trees.
zlib-ng exposes zlibstatic as an ALIAS target (compat mode), which cannot
have INTERFACE_SYSTEM_INCLUDE_DIRECTORIES set via set_target_properties.
Skip the property when the target is an alias; linking still works.
The bundled zlib path hardcodes zlib-src/zlib-build layout; zlib-ng
generates zconf.h in its binary dir. Use ZLIB_SOURCE_DIR/ZLIB_BINARY_DIR
from the generated zlib-paths.cmake.
zlib-ng 2.x defaults ZLIB_COMPAT=OFF, emitting zconf-ng.h instead of the
zlib-compatible zconf.h that rawspeed sources include.
zlib-ng 2.x hits MSVC 18 STL1003 in its C-toolset config and defaults to
non-compat headers; madler zlib matches the layout rawspeed's bundled
zlib module assumes (real zlibstatic target, zlib-compatible zconf.h).
The nested zlib build regenerates zconf.h into the source tree; it is a
build artifact and must not be tracked.
Builds the rawspeed-cli wrapper from RAWtoJXL's native/ workspace (which
pins this fork as its submodule) and uploads the win-x64 zip + checksum
to this fork's releases. Triggered manually with a version, by a
rawspeed-cli-v* tag, or weekly.
Avoids gh auth/version quirks by calling the releases API directly with
the Actions token; idempotent when the release already exists.
Add a minimal rawspeed-cli utility that decodes a raw file through
librawspeed, demosaics 16-bit Bayer CFA images (multithreaded
weighted-average interpolation with gray-world white balance) and
writes a PPM (16-bit by default, 8-bit with an optional "8" flag).

Make it build with MSVC:
- msvc_compat.h (force-included via /FI) shims GCC-only builtins
  (__attribute__, __PRETTY_FUNCTION__, __builtin_unreachable,
  __builtin_{sadd,mul}_overflow) for MSVC
- compiler-flags.cmake: add /EHsc for MSVC, guard -O0/-O3 appends to
  non-MSVC
- debug-info.cmake: use /Zi + /DEBUG on MSVC, guard GCC-only flags
  (-g3, -ggdb3, -gz, -gsplit-dwarf, gdb-index, -g0)

Rework the rawspeed-cli publish workflow:
- build from this repository instead of a RAWtoJXL checkout
- trigger only on rawspeed-cli-v* tags (drop dispatch + schedule)
- stricter smoke test: require exit code 2 and usage output
- validate release tag format, package exe + DLLs, and replace
  existing release assets idempotently via the REST API

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
USE_BUNDLED_PUGIXML / USE_BUNDLED_ZLIB now default to ON, but
PUGIXML_PATH / ZLIB_PATH still defaulted to /usr/src/{pugixml,zlib},
which only exists on distros with the library source packages
installed, so plain configure runs (e.g. the inherited CI matrix on
linux, macOS and MSYS2 runners) failed the in-tree setup with
"Did not find pugixml sources!".

Default both paths to the vendored in-tree copies
(third_party/pugixml-1.14, third_party/zlib-1.3.1) so bundled mode
works out of the box everywhere; explicit -DPUGIXML_PATH /
-DZLIB_PATH still override.

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
Reformat the rawspeed-cli utility sources and the hand-wrapped
Array1DRef<const DngSliceElement> loop headers in
AbstractDngDecompressor.cpp to satisfy the clang-format check
(LLVM style, verified with clang-format 18.1.8, the version used by
CI; formatting is idempotent).

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
The clang-format check formats every tracked file not matched by
.clang-format-ignore; the vendored third_party/pugixml-1.14 and
third_party/zlib-1.3.1 trees tracked for offline in-tree builds
should not be reformatted to the rawspeed style. Ignore the whole
third_party/ tree.

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
Clang builds rawspeed with -Weverything -Werror, which flagged the
rawspeed-cli sources (-Wunsafe-buffer-usage, -Wimplicit-int-float-
conversion, -Wdouble-promotion); MSVC does not enforce these, so the
utility built fine locally but failed the CI matrix.

- wrap argv in rawspeed::Array1DRef like the other utilities and drop
  all raw pointer arithmetic / C-array subscripts in favor of
  std::array::at(), std::vector::at() and rawspeed::Array1DRef
- make int->float and float->double conversions explicit
- verified with clang-format 18.1.8 and the exact CI warning flag set
  (-Weverything -Werror), and with an MSVC build + smoke test

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
The bundled zlib unconditionally builds its example/minigzip test
binaries and registers them with ctest. On linux/macOS those failed to
link (the shared lib target inherits the global hidden visibility
preset), and on MSYS2 the example64 ctest entry failed. rawspeed only
uses zlibstatic, so set ZLIB_BUILD_EXAMPLES=OFF for the in-tree zlib.

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
Comment thread src/utilities/rawspeed-cli/main.cpp Outdated
rawspeed::FileReader reader(argv(1));
auto [storage, buffer] = reader.readFile();
(void)storage;
rawspeed::RawParser parser(std::move(buffer));
Comment thread src/utilities/rawspeed-cli/main.cpp Outdated

std::array<float, 3> wb = {1.0F, 1.0F, 1.0F};
for (int c = 0; c < 3; ++c) {
if (cnt.at(c) > 0 && cnt.at(1) > 0 && sum.at(c) > 0.0 && sum.at(1) > 0.0)
Comment thread src/utilities/rawspeed-cli/main.cpp Outdated

const auto mosaic = raw->getU16DataAsCroppedArray2DRef().getAsArray2DRef();
const uint32_t w = static_cast<uint32_t>(mosaic.width());
const uint32_t h = static_cast<uint32_t>(mosaic.height());
Comment thread src/utilities/rawspeed-cli/main.cpp Outdated
}

const auto mosaic = raw->getU16DataAsCroppedArray2DRef().getAsArray2DRef();
const uint32_t w = static_cast<uint32_t>(mosaic.width());
Comment thread src/utilities/rawspeed-cli/main.cpp Outdated
}
}

static bool render(rawspeed::RawImage raw, std::vector<uint16_t>& rgbOut,
Comment thread src/utilities/rawspeed-cli/main.cpp Outdated
rawspeed::Array1DRef<uint16_t> rgb;
uint32_t rgbWidth;
uint32_t rgbHeight;
int patternCode;
Comment thread src/utilities/rawspeed-cli/main.cpp Outdated
rawspeed::Array2DRef<uint16_t> mosaic;
rawspeed::Array1DRef<uint16_t> rgb;
uint32_t rgbWidth;
uint32_t rgbHeight;
Comment thread src/utilities/rawspeed-cli/main.cpp Outdated
struct DemosaicJob {
rawspeed::Array2DRef<uint16_t> mosaic;
rawspeed::Array1DRef<uint16_t> rgb;
uint32_t rgbWidth;

struct DemosaicJob {
rawspeed::Array2DRef<uint16_t> mosaic;
rawspeed::Array1DRef<uint16_t> rgb;
using rawspeed::CFAColor;

struct DemosaicJob {
rawspeed::Array2DRef<uint16_t> mosaic;
The ClangTidy CI flavor fails when any TU has a clang-tidy finding;
rawspeed-cli/main.cpp was the only offender:
- directly include adt/Array1DRef.h / adt/Array2DRef.h
  (misc-include-cleaner)
- move file-local functions into an anonymous namespace instead of
  declaring them static (misc-use-anonymous-namespace)
- use in-class default member initializers (modernize-use-default-
  member-init) and auto for static_cast-initialized variables
  (modernize-use-auto)
- drop std::move() on a trivially-copyable Buffer
  (performance-move-const-arg) and take RawImage by const reference
  (performance-unnecessary-value-param)
- replace the nested conditional with a distance-to-weight lookup
  table (readability-avoid-nested-conditional-operator) and brace all
  single-statement if bodies (readability-braces-around-statements)

Verified locally with clang-tidy 20 on the exact CI check set (zero
findings), clang-format 18.1.8 idempotency, a strict -Weverything
-Werror clang syntax pass, and an MSVC build + smoke test.

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
msys2 now ships a clang that is new enough to warn about __COUNTER__
being a C2y extension under -Weverything -Werror, failing the
windows-msys2 CLANG64/CLANGARM64 jobs on pre-existing sources (test
and benchmark files). Disable -Wc2y-extensions for clang, matching
the existing -Wno-c++20-extensions treatment; older clangs ignore the
unknown flag.

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
CodeChecker fails against clang-21 because clang dropped
-dumpfullversion, which CodeChecker uses for analyzer version
detection ("clang: error: no input files"), breaking the
ClangStaticAnalysis and ClangCTUStaticAnalysis jobs regardless of the
code under analysis. Pin those two flavors to clang-19 until
CodeChecker gains support for newer clang.

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
The codecov uploader crashes while processing the gcov reports
(FileNotFoundError while resolving source paths recorded in the
reports), which fails the codecov job even though the coverage
collection itself succeeded. Coverage reporting is best-effort, so
stop treating upload failures as CI failures (fail_ci_if_error: false).

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
The repository is public, so all standard-runner usage is free, but
avoid pointless compute and keep the surface minimal:

- CI.yml / clang-format.yml: drop the `push` trigger for develop and
  stable; fork syncs would otherwise launch the full CI matrix. Pull
  request checks are unaffected and remain the merge gate.
- CI-rpuu.yml: drop the weekly cron schedule (upstream-specific
  masterset cache warmup); the workflow_call entry point used by CI
  stays intact.
- docs.yml: skip both jobs unless running on darktable-org/rawspeed;
  the schedule/dispatch entry points remain but are inert here.

AI assistance disclosure: prepared with AI assistance (opencode), per
AGENTS.md disclosure rules.
@Abas-Tim
Abas-Tim merged commit e59011d into develop Sep 6, 2026
52 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants