Skip to content

Commit acd4fe0

Browse files
authored
Merge branch 'master' into feat/config-request-timeout
2 parents df0dfb7 + 7e3fd96 commit acd4fe0

29 files changed

Lines changed: 5078 additions & 300 deletions

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ All notable changes to this project are documented in this file.
3030
a `"timeout = <ms>"` spec (e.g. `{.ffi: "timeout = 30000".}`), parsed like the
3131
`abi = ...` spec; runtime-only, codegen ignores it
3232
([#93](https://github.com/logos-messaging/nim-ffi/issues/93)).
33+
- **C binding generator** (`-d:targetLang=c`): emits a header-only C binding
34+
(`<lib>.h`) plus a `CMakeLists.txt`, alongside the existing Rust / C++ / CDDL
35+
backends. Requests/responses travel as CBOR using the same vendored TinyCBOR
36+
the C++ backend uses. C has no generics or overloading, so each `seq[T]` /
37+
`Option[T]` is monomorphised into its own struct + encode/decode/free triple.
38+
The high-level `<lib>_ctx_*` API is asynchronous: each method/constructor
39+
takes a typed result callback and the binding owns and reclaims all reply
40+
data and error strings (valid only for the duration of the callback), so the
41+
caller never frees anything — there is no blocking wait and no manual-free
42+
contract. Shared codegen helpers were extracted
43+
into `ffi/codegen/common.nim` (used by both the C and C++ backends). New
44+
`nimble genbindings_c` / `genbindings_c_echo` / `check_bindings_c` /
45+
`test_c_e2e` tasks, a `tests/e2e/c` ctest harness, and a
46+
`tests/unit/test_c_codegen.nim` unit suite.
3347
- Per-interaction ABI-format annotations: `declareLibrary` now takes an
3448
optional `defaultABIFormat` (`"cbor"` default, or `"c"`) that every
3549
`{.ffi.}` / `{.ffiCtor.}` / `{.ffiDtor.}` / `{.ffiRaw.}` / `{.ffiEvent.}`
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
cmake_minimum_required(VERSION 3.14)
2+
project(echo_c_bindings C)
3+
4+
set(CMAKE_C_STANDARD 11)
5+
set(CMAKE_C_STANDARD_REQUIRED ON)
6+
7+
# ── Locate the repository root (contains ffi.nimble) ─────────────────────────
8+
set(_search_dir "${CMAKE_CURRENT_SOURCE_DIR}")
9+
set(REPO_ROOT "")
10+
foreach(_i RANGE 10)
11+
if(EXISTS "${_search_dir}/ffi.nimble")
12+
set(REPO_ROOT "${_search_dir}")
13+
break()
14+
endif()
15+
get_filename_component(_search_dir "${_search_dir}" DIRECTORY)
16+
endforeach()
17+
if("${REPO_ROOT}" STREQUAL "")
18+
message(FATAL_ERROR "Cannot find repo root (no ffi.nimble in any ancestor)")
19+
endif()
20+
21+
# Build the Nim dylib + vendored TinyCBOR (shared with the C++ backend).
22+
set(NIM_FFI_LIB echo)
23+
set(NIM_FFI_SRC ../echo.nim)
24+
include("${REPO_ROOT}/ffi/codegen/templates/nim_ffi_lib.cmake")
25+
26+
find_package(Threads REQUIRED)
27+
28+
add_library(echo_headers INTERFACE)
29+
target_include_directories(echo_headers INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
30+
target_link_libraries(echo_headers INTERFACE echo tinycbor Threads::Threads)
31+
# The generated header is async (no blocking helper), but consumer code that
32+
# waits on a result callback typically uses nanosleep / pthreads, which need a
33+
# POSIX feature level that strict `-std=c11` hides. Define it for consumers.
34+
target_compile_definitions(echo_headers INTERFACE _POSIX_C_SOURCE=200809L)
35+
36+
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/main.c")
37+
add_executable(echo_example main.c)
38+
target_link_libraries(echo_example PRIVATE echo_headers)
39+
add_dependencies(echo_example echo_nim_lib)
40+
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
41+
add_custom_command(TARGET echo_example POST_BUILD
42+
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
43+
"${echo_RUNTIME_LIB}"
44+
"$<TARGET_FILE_DIR:echo_example>"
45+
COMMENT "Staging echo.dll next to echo_example.exe")
46+
endif()
47+
endif()

0 commit comments

Comments
 (0)