build(windows): vendor xxd.c #36746

Problem:
Currently we fetch a prebuilt xxd.exe from neovim/deps for Windows,
which is not ideal in terms of obviousness, misses updates, and is
clumsy to update.

Solution:
Similar to tee.c (#36363), vendor xxd.c from Vim and build it as part
of the Neovim build process. This makes the source obvious, enables
analyzer checks, and simplifies updates.

Fixes #36664
This commit is contained in:
benarcher2691
2025-11-30 05:15:47 +01:00
committed by GitHub
parent 242261554e
commit 5bb8734fb6
6 changed files with 1273 additions and 4 deletions

View File

@@ -313,6 +313,7 @@ add_dependencies(nvim nvim_bin nvim_runtime_deps nvim_runtime)
add_subdirectory(src/nvim)
add_subdirectory(src/tee)
add_subdirectory(src/xxd)
add_subdirectory(cmake.config)
add_subdirectory(runtime)
add_subdirectory(test)

View File

@@ -365,6 +365,18 @@ pub fn build(b: *std.Build) !void {
test_deps.dependOn(test_fixture(b, "printenv-test", null, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "streams-test", libuv, target, optimize, &flags));
// xxd - hex dump utility (vendored from Vim)
const xxd_exe = b.addExecutable(.{
.name = "xxd",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});
xxd_exe.addCSourceFile(.{ .file = b.path("src/xxd/xxd.c") });
xxd_exe.linkLibC();
test_deps.dependOn(&b.addInstallArtifact(xxd_exe, .{}).step);
const parser_c = b.dependency("treesitter_c", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "c", parser_c.path("."), false, target, optimize));
const parser_markdown = b.dependency("treesitter_markdown", .{ .target = target, .optimize = optimize });

View File

@@ -426,7 +426,10 @@ list(SORT NVIM_SOURCES)
list(SORT NVIM_HEADERS)
list(APPEND UNCRUSTIFY_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS})
list(APPEND UNCRUSTIFY_NVIM_SOURCES ${PROJECT_SOURCE_DIR}/src/tee/tee.c)
list(APPEND UNCRUSTIFY_NVIM_SOURCES
${PROJECT_SOURCE_DIR}/src/tee/tee.c
${PROJECT_SOURCE_DIR}/src/xxd/xxd.c
)
foreach(sfile ${NVIM_SOURCES})
get_filename_component(f ${sfile} NAME)
@@ -458,7 +461,10 @@ foreach(hfile ${NVIM_HEADERS})
endforeach()
list(APPEND LINT_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS})
list(APPEND LINT_NVIM_SOURCES ${PROJECT_SOURCE_DIR}/src/tee/tee.c)
list(APPEND LINT_NVIM_SOURCES
${PROJECT_SOURCE_DIR}/src/tee/tee.c
${PROJECT_SOURCE_DIR}/src/xxd/xxd.c
)
# Log level (NVIM_LOG_DEBUG in log.h)
if(CI_BUILD)
@@ -864,7 +870,7 @@ target_link_libraries(libnvim PRIVATE main_lib PUBLIC libuv)
find_program(CLANG_TIDY_PRG clang-tidy)
mark_as_advanced(CLANG_TIDY_PRG)
set(EXCLUDE_CLANG_TIDY typval_encode.c.h ui_events.in.h)
set(EXCLUDE_CLANG_TIDY typval_encode.c.h ui_events.in.h xxd/xxd.c)
if(WIN32)
list(APPEND EXCLUDE_CLANG_TIDY
os/pty_proc_unix.h
@@ -926,7 +932,8 @@ add_glob_target(
FLAGS --output=${LINT_OUTPUT_FORMAT}
FILES ${LINT_NVIM_SOURCES}
EXCLUDE
tui/terminfo_defs.h)
tui/terminfo_defs.h
xxd/xxd.c)
set(UNCRUSTIFY_PRG ${DEPS_BIN_DIR}/uncrustify)
set(UNCRUSTIFY_CONFIG ${PROJECT_SOURCE_DIR}/src/uncrustify.cfg)

12
src/xxd/CMakeLists.txt Normal file
View File

@@ -0,0 +1,12 @@
add_executable(xxd xxd.c)
# xxd has to be in the same directory as the nvim executable
set_target_properties(xxd PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)
if(WIN32)
install(TARGETS xxd
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
)
endif()

1218
src/xxd/xxd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local eq = t.eq
local clear = n.clear
local fn = n.fn
local testprg = n.testprg
describe('xxd', function()
before_each(clear)
it('works', function()
-- Round-trip test: encode then decode should return original
local input = 'hello'
local encoded = fn.system({ testprg('xxd') }, input)
local decoded = fn.system({ testprg('xxd'), '-r' }, encoded)
eq(input, decoded)
end)
end)