Skip to content

build: Add support building with msvc#59

Open
lygstate wants to merge 47 commits into
lvgl:masterfrom
lygstate:msvc
Open

build: Add support building with msvc#59
lygstate wants to merge 47 commits into
lvgl:masterfrom
lygstate:msvc

Conversation

@lygstate
Copy link
Copy Markdown

@lygstate lygstate commented May 10, 2026

        "-DCMAKE_PREFIX_PATH=C:/work/vcpkg/packages/zlib_x64-windows;C:/work/vcpkg/packages/curl_x64-windows;C:/work/vcpkg/packages/libffi_x64-windows;C:/work/vcpkg/packages/sdl2_x64-windows",
        "-DBUILD_LVGL_SIMULATOR=ON",
        "-DUSE_EXTERNAL_FFI=ON",
        "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>"

vcpkg install:

.\vcpkg.exe install curl zlib libffi sdl2 libffi:x64-windows-static

Summary by cubic

Add MSVC build support and a simulator screenshot API, upgrade txiki to v26.5.0, and expose LVGL constants to JS for more reliable cross‑platform builds.

  • New Features

    • MSVC support: C++23 on MSVC (C++14 elsewhere), /utf-8, WIN32_LEAN_AND_MEAN, Arc name clash resolved; new BUILD_LVGL_SIMULATOR=ON for simulator builds.
    • Simulator PNG capture: NativeRender.RenderUtil.captureDisplay(path) saves the current screen (simulator only); hides cursor/FPS during capture; added GUI test harness and CI that builds and runs tests on Linux/macOS/Windows.
    • LVGL constants in JS: NativeRender.lv_conf exposes compiled LVGL enums (parts/states, align, flex/grid, widget modes); UI now uses these (e.g., STYLE_TYPE.PART_MAIN, LVGL widget enums for Arc/Chart/Keyboard).
    • Headers/config: add deps/lvgl.h umbrella and split LVGL config into lv_conf_sim.h and lv_conf_device.h.
  • Bug Fixes

    • Harden QuickJS bindings: correct argc guards and declare real arities to avoid argv OOB reads; adapt to single‑arg JS_IsArray.
    • MSVC compatibility: explicit enum casts and separate lv_obj_add_flag calls fix build/runtime issues; remove zero‑length function tables.
    • Style/runtime fixes: correct style value types and animation duration order; initialize is_new; return JS_UNDEFINED from stopPropagation; pass ArrayBuffer for image/GIF data; resolve local asset paths with import.meta.dirname.
  • Dependencies

    • Bump txiki to v26.5.0 and @txikijs/types to ^26.5.0.
  • Migration

    • Install with vcpkg: .\vcpkg.exe install curl zlib libffi sdl2 libffi:x64-windows-static
    • Example CMake: -DBUILD_LVGL_SIMULATOR=ON -DUSE_EXTERNAL_FFI=ON -DCMAKE_PREFIX_PATH=C:/work/vcpkg/packages/zlib_x64-windows;C:/work/vcpkg/packages/curl_x64-windows;C:/work/vcpkg/packages/libffi_x64-windows;C:/work/vcpkg/packages/sdl2_x64-windows -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>

Written for commit ee1314b. Summary will update on new commits.

Review in cubic

Closes: #57

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 45 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/engine/hal/simulator/simulator.cpp">

<violation number="1" location="src/engine/hal/simulator/simulator.cpp:3">
P1: Wrapping `LV_IMG_DECLARE(mouse_cursor_icon)` in `extern "C"` creates a C-linkage reference, but `mouse_cursor_icon.c` is compiled with the C++ compiler in this build, so the definition will not match and linking can fail.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/render/native/components/roller/roller_wrap.cpp Outdated
Comment thread src/render/native/components/dropdownlist/dropdownlist_wrap.cpp Outdated
Comment on lines +3 to +7
extern "C" {

LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image file.*/

}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Wrapping LV_IMG_DECLARE(mouse_cursor_icon) in extern "C" creates a C-linkage reference, but mouse_cursor_icon.c is compiled with the C++ compiler in this build, so the definition will not match and linking can fail.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/engine/hal/simulator/simulator.cpp, line 3:

<comment>Wrapping `LV_IMG_DECLARE(mouse_cursor_icon)` in `extern "C"` creates a C-linkage reference, but `mouse_cursor_icon.c` is compiled with the C++ compiler in this build, so the definition will not match and linking can fail.</comment>

<file context>
@@ -1,5 +1,11 @@
 #include "./simulator.hpp"
 
+extern "C" {
+
+LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image file.*/
</file context>
Suggested change
extern "C" {
LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image file.*/
}
LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image file.*/

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You were wrong about mouse_cursor_icon.c, the compiler for mouse_cursor_icon.c is default to c, that's why I use
extern "C"

Comment thread src/render/native/components/line/line_wrap.cpp Outdated
Comment thread src/render/native/components/calendar/calendar_wrap.cpp Outdated
@lygstate
Copy link
Copy Markdown
Author

I create a fork https://github.com/lvgljs/lvgljs to get this merged

lygstate added 26 commits June 1, 2026 20:01
- Add RenderUtil.captureDisplay for simulator PNG export
- Add GUI test harness scripts for screenshot workflows
- Hide FPS/memory monitors and mouse cursor during capture
Add lv_bindings_js.h as a single entry point for lvgl, quickjs, and private.h instead of repeating extern C blocks across native render headers.
Add a GitHub Actions workflow that builds the simulator on each platform and runs bundled GUI tests via a JavaScript harness. Add a Linux device job that builds the framebuffer HAL without SDL or xvfb-run. Tests auto-exit through gui-test-runner.js with shared exit codes instead of engine changes. Also add build:ui for React bindings and switch dependency locking to yarn.

treat screenshot diffs below 0.01 as equal
Several JS-callable component methods guarded with a smaller argc than the highest argv[] index they read. Since these functions are registered with declared length 0, QuickJS does not pad argv, so passing too few arguments caused out-of-bounds reads of the argument array. Align each argc check with the highest argv index accessed.
Set the TJS_CFUNC_DEF length field to each method's real arity so QuickJS pads argv with undefined up to that count. This provides a defensive backstop against out-of-bounds argv reads on top of the argc guards, and reports correct Function.prototype.length. Scoped to methods that read beyond argv[0].
Signed-off-by: Yonggang Luo <luoyonggang@gmail.com>
The fetch test is evaluated directly as an ES module by the txiki
runtime (not bundled like the jsx/tsx tests), so CommonJS require is
undefined. Import the built-in tjs:assert module instead.
Replace flaky httpbin.org requests with an in-process echo server so CI and offline runs stay reliable, and load the helper via an absolute path so relative imports work on Windows.
Set TEST_CAPTURE during --capture and freeze animation, random data,
and interval-driven updates so PNG comparison is consistent on Linux,
macOS, and device builds.
Bump checkout and setup-node to v6, project Node to 24, and artifact actions to v7.
lv_anim_set_time was called before JS_ToInt32, so animations used an uninitialized duration instead of the value from the style object.
Add a single native bridge that publishes compiled LVGL header values to JavaScript as NativeRender.lv_conf, aligned with the lv_conf.h build used by the binary.

Exposes coord sentinels (LV_COORD_MAX, LV_SIZE_CONTENT, LV_GRID_CONTENT), style parts/states, align, dir, flex flow/align, grid align, scroll snap, and LV_STYLE_* constants so JS no longer hardcodes values that depend on LV_USE_LARGE_COORD or LVGL version.

Re-export the cached TS module as the lv_conf namespace from lvgljs-ui.
Replace hardcoded 2001 | (1 << 13) with the native lv_conf constant so auto sizing stays correct across LVGL versions.
Replace hardcoded grid auto and fr track values with native lv_conf constants derived from LV_COORD_MAX.
Share one LV_DIR_MAP for scroll-dir, EDropdownlistDirection, and Tabs tabPosition so direction string-to-LVGL mappings stay in sync.
Replace hardcoded flex flow/align bit flags with cached NativeRender.lv_conf values. Fixes column-reverse mapping to row-reverse only (8 vs 9).
…enums

Replace hardcoded LVGL values with cached NativeRender.lv_conf constants so style mappings stay in sync with the native build.
Replace hardcoded LV_LABEL_LONG_*, LV_TEXT_ALIGN_*, LV_TEXT_DECOR_*, and LV_GRAD_DIR_* values in style pipes with cached NativeRender.lv_conf constants.
Replace hardcoded LV_BORDER_SIDE flag values in the border style pipe with cached NativeRender.lv_conf constants.
Replace the hardcoded 0x00 flex-flow initializer with the cached lv_conf constant.
lygstate added 21 commits June 2, 2026 04:45
Replace hardcoded 0x0000 style selectors with cached STYLE_TYPE.PART_MAIN across component wrappers.
Replace hardcoded 0x0002 focus style selectors in Input and Textarea with cached STYLE_TYPE.STATE_FOCUSED.
Replace hardcoded zero defaults with the cached lv_conf constant so flex alignment stays in sync with the native LVGL enum values.
…yboard

Replace hardcoded mode/type integers in component prop setters with cached NativeRender.lv_conf constants exposed from the native LVGL headers (f688ac9).

Arc: normal/symmetrical/reverse now map to LV_ARC_MODE_* (lv_arc_mode_t).

Chart: none/line/bar/scatter now map to LV_CHART_TYPE_* (lv_chart_type_t).

Keyboard: lower/upper/special/number now map to LV_KEYBOARD_MODE_* (lv_keyboard_mode_t).

String keys and component APIs are unchanged; only the numeric values passed to native setMode/setType are sourced from lv_conf so they stay aligned with the linked LVGL build.
Move hardcoded LVGL event codes into event_map.ts backed by NativeRender.lv_conf, fixing EVENT_CHILD_CHANGED which previously duplicated EVENT_DELETE.
Introduce deps/lvgl.h and switch project includes from lvgl/lvgl.h to angle-bracket lvgl.h.
…riable]

[build] /mnt/c/work/lvgl/lv_binding_js/deps/txiki/deps/libwebsockets/lib/system/async-dns/async-dns.c:801:27: error: variable ‘c’ set but not used [-Werror=unused-but-set-variable]
[build]   801 |         lws_adns_cache_t *c;
[build]       |                           ^
[build] cc1: all warnings being treated as errors
The WRAPPED_STOPPROPAGATION macro defines NativeEventStopPropagation,
a QuickJS cfunc bound as event.stopPropagation(). Add an explicit
return JS_UNDEFINED so the handler satisfies the JSValue return type.
Use lv_coord_t, lv_opa_t, and uint8_t where the LVGL APIs expect them, including fixing flexGrow which incorrectly cast to lv_flex_flow_t.
Add explicit enum casts in component constructors and style setters so LVGL API types compile under MSVC. Call lv_obj_add_flag separately for EVENT_BUBBLE and CLICK_FOCUSABLE instead of OR-ing flags, fixing broken grid layout in the widgets demo.
The txiki runtime does not provide Node.js Buffer, causing ReferenceError when loading remote GIF/image assets. Use fetch arrayBuffer results directly and fix styleType being passed as a .then() rejection handler.
MSVC does not support zero-length arrays. Drop unused empty ComponentClassFuncs tables and JS_SetPropertyFunctionList calls from native component bindings.

Signed-off-by: Yonggang Luo <luoyonggang@gmail.com>
Relative paths like ./2.png were resolved from the process cwd, causing
ENOENT. Use import.meta.dirname so assets load next to the entry module.
Give test/gif/1 an 8000ms render window so the remote asset can finish loading before screenshot capture.
Skip infinite rotate/scale animations when TEST_CAPTURE is set, matching other animated GUI tests.
This reverts commit 6b1b05e.

It's currently is disabled, so not test at all, there is no need test it
- Add native pause/resume on the GIF LVGL timer
- Expose pause/resume in the JS bridge and GIFComp
- Add paused prop and apply it after async GIF load
- Pause GIF in the test when TEST_CAPTURE is set
- Local GIF/style paths used __dirname and fs.readFile, which do not work in
  the txiki module environment
- Resolve relative asset paths with import.meta.dirname instead of __dirname
- Read local GIF binary data with tjs.readFile instead of fs.readFile
- Use import.meta.dirname for style background-image and arc-image paths
Problem:
- test/gif/1 failed when loading a remote GIF via fetch() + arrayBuffer()
- getGIFBinary relies on octet-stream responses and arrayBuffer(), which is
  not implemented correctly in the current JavaScript runtime

GIF test (test/gif/1):
- Add sample.gif bundled next to index.jsx
- Point src at ./sample.gif instead of a remote GIF URL
- Drop the 8000ms render override; default window is enough for a local file

Preserve fetch + arrayBuffer coverage (test/runtime/fetch/1):
- Add fetchBinaryWithArrayBuffer() using httpbun.com/bytes/N
- Switch other fetch tests from httpbin.org to httpbun.com
- Exit with TEST_EXIT_OK on success so the harness can detect pass/fail
- Mark test/runtime/fetch/1/xfail until arrayBuffer is implemented

Test harness (scripts/run-tests.js, cli-test-runner.js):
- Route test/runtime/** through scripts/cli-test-runner.js (async CLI tests)
- Keep test/** GUI tests on scripts/gui-test-runner.js
- Support expected failures: empty xfail file beside index.js (XFAIL/XPASS)
- Print failure stdout/stderr for FAIL and XFAIL; list failed tests before summary
- Include runtime tests when --capture is used (no screenshot for CLI tests)
- Point deps/txiki submodule at release v26.5.0 (9d7b4db).
- Bump @txikijs/types from ^24.6.0 to ^26.5.0 in package.json; refresh yarn.lock.
- scripts/run-tests.js: align bundled-test harness with txiki v26 runtime API
  - tjs.exepath -> tjs.exePath when spawning GUI and CLI child runners
  - tjs.readdir -> tjs.readDir for recursive test discovery under test/
  - tjs.mkdir -> tjs.makeDir when creating the --capture screenshot directory
  - Read child stdout/stderr via proc.stdout.text() / proc.stderr.text() instead of slurpStdio
- Native C++ bindings: QuickJS JS_IsArray is single-argument in v26.5.0
  - Drop ctx from JS_IsArray in component.hpp and style.cpp
  - Update arc, calendar, chart, dropdownlist, line, roller, slider, and tabview wraps
- .github/workflows/build.yml: remove -DCMAKE_POLICY_VERSION_MINIMUM=3.5 from CI cmake
  configures; no longer required after the txiki upgrade
- test/runtime/fetch/1: remove xfail; Response.arrayBuffer() is available in txiki v26.5.0
- Add CMake and source fixes for MSVC (C++23, Arc rename, mouse cursor)
- Add a windows-2025 workflow job that installs static deps via vcpkg,
  builds with MSVC, runs the screenshot test suite, and uploads artifacts
- Include Windows in screenshot collection
- Remove CMAKE_POLICY_VERSION_MINIMUM from Linux/macOS Ninja configures
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.

Add msvc support by upgrading txiki and other deps

1 participant