Introduce rust: In xdiff
Subsystems (4)
cover Introduce rust: In xdiff
This is a continuation of
https://lore.kernel.org/git/[email protected]/,
but I am removing the RFC label.
Changes since the last RFC patch series (range-diff added below):
* Addressed feedback:
* Use self instead of this
* Update ivec to use Git code style
* Remove environment variable CI_IS_DOCKER from github workflows
* Remove PHONY target interop-objs
* Removed left over asserts in Rust and fix near by code
* Other changes:
* Avoid name mangling of ivec if c++ compiler used
* Fixed a typo in patch 11 commit message
High level overview:
* patch 1: add a policy for using Rust (brian's patch, with a small tweak)
* patch 2: introduce Rust to the codebase
* patches 3-5: adapt CI (github workflows) to build Git with Rust
* patch 6: introduce the ivec type
* patches 7-14: xdiff code cleanup in preparation for translating to Rust
* patch 15: translate a C function into Rust and call it from C
Build results for these changes:
https://github.com/git/git/actions/runs/17330190596
Range-Diff against last RFC version:
1: 6d065f550f = 1: 6d065f550f doc: add a policy for using Rust
2: 0393995125 = 2: cc9cf87775 xdiff: introduce rust
3: a98d9e4d21 ! 3: 6c47401ba0 github workflows: install rust
@@ .github/workflows/main.yml: jobs:
image: fedora:latest
# A RHEL 8 compatible distro. Supported until 2029-05-31.
@@ .github/workflows/main.yml: jobs:
- jobname: ${{matrix.vector.jobname}}
CC: ${{matrix.vector.cc}}
CI_JOB_IMAGE: ${{matrix.vector.image}}
-+ CI_IS_DOCKER: "true"
CUSTOM_PATH: /custom
+ CARGO_HOME: /home/builder/.cargo
runs-on: ubuntu-latest
4: 0d2b39c3e0 = 4: 8e350700bc win+Meson: do allow linking with the Rust-built xdiff
5: e65488ab99 = 5: a00cbf7bcb github workflows: upload Cargo.lock
6: db5d22b188 ! 6: 922d506ed6 ivec: create a vector type that is interoperable between C and Rust
@@ Makefile: reconfigure config.mak.autogen: config.status
endif
+INTEROP_OBJS += interop/ivec.o
-+.PHONY: interop-objs
-+interop-objs: $(INTEROP_OBJS)
+
XDIFF_OBJS += xdiff/xdiffi.o
XDIFF_OBJS += xdiff/xemit.o
@@ interop/ivec.c (new)
@@
+#include "ivec.h"
+
-+static void ivec_set_capacity(void* self, usize new_capacity) {
-+ struct rawivec *this = self;
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++static void ivec_set_capacity(void *self_, usize new_capacity)
++{
++ struct rawivec *self = self_;
++
+ if (new_capacity == 0)
-+ FREE_AND_NULL(this->ptr);
++ FREE_AND_NULL(self->ptr);
+ else
-+ this->ptr = xrealloc(this->ptr, new_capacity * this->element_size);
-+ this->capacity = new_capacity;
++ self->ptr = xrealloc(self->ptr, new_capacity * self->element_size);
++ self->capacity = new_capacity;
+}
+
-+void ivec_init(void* self, usize element_size) {
-+ struct rawivec *this = self;
-+ this->ptr = NULL;
-+ this->length = 0;
-+ this->capacity = 0;
-+ this->element_size = element_size;
++void ivec_init(void *self_, usize element_size)
++{
++ struct rawivec *self = self_;
++
++ self->ptr = NULL;
++ self->length = 0;
++ self->capacity = 0;
++ self->element_size = element_size;
+}
+
+/*
@@ interop/ivec.c (new)
+ * to the specified capacity, and then calloc self.capacity number of
+ * elements.
+ */
-+void ivec_zero(void* self, usize capacity) {
-+ struct rawivec *this = self;
-+ if (this->ptr)
-+ FREE_AND_NULL(this->ptr);
-+ this->capacity = this->length = capacity;
-+ this->ptr = xcalloc(this->capacity, this->element_size);
++void ivec_zero(void *self_, usize capacity)
++{
++ struct rawivec *self = self_;
++
++ if (self->ptr)
++ FREE_AND_NULL(self->ptr);
++ self->capacity = self->length = capacity;
++ self->ptr = xcalloc(self->capacity, self->element_size);
+}
+
-+void ivec_clear(void* self) {
-+ struct rawivec *this = self;
-+ this->length = 0;
++void ivec_clear(void *self_)
++{
++ struct rawivec *self = self_;
++
++ self->length = 0;
+}
+
-+void ivec_reserve_exact(void* self, usize additional) {
-+ struct rawivec *this = self;
-+ usize new_capacity = this->capacity + additional;
++void ivec_reserve_exact(void *self_, usize additional)
++{
++ struct rawivec *self = self_;
++ usize new_capacity = self->capacity + additional;
++
+ ivec_set_capacity(self, new_capacity);
+}
+
-+void ivec_reserve(void* self, usize additional) {
-+ struct rawivec *this = self;
++void ivec_reserve(void *self_, usize additional)
++{
++ struct rawivec *self = self_;
+ usize growby = 128;
-+ if (this->capacity > growby) {
-+ growby = this->capacity;
++
++ if (self->capacity > growby) {
++ growby = self->capacity;
+ }
+ if (additional > growby) {
+ growby = additional;
@@ interop/ivec.c (new)
+ ivec_reserve_exact(self, growby);
+}
+
-+void ivec_shrink_to_fit(void* self) {
-+ struct rawivec *this = self;
-+ ivec_set_capacity(self, this->length);
++void ivec_shrink_to_fit(void *self_)
++{
++ struct rawivec *self = self_;
++
++ ivec_set_capacity(self_, self->length);
+}
+
-+void ivec_resize(void* self, usize new_length, void* default_value) {
-+ struct rawivec *this = self;
-+ isize additional = (isize) (new_length - this->capacity);
++void ivec_resize(void *self_, usize new_length, void *default_value)
++{
++ struct rawivec *self = self_;
++ isize additional = (isize) (new_length - self->capacity);
++
+ if (additional > 0) {
-+ ivec_reserve(self, additional);
++ ivec_reserve(self_, additional);
+ }
+
-+ for (usize i = this->length; i < new_length; i++) {
-+ void* dst = (u8*) this->ptr + (this->length + i) * this->element_size;
-+ memcpy(dst, default_value, this->element_size);
++ for (usize i = self->length; i < new_length; i++) {
++ void *dst = (u8 *)self->ptr + (self->length + i) * self->element_size;
++ memcpy(dst, default_value, self->element_size);
+ }
-+ this->length = new_length;
++ self->length = new_length;
+}
+
-+void ivec_push(void* self, void* value) {
-+ struct rawivec *this = self;
-+ u8* dst;
++void ivec_push(void *self_, void *value)
++{
++ struct rawivec *self = self_;
++ u8 *dst;
+
-+ if (this->length == this->capacity) {
-+ ivec_reserve(self, 1);
++ if (self->length == self->capacity) {
++ ivec_reserve(self_, 1);
+ }
-+ dst = (u8*) this->ptr + this->length * this->element_size;
-+ memcpy(dst, value, this->element_size);
-+ this->length++;
++ dst = (u8 *)self->ptr + self->length * self->element_size;
++ memcpy(dst, value, self->element_size);
++ self->length++;
+}
+
-+void ivec_extend_from_slice(void* self, void const* ptr, usize size) {
-+ struct rawivec *this = self;
-+ u8* dst;
++void ivec_extend_from_slice(void *self_, void const *ptr, usize size)
++{
++ struct rawivec *self = self_;
++ u8 *dst;
+
+ if (size == 0)
+ return;
+
-+ if (this->length + size > this->capacity) {
-+ ivec_reserve(self, this->capacity - this->length + size);
++ if (self->length + size > self->capacity) {
++ ivec_reserve(self_, self->capacity - self->length + size);
+ }
-+ dst = (u8*) this->ptr + this->length * this->element_size;
-+ memcpy(dst, ptr, size * this->element_size);
-+ this->length += size;
++ dst = (u8 *)self->ptr + self->length * self->element_size;
++ memcpy(dst, ptr, size * self->element_size);
++ self->length += size;
+}
+
-+bool ivec_equal(void* self, void* other) {
-+ struct rawivec *lhs = self;
++bool ivec_equal(void *self_, void *other)
++{
++ struct rawivec *lhs = self_;
+ struct rawivec *rhs = other;
+
+ if (lhs->element_size != rhs->element_size) {
@@ interop/ivec.c (new)
+ return false;
+ }
+
-+
+ for (usize i = 0; i < lhs->length; i++) {
-+ void* left = (u8 *) lhs->ptr + i * lhs->element_size;
-+ void* right = (u8 *) rhs->ptr + i * rhs->element_size;
++ void *left = (u8 *)lhs->ptr + i * lhs->element_size;
++ void *right = (u8 *)rhs->ptr + i * rhs->element_size;
+ if (memcmp(left, right, lhs->element_size) != 0) {
+ return false;
+ }
@@ interop/ivec.c (new)
+}
+
+
-+void ivec_free(void* self) {
-+ struct rawivec *this = self;
-+ FREE_AND_NULL(this->ptr);
-+ this->length = 0;
-+ this->capacity = 0;
++void ivec_free(void *self_)
++{
++ struct rawivec *self = self_;
++
++ FREE_AND_NULL(self->ptr);
++ self->length = 0;
++ self->capacity = 0;
+ /* don't modify self->element_size */
+}
+
-+void ivec_move(void* source, void* destination) {
-+ struct rawivec *this = source;
-+ struct rawivec *that = destination;
++void ivec_move(void *source, void *destination)
++{
++ struct rawivec *src = source;
++ struct rawivec *dst = destination;
+
-+ if (this->element_size != that->element_size)
++ if (src->element_size != dst->element_size)
+ BUG("mismatched element_size");
+
+ ivec_free(destination);
-+ that->ptr = this->ptr;
-+ that->length = this->length;
-+ that->capacity = this->capacity;
++ dst->ptr = src->ptr;
++ dst->length = src->length;
++ dst->capacity = src->capacity;
++
++ src->ptr = NULL;
++ src->length = 0;
++ src->capacity = 0;
++}
+
-+ this->ptr = NULL;
-+ this->length = 0;
-+ this->capacity = 0;
++#ifdef __cplusplus
+}
++#endif
## interop/ivec.h (new) ##
@@
+#ifndef IVEC_H
+#define IVEC_H
+
-+#include "../git-compat-util.h"
++#include <git-compat-util.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
+
+struct rawivec {
-+ void* ptr;
++ void *ptr;
+ usize length;
+ usize capacity;
+ usize element_size;
@@ interop/ivec.h (new)
+
+#define DEFINE_IVEC_TYPE(type, suffix) \
+struct ivec_##suffix { \
-+ type* ptr; \
++ type *ptr; \
+ size_t length; \
+ size_t capacity; \
+ size_t element_size; \
@@ interop/ivec.h (new)
+DEFINE_IVEC_TYPE(usize, usize);
+DEFINE_IVEC_TYPE(isize, isize);
+
-+void ivec_init(void* self, usize element_size);
-+void ivec_zero(void* self, usize capacity);
-+void ivec_clear(void* self);
-+void ivec_reserve_exact(void* self, usize additional);
-+void ivec_reserve(void* self, usize additional);
-+void ivec_shrink_to_fit(void* self);
-+void ivec_resize(void* self, usize new_length, void* default_value);
-+void ivec_push(void* self, void* value);
-+void ivec_extend_from_slice(void* self, void const* ptr, usize size);
-+bool ivec_equal(void* self, void* other);
-+void ivec_free(void* self);
-+void ivec_move(void* source, void* destination);
++void ivec_init(void *self_, usize element_size);
++void ivec_zero(void *self_, usize capacity);
++void ivec_clear(void *self_);
++void ivec_reserve_exact(void *self_, usize additional);
++void ivec_reserve(void *self_, usize additional);
++void ivec_shrink_to_fit(void *self_);
++void ivec_resize(void *self_, usize new_length, void *default_value);
++void ivec_push(void *self_, void *value);
++void ivec_extend_from_slice(void *self_, void const *ptr, usize size);
++bool ivec_equal(void *self_, void *other);
++void ivec_free(void *self_);
++void ivec_move(void *source, void *destination);
++
++#ifdef __cplusplus
++}
++#endif
+
+#endif //IVEC_H
@@ rust/interop/src/ivec.rs (new)
+
+impl<T> Drop for IVec<T> {
+ fn drop(&mut self) {
-+ unsafe {
-+ self._free();
-+ }
++ self._set_capacity(0);
+ }
+}
+
@@ rust/interop/src/ivec.rs (new)
+ }
+ }
+
-+ fn _zero(&mut self) {
-+ self.ptr = std::ptr::null_mut();
-+ self.length = 0;
-+ self.capacity = 0;
-+ // DO NOT MODIFY element_size!!!
-+ }
-+
-+ unsafe fn _free(&mut self) {
-+ free(self.ptr as *mut std::ffi::c_void);
-+ self._zero();
-+ }
-+
+ fn _set_capacity(&mut self, new_capacity: usize) {
+ unsafe {
+ if new_capacity == self.capacity {
+ return;
+ }
++ if new_capacity < self.length {
++ self.truncate(new_capacity);
++ }
+ if new_capacity == 0 {
-+ self._free();
++ free(self.ptr as *mut c_void);
++ self.ptr = std::ptr::null_mut();
++ self.length = 0;
++ self.capacity = 0;
++ // DO NOT MODIFY element_size!!!
+ } else {
-+ let t = realloc(
-+ self.ptr as *mut std::ffi::c_void,
-+ new_capacity * size_of::<T>(),
-+ );
++ let t = realloc(self.ptr as *mut c_void, new_capacity * size_of::<T>());
+ if t.is_null() {
+ panic!("out of memory");
+ }
@@ rust/interop/src/ivec.rs (new)
+ /* capacity does not need to be changed */
+ }
+
++ /* IVec grows */
+ if new_length > self.length {
+ let range = self.length..new_length;
+ self._buffer_mut()[range].fill(default_value);
++ self.length = new_length;
+ }
+
-+ self.length = new_length;
++ /* IVec shrinks */
++ if new_length < self.length {
++ self.truncate(new_length);
++ }
+ }
+
+ fn _buffer_mut(&mut self) -> &mut [T] {
@@ rust/interop/src/ivec.rs (new)
+ self._resize(new_length, default_value, true);
+ }
+
++ pub fn truncate(&mut self, new_length: usize) {
++ if new_length >= self.length {
++ return;
++ }
++
++ if std::mem::needs_drop::<T>() {
++ let range = new_length..self.length;
++ for v in &mut self.as_mut_slice()[range] {
++ unsafe {
++ std::ptr::drop_in_place(v);
++ }
++ }
++ }
++
++ self.length = new_length;
++ }
++
+ pub fn insert(&mut self, index: usize, value: T) {
+ if self.length == self.capacity {
+ self.reserve(1);
@@ rust/interop/src/ivec.rs (new)
+#[cfg(test)]
+mod tests {
+ use crate::ivec::IVec;
++ use std::cell::RefCell;
++ use std::mem::size_of;
++ use std::ops::{Deref, DerefMut};
+ use std::panic;
++ use std::rc::Rc;
++
++ struct DropTest {
++ value: Rc<RefCell<u64>>,
++ }
++
++ impl DropTest {
++ fn new(value: Rc<RefCell<u64>>) -> Self {
++ Self { value }
++ }
++ }
++
++ impl Drop for DropTest {
++ fn drop(&mut self) {
++ *self.value.borrow_mut() -= 1;
++ }
++ }
++
++ #[test]
++ fn test_drop_elements() {
++ let counter = Rc::new(RefCell::new(0u64));
++ let size = 5;
++
++ /* drop whole IVec */
++ let mut vec = IVec::new();
++ for _ in 0..size {
++ let tmp = DropTest::new(counter.clone());
++ *tmp.value.borrow_mut() += 1;
++ vec.push(tmp);
++ }
++ let cur = *counter.borrow();
++ assert_eq!(size, cur);
++ drop(vec);
++
++ let cur = *counter.borrow();
++ assert_eq!(0u64, cur);
++
++ /* drop some elements */
++ let mut vec = IVec::new();
++ for i in 0..size {
++ let tmp = DropTest::new(counter.clone());
++ *tmp.value.borrow_mut() += 1;
++ vec.push(tmp);
++ }
++ let cur = *counter.borrow().deref();
++ assert_eq!(size, cur);
++
++ let expected = 2u64;
++ vec.truncate(expected as usize);
++
++ let cur = *counter.borrow();
++ assert_eq!(expected, cur);
++ drop(vec);
++ }
+
+ #[test]
+ fn test_panic_on_out_of_bounds() {
@@ rust/interop/src/ivec.rs (new)
+ let expected = vec.capacity + 10;
+ let default_value = 19;
+ vec.resize(expected, default_value);
-+ // assert_eq!(vec.capacity, vec.slice.len());
+ assert_eq!(expected, vec.length);
+ assert!(vec.capacity >= expected);
+ for i in 0..vec.length {
@@ rust/interop/src/ivec.rs (new)
+ }
+
+ vec.reserve(10);
-+ // assert_eq!(vec.capacity, vec.slice.len());
+ assert!(vec.capacity > vec.length);
+ let length_before = vec.length;
+ vec.shrink_to_fit();
+ assert_eq!(length_before, vec.length);
+ assert_eq!(vec.length, vec.capacity);
-+ // assert_eq!(vec.capacity, vec.slice.len());
+ }
+
+ #[test]
@@ rust/interop/src/ivec.rs (new)
+ assert_eq!(16, vec.element_size);
+ assert_eq!(size_of::<usize>() * 4, size_of::<IVec<u128>>());
+ }
-+
-+ #[test]
-+ fn test_manual_free() {
-+ type TestType = i16;
-+ let mut vec = IVec::<TestType>::new();
-+
-+ unsafe { vec._free() };
-+ assert!(vec.ptr.is_null());
-+ assert_eq!(0, vec.length);
-+ assert_eq!(0, vec.capacity);
-+ assert_eq!(size_of::<TestType>(), vec.element_size);
-+ }
+}
## rust/interop/src/lib.rs ##
@@ rust/interop/src/lib.rs
+ pub fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void;
+ pub fn free(ptr: *mut c_void);
+}
-
- ## rust/xdiff/src/lib.rs ##
-@@
-+
7: d4bed95463 = 7: 3a6f822e2a xdiff/xprepare: remove superfluous forward declarations
8: 7c68ce5349 = 8: c7cd71dae0 xdiff: delete unnecessary fields from xrecord_t and xdfile_t
9: e516ccc8c0 = 9: 1096c8f0a4 xdiff: make fields of xrecord_t Rust friendly
10: 21bfb9f088 = 10: 0cd2168512 xdiff: use one definition for freeing xdfile_t
11: 6ce0e252b3 ! 11: 7ea2dccd71 xdiff: replace chastore with an ivec in xdfile_t @@ Commit message
xdiff: replace chastore with an ivec in xdfile_t
xdfile_t currently uses a chastore which functions as a memory pool and
- a vector which maps to the alocations created by the chastore. It seems
+ a vector which maps to the allocations created by the chastore. It seems
like xrecord_t used to be a linked list until the recs and nrec fields were added. I think that xrecord_t.next was meant to be removed, but was overlooked. This dual data structure setup make the code somewhat
12: 0cfc6cf26b = 12: d8f561e173 xdiff: delete nrec field from xdfile_t
13: cf0387d851 = 13: 15c2854a32 xdiff: delete recs field from xdfile_t
14: ea699135f9 = 14: 3dacb2c09d xdiff: make xdfile_t more rust friendly
15: b18544b74f ! 15: 9fdd23acf6 xdiff: implement xdl_trim_ends() in Rust
@@ rust/xdiff/src/lib.rs
@@
+pub mod xprepare;
+pub mod xtypes;
-
++
+use crate::xprepare::trim_ends;
+use crate::xtypes::xdfile;
+Ezekiel Newren (13):
xdiff: introduce rust
github workflows: install rust
github workflows: upload Cargo.lock
ivec: create a vector type that is interoperable between C and Rust xdiff/xprepare: remove superfluous forward declarations
xdiff: delete unnecessary fields from xrecord_t and xdfile_t
xdiff: make fields of xrecord_t Rust friendly
xdiff: use one definition for freeing xdfile_t
xdiff: replace chastore with an ivec in xdfile_t
xdiff: delete nrec field from xdfile_t
xdiff: delete recs field from xdfile_t
xdiff: make xdfile_t more rust friendly
xdiff: implement xdl_trim_ends() in Rust
Johannes Schindelin (1):
win+Meson: do allow linking with the Rust-built xdiff
brian m. carlson (1):
doc: add a policy for using Rust
.github/workflows/main.yml | 88 ++- .gitignore | 3 + Documentation/Makefile | 1 + Documentation/technical/platform-support.adoc | 2 + Documentation/technical/rust-support.adoc | 142 +++++ Makefile | 67 ++- build_rust.sh | 57 ++ ci/install-dependencies.sh | 14 +- ci/install-rust-toolchain.sh | 30 + ci/install-rustup.sh | 25 + ci/lib.sh | 1 + ci/make-test-artifacts.sh | 9 + ci/run-build-and-tests.sh | 13 + config.mak.uname | 4 + git-compat-util.h | 17 + interop/ivec.c | 180 ++++++ interop/ivec.h | 60 ++ meson.build | 54 +- rust/Cargo.toml | 6 + rust/interop/Cargo.toml | 14 + rust/interop/src/ivec.rs | 516 ++++++++++++++++++ rust/interop/src/lib.rs | 10 + rust/xdiff/Cargo.toml | 15 + rust/xdiff/src/lib.rs | 15 + rust/xdiff/src/xprepare.rs | 27 + rust/xdiff/src/xtypes.rs | 19 + xdiff/xdiffi.c | 60 +- xdiff/xdiffi.h | 8 +- xdiff/xemit.c | 24 +- xdiff/xhistogram.c | 2 +- xdiff/xmerge.c | 72 +-- xdiff/xpatience.c | 16 +- xdiff/xprepare.c | 271 ++++----- xdiff/xtypes.h | 27 +- xdiff/xutils.c | 12 +- 35 files changed, 1562 insertions(+), 319 deletions(-) create mode 100644 Documentation/technical/rust-support.adoc create mode 100755 build_rust.sh create mode 100755 ci/install-rust-toolchain.sh create mode 100755 ci/install-rustup.sh create mode 100644 interop/ivec.c create mode 100644 interop/ivec.h create mode 100644 rust/Cargo.toml create mode 100644 rust/interop/Cargo.toml create mode 100644 rust/interop/src/ivec.rs create mode 100644 rust/interop/src/lib.rs create mode 100644 rust/xdiff/Cargo.toml create mode 100644 rust/xdiff/src/lib.rs create mode 100644 rust/xdiff/src/xprepare.rs create mode 100644 rust/xdiff/src/xtypes.rs
base-commit: 16bd9f20a403117f2e0d9bcda6c6e621d3763e77
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2043%2Fezekielnewren%2Fintroduce_rust-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2043/ezekielnewren/introduce_rust-v1
Pull-Request: https://github.com/git/git/pull/2043
Signature · 1 line
gitgitgadget
PATCH 1/15 doc: add a policy for using Rust
From: "brian m. carlson" <[email protected]>
Git has historically been written primarily in C, with some shell and Perl. However, C is not memory safe, which makes it more likely that security vulnerabilities or other bugs will be introduced, and it is also more verbose and less ergonomic than other, more modern languages.
One of the most common modern compiled languages which is easily interoperable with C is Rust. It is popular (the most admired language on the 2024 Stack Overflow Developer Survey), efficient, portable, and robust.
Introduce a document laying out the incremental introduction of Rust to Git and provide a detailed rationale for doing so, including the points above. Propose a design for this approach that addresses the needs of downstreams and distributors, as well as contributors.
Since we don't want to carry both a C and Rust version of code and want to be able to add new features only in Rust, mention that Rust is a required part of our platform support policy.
It should be noted that a recent discussion at the Berlin Git Merge Contributor Summit found widespread support for the addition of Rust to Git. While of course not all contributors were represented, the proposal appeared to have the support of a majority of active contributors.
[en: Added some comments about types, and changed the recommondations
about cbindgen, bindgen, rustix, libc.]
--- Documentation/Makefile | 1 + Documentation/technical/platform-support.adoc | 2 + Documentation/technical/rust-support.adoc | 142 ++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 Documentation/technical/rust-support.adoc
Documentation/Makefile +1 -0
@@ -127,6 +127,7 @@ TECH_DOCS += technical/parallel-checkout TECH_DOCS += technical/partial-clone TECH_DOCS += technical/platform-support TECH_DOCS += technical/racy-git +TECH_DOCS += technical/rust-support TECH_DOCS += technical/reftable TECH_DOCS += technical/scalar TECH_DOCS += technical/send-pack-pipeline
Documentation/technical/platform-support.adoc +2 -0
@@ -33,6 +33,8 @@ meet the following minimum requirements: * Has active security support (taking security releases of dependencies, etc) +* Supports Rust and the toolchain version specified in link:rust-support.adoc[]. + These requirements are a starting point, and not sufficient on their own for the Git community to be enthusiastic about supporting your platform. Maintainers of platforms which do meet these requirements can follow the steps below to make it
Documentation/technical/rust-support.adoc new file +142 -0
142 lines not on this page · raw message
Signature · 1 line
gitgitgadget
Re: [PATCH 01/15] doc: add a policy for using Rust
Quoted 8 lines · brian m. carlson via GitGitGadget
Documentation/technical/rust-support.adoc new file +8
-0+Crates like libc or rustix define types like c_long, but in ways that are not +safe across platforms. +From https://docs.rs/rustix/latest/rustix/ffi/type.c_long.html: + + This type will always be i32 or i64. Most notably, many Linux-based + systems assume an i64, but Windows assumes i32. The C standard technically + only requires that this type be a signed integer that is at least 32 bits + and at least the size of an int, although in practice, no system would
Documentation/technical/rust-support.adoc line 92
Quoted 10 lines
Documentation/technical/rust-support.adoc new file +10
-0+ have a long that is neither an i32 nor i64. + +Also, note that other locations, such as +https://docs.rs/libc/latest/libc/type.c_long.html, just hardcode c_long as i64 +even though C may mean i32 on some platforms. + +As such, using the c_long type would give us portability issues, and +perpetuate some of the bugs git has faced across platforms. Avoid using C's +types (long, unsigned, char, etc.), and switch to unambiguous types (e.g. i32 +or i64) before trying to make C and Rust interoperate.
This makes sense. I agree fixed-size types are better and less brittle.
Documentation/technical/rust-support.adoc line 98
Quoted 5 lines
Documentation/technical/rust-support.adoc new file +5
-0+Crates like libc and rustix may have also traditionally aided interoperability +with older versions of Rust (e.g. when worrying about stat[64] system calls), +but the Rust standard library in newer versions of Rust handle these concerns +in a platform agnostic way. There may arise cases where we need to consider +these crates, but for now we omit them.
I'm fine with omitting them for now. However, we may very well need them in the future.
Documentation/technical/rust-support.adoc line 103
Quoted 4 lines
Documentation/technical/rust-support.adoc new file +4
-0+Tools like bindgen and cbindgen create C-styled unsafe Rust code rather than +idiomatic Rust; where possible, we prefer to switch to idiomatic Rust. Any +standard C library functions that are needed can be manually wrapped on the +Rust side.
I agree that we want to use idiomatic Rust whenever possible. However, I don't want to define structures and function definitions in both languages and rely on people keeping them in sync, since that's a great way to create brittle, broken code. Very notably, I have seen these kinds of misalignments break only on big-endian architectures, which most of us do not use, so we can really end up causing problems that are very subtle this way.
I would prefer we wrote these functions with cbindgen to avoid this. If we define structures only in Rust and never ever use C structures, then we can avoid bindgen.
Signature · 2 lines
brian m. carlson (they/them) Toronto, Ontario, CA
Re: [PATCH 01/15] doc: add a policy for using Rust
Quoted 13 lines · brian m. carlson
Documentation/technical/rust-support.adoc line 103
Quoted 4 lines
Documentation/technical/rust-support.adoc new file +4
-0+Tools like bindgen and cbindgen create C-styled unsafe Rust code rather than +idiomatic Rust; where possible, we prefer to switch to idiomatic Rust. Any +standard C library functions that are needed can be manually wrapped on the +Rust side.I agree that we want to use idiomatic Rust whenever possible. However, I don't want to define structures and function definitions in both languages and rely on people keeping them in sync, since that's a great way to create brittle, broken code. Very notably, I have seen these kinds of misalignments break only on big-endian architectures, which most of us do not use, so we can really end up causing problems that are very subtle this way.
Quoted 3 lines
I would prefer we wrote these functions with cbindgen to avoid this. If we define structures only in Rust and never ever use C structures, then we can avoid bindgen.
Could you create a patch with your preferred wording about bindgen and cbindgen for me? I'd prefer to introduce bindgen/cbindgen in a different patch series because this one is already doing a lot just to make Rust exist in Git.
Re: [PATCH 01/15] doc: add a policy for using Rust
Quoted 4 lines · Ezekiel Newren
Could you create a patch with your preferred wording about bindgen and cbindgen for me? I'd prefer to introduce bindgen/cbindgen in a different patch series because this one is already doing a lot just to make Rust exist in Git.
I think it's fine to introduce it in a different series. I'll plan to do that myself if it doesn't get done sooner.
My change to the text is the following:
Tools like bindgen and cbindgen create C-styled unsafe Rust code rather than idiomatic Rust; where possible, we prefer to switch to idiomatic Rust. However, we may use bindgen and cbindgen to share existing Git types as an interim step.
You can find the patch at https://github.com/bk2204/git.git in the rust-policy branch.
Signature · 2 lines
brian m. carlson (they/them) Toronto, Ontario, CA
Re: [PATCH 01/15] doc: add a policy for using Rust
Quoted 2 lines · brian m. carlson
I think it's fine to introduce it in a different series. I'll plan to do that myself if it doesn't get done sooner.
Actually now that I'm knee deep in adding cbindgen to Rust it'll make less sense to add it later. I'm currently working on refactoring my entire patch series to include cbindgen from the beginning. I haven't looked into cbindgen until now because I wanted to understand at a deep level how C <-> Rust ffi worked rather than using an automagical tool like cbindgen. I now think cbindgen should be part of the introduction of Rust.
Re: [PATCH 01/15] doc: add a policy for using Rust
Quoted 7 lines · Ezekiel Newren
Actually now that I'm knee deep in adding cbindgen to Rust it'll make less sense to add it later. I'm currently working on refactoring my entire patch series to include cbindgen from the beginning. I haven't looked into cbindgen until now because I wanted to understand at a deep level how C <-> Rust ffi worked rather than using an automagical tool like cbindgen. I now think cbindgen should be part of the introduction of Rust.
I've been able to get cbindgen to work with 1.63.0, but I'm not ready to release my next patch series yet.
PATCH 2/15 xdiff: introduce rust
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Upcoming patches will simplify xdiff, while also porting parts of it to Rust. In preparation, add some stubs and setup the Rust build. For now, it is easier to let cargo build rust and have make or meson merely link against the static library that cargo builds. In line with ongoing libification efforts, use multiple crates to allow more modularity on the Rust side. xdiff is the crate that this series will focus on, but we also introduce the interop crate for future patch series.
In order to facilitate interoperability between C and Rust, introduce C definitions for Rust primitive types in git-compat-util.h.
--- .gitignore | 3 +++ Makefile | 53 ++++++++++++++++++++++++++++---------- build_rust.sh | 57 +++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 17 ++++++++++++ meson.build | 52 +++++++++++++++++++++++++++++++------ rust/Cargo.toml | 6 +++++ rust/interop/Cargo.toml | 14 ++++++++++ rust/interop/src/lib.rs | 0 rust/xdiff/Cargo.toml | 15 +++++++++++ rust/xdiff/src/lib.rs | 0 10 files changed, 196 insertions(+), 21 deletions(-) create mode 100755 build_rust.sh create mode 100644 rust/Cargo.toml create mode 100644 rust/interop/Cargo.toml create mode 100644 rust/interop/src/lib.rs create mode 100644 rust/xdiff/Cargo.toml create mode 100644 rust/xdiff/src/lib.rs
.gitignore +3 -0
@@ -254,3 +254,6 @@ Release/ /contrib/buildsystems/out /contrib/libgit-rs/target /contrib/libgit-sys/target +/.idea/ +/rust/target/ +/rust/Cargo.lock
Makefile +40 -13
128 lines not on this page · raw message
build_rust.sh new file +57 -0
57 lines not on this page · raw message
git-compat-util.h +17 -0
@@ -196,6 +196,23 @@ static inline int is_xplatform_dir_sep(int c)#include "compat/msvc.h" #endif +/* rust types */ +typedef uint8_t u8 ; +typedef uint16_t u16 ; +typedef uint32_t u32 ; +typedef uint64_t u64 ; + +typedef int8_t i8 ; +typedef int16_t i16 ; +typedef int32_t i32 ; +typedef int64_t i64 ; + +typedef float f32 ; +typedef double f64 ; + +typedef size_t usize ; +typedef ptrdiff_t isize ; +/* used on Mac OS X */ #ifdef PRECOMPOSE_UNICODE #include "compat/precompose_utf8.h"
meson.build +44 -8
64 lines not on this page · raw message
rust/Cargo.toml new file +6 -0
@@ -0,0 +1,6 @@ +[workspace] +members = [ + "xdiff", + "interop", +] +resolver = "2"
rust/interop/Cargo.toml new file +14 -0
@@ -0,0 +1,14 @@ +[package] +name = "interop" +version = "0.1.0" +edition = "2021" + +[lib] +name = "interop" +path = "src/lib.rs" +## staticlib to generate xdiff.a for use by gcc +## cdylib (optional) to generate xdiff.so for use by gcc +## rlib is required by the rust unit tests +crate-type = ["staticlib", "rlib"] + +[dependencies]
rust/interop/src/lib.rs new file +0 -0
rust/xdiff/Cargo.toml new file +15 -0
@@ -0,0 +1,15 @@ +[package] +name = "xdiff" +version = "0.1.0" +edition = "2021" + +[lib] +name = "xdiff" +path = "src/lib.rs" +## staticlib to generate xdiff.a for use by gcc +## cdylib (optional) to generate xdiff.so for use by gcc +## rlib is required by the rust unit tests +crate-type = ["staticlib", "rlib"] + +[dependencies] +interop = { path = "../interop" }
rust/xdiff/src/lib.rs new file +0 -0
Signature · 1 line
gitgitgadget
PATCH 3/15 github workflows: install rust
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Prefer using actions-rs/toolchain@v1 where possible to install rustup, but for docker targets use a script to install rustup. Consolidate the Rust toolchain definitions in main.yaml. Use install-rust-toolchain.sh to ensure the correct toolchain is used. Five overrides are used in main.yaml:
* On Windows: Rust didn't resolve the bcrypt library on Windows correctly until version 1.78.0. Also since rustup mis-identifies the Rust toolchain, the Rust target triple must be set to x86_64-pc-windows-gnu for make (win build), and x86_64-pc-windows-msvc for meson (win+Meson build).
* On musl: libc differences, such as ftruncate64 vs ftruncate, were not accounted for until Rust version 1.72.0. No older version of Rust will work on musl for our needs.
* In a 32-bit docker container running on a 64-bit host, we need to override the Rust target triple. This is because rustup asks the kernel for the bitness of the system and it says 64, even though the container is 32-bit. This also allows us to remove the BITNESS environment variable in ci/lib.sh.
The logic for selecting library names was initially provided in a patch from Johannes, but was reworked and squashed into this commit.
--- .github/workflows/main.yml | 60 +++++++++++++++++++++++++++++++++++- ci/install-dependencies.sh | 14 ++++----- ci/install-rust-toolchain.sh | 30 ++++++++++++++++++ ci/install-rustup.sh | 25 +++++++++++++++ ci/lib.sh | 1 + ci/make-test-artifacts.sh | 9 ++++++ ci/run-build-and-tests.sh | 13 ++++++++ 7 files changed, 144 insertions(+), 8 deletions(-) create mode 100755 ci/install-rust-toolchain.sh create mode 100755 ci/install-rustup.sh
.github/workflows/main.yml +59 -1
@@ -26,6 +26,13 @@ jobs: outputs: enabled: ${{ steps.check-ref.outputs.enabled }}${{ steps.skip-if-redundant.outputs.enabled }} skip_concurrent: ${{ steps.check-ref.outputs.skip_concurrent }} + rust_version_minimum: 1.61.0 + rust_version_windows: 1.78.0 + rust_version_musl: 1.72.0 + ## the rust target is inferred by rustup unless specified + rust_target_windows_make: x86_64-pc-windows-gnu + rust_target_windows_meson: x86_64-pc-windows-msvc + rust_target_32bit_linux: i686-unknown-linux-gnu steps: - name: try to clone ci-config branch run: |
@@ -108,12 +115,26 @@ jobs: needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' runs-on: windows-latest + env: + CARGO_HOME: "/c/Users/runneradmin/.cargo" concurrency: group: windows-build-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v4 - uses: git-for-windows/setup-git-for-windows-sdk@v1 + - name: Install rustup via github actions + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: false + - name: Install Rust toolchain + shell: bash + env: + RUST_VERSION: ${{ needs.ci-config.outputs.rust_version_windows }} + RUST_TARGET: ${{ needs.ci-config.outputs.rust_target_windows_make }} + run: ci/install-rust-toolchain.sh - name: build shell: bash env:
@@ -254,12 +275,26 @@ jobs: needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' runs-on: windows-latest + env: + CARGO_HOME: "/c/Users/runneradmin/.cargo" concurrency: group: windows-meson-build-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 + - name: Install rustup via github actions + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: false + - name: Install Rust toolchain + shell: bash + env: + RUST_VERSION: ${{ needs.ci-config.outputs.rust_version_windows }} + RUST_TARGET: ${{ needs.ci-config.outputs.rust_target_windows_meson }} + run: ci/install-rust-toolchain.sh - name: Set up dependencies shell: pwsh run: pip install meson ninja
@@ -329,11 +364,24 @@ jobs: jobname: ${{matrix.vector.jobname}} CI_JOB_IMAGE: ${{matrix.vector.pool}} TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t + CARGO_HOME: "/Users/runner/.cargo" runs-on: ${{matrix.vector.pool}} steps: - uses: actions/checkout@v4 - run: ci/install-dependencies.sh - - run: ci/run-build-and-tests.sh + - name: Install rustup via github actions + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: false + - name: Install Rust toolchain + shell: bash + env: + RUST_VERSION: ${{ needs.ci-config.outputs.rust_version_minimum }} + run: ci/install-rust-toolchain.sh + - name: Run build and tests + run: ci/run-build-and-tests.sh - name: print test failures if: failure() && env.FAILED_TEST_ARTIFACTS != '' run: ci/print-test-failures.sh
@@ -393,9 +441,11 @@ jobs: cc: gcc - jobname: linux-musl-meson image: alpine:latest + rust_version_override: ${{ needs.ci-config.outputs.rust_version_musl }} # Supported until 2025-04-02. - jobname: linux32 image: i386/ubuntu:focal + rust_target_override: ${{ needs.ci-config.outputs.rust_target_32bit_linux }} - jobname: pedantic image: fedora:latest # A RHEL 8 compatible distro. Supported until 2029-05-31.
@@ -409,6 +459,7 @@ jobs: CC: ${{matrix.vector.cc}} CI_JOB_IMAGE: ${{matrix.vector.image}} CUSTOM_PATH: /custom + CARGO_HOME: /home/builder/.cargo runs-on: ubuntu-latest container: ${{matrix.vector.image}} steps:
@@ -433,6 +484,13 @@ jobs: - run: ci/install-dependencies.sh - run: useradd builder --create-home - run: chown -R builder . + - name: Install rustup via script + run: sudo --preserve-env --set-home --user=builder ci/install-rustup.sh + - name: Install Rust toolchain + env: + RUST_VERSION: ${{ matrix.vector.rust_version_override || needs.ci-config.outputs.rust_version_minimum }} + RUST_TARGET: ${{ matrix.vector.rust_target_override || '' }} + run: sudo --preserve-env --set-home --user=builder ci/install-rust-toolchain.sh - run: sudo --preserve-env --set-home --user=builder ci/run-build-and-tests.sh - name: print test failures if: failure() && env.FAILED_TEST_ARTIFACTS != ''
ci/install-dependencies.sh +7 -7
@@ -24,14 +24,14 @@ fi case "$distro" in alpine-*) - apk add --update shadow sudo meson ninja-build gcc libc-dev curl-dev openssl-dev expat-dev gettext \ + apk add --update shadow sudo meson ninja-build gcc libc-dev curl curl-dev openssl-dev expat-dev gettext \ zlib-ng-dev pcre2-dev python3 musl-libintl perl-utils ncurses \ apache2 apache2-http2 apache2-proxy apache2-ssl apache2-webdav apr-util-dbd_sqlite3 \ bash cvs gnupg perl-cgi perl-dbd-sqlite perl-io-tty >/dev/null ;; fedora-*|almalinux-*) dnf -yq update >/dev/null && - dnf -yq install shadow-utils sudo make gcc findutils diffutils perl python3 gawk gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null + dnf -yq install shadow-utils sudo make gcc findutils diffutils perl python3 gawk gettext zlib-devel expat-devel openssl-devel curl curl-devel pcre2-devel >/dev/null ;; ubuntu-*|i386/ubuntu-*|debian-*) # Required so that apt doesn't wait for user input on certain packages.
@@ -55,8 +55,8 @@ ubuntu-*|i386/ubuntu-*|debian-*) sudo apt-get -q update sudo apt-get -q -y install \ $LANGUAGES apache2 cvs cvsps git gnupg $SVN \ - make libssl-dev libcurl4-openssl-dev libexpat-dev wget sudo default-jre \ - tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \ + make libssl-dev curl libcurl4-openssl-dev libexpat-dev wget sudo default-jre \ + tcl tk gettext zlib1g zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \ libemail-valid-perl libio-pty-perl libio-socket-ssl-perl libnet-smtp-ssl-perl libdbd-sqlite3-perl libcgi-pm-perl \ libsecret-1-dev libpcre2-dev meson ninja-build pkg-config \ ${CC_PACKAGE:-${CC:-gcc}} $PYTHON_PACKAGE
@@ -121,13 +121,13 @@ ClangFormat) ;; StaticAnalysis) sudo apt-get -q update - sudo apt-get -q -y install coccinelle libcurl4-openssl-dev libssl-dev \ + sudo apt-get -q -y install coccinelle curl libcurl4-openssl-dev libssl-dev \ libexpat-dev gettext make ;; sparse) sudo apt-get -q update -q - sudo apt-get -q -y install libssl-dev libcurl4-openssl-dev \ - libexpat-dev gettext zlib1g-dev sparse + sudo apt-get -q -y install libssl-dev curl libcurl4-openssl-dev \ + libexpat-dev gettext zlib1g zlib1g-dev sparse ;; Documentation) sudo apt-get -q update
ci/install-rust-toolchain.sh new file +30 -0
@@ -0,0 +1,30 @@ +#!/bin/sh + +if [ "$CARGO_HOME" = "" ]; then + echo >&2 "::error:: CARGO_HOME is not set" + exit 2 +fi +export PATH="$CARGO_HOME/bin:$PATH" +rustup -vV || exit $? + +## Enforce the correct Rust toolchain +rustup override unset || true + +## install a specific version of rust +if [ "$RUST_TARGET" != "" ]; then + rustup default --force-non-host "$RUST_VERSION-$RUST_TARGET" || exit $? +else + rustup default "$RUST_VERSION" || exit $? +fi + +rustc -vV || exit $? + +RE_RUST_TARGET="$RUST_TARGET" +if [ "$RUST_TARGET" = "" ]; then + RE_RUST_TARGET="[^ ]+" +fi + +if ! rustup show active-toolchain | grep -E "^$RUST_VERSION-$RE_RUST_TARGET \(default\)$"; then + echo >&2 "::error:: wrong Rust toolchain, active-toolchain: $(rustup show active-toolchain)" + exit 3 +fi
ci/install-rustup.sh new file +25 -0
@@ -0,0 +1,25 @@ +#!/bin/sh + +## github workflows actions-rs/toolchain@v1 doesn't work for docker +## targets. This script should only be used if the ci pipeline +## doesn't support installing rust on a particular target. + +if [ "$(id -u)" -eq 0 ]; then + echo >&2 "::warning:: installing rust as root" +fi + +if [ "$CARGO_HOME" = "" ]; then + echo >&2 "::error:: CARGO_HOME is not set" + exit 2 +fi + +export RUSTUP_HOME=$CARGO_HOME + +## install rustup +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y +if [ ! -f $CARGO_HOME/env ]; then + echo "PATH=$CARGO_HOME/bin:\$PATH" > $CARGO_HOME/env +fi +. $CARGO_HOME/env + +rustup -vV
ci/lib.sh +1 -0
@@ -1,5 +1,6 @@ # Library of functions shared by all CI scripts + if test true = "$GITHUB_ACTIONS" then begin_group () {
ci/make-test-artifacts.sh +9 -0
@@ -7,6 +7,15 @@ mkdir -p "$1" # in case ci/lib.sh decides to quit early . ${0%/*}/lib.sh +## ensure rustup is in the PATH variable +if [ "$CARGO_HOME" = "" ]; then + echo >&2 "::error:: CARGO_HOME is not set" + exit 2 +fi +export PATH="$CARGO_HOME/bin:$PATH" + +rustc -vV + group Build make artifacts-tar ARTIFACTS_DIRECTORY="$1" check_unignored_build_artifacts
ci/run-build-and-tests.sh +13 -0
@@ -5,6 +5,15 @@ . ${0%/*}/lib.sh +## ensure rustup is in the PATH variable +if [ "$CARGO_HOME" = "" ]; then + echo >&2 "::error:: CARGO_HOME is not set" + exit 2 +fi +. $CARGO_HOME/env + +rustc -vV || exit $? + run_tests=t case "$jobname" in
@@ -72,5 +81,9 @@ case "$jobname" in ;; esac +if [ -d "$CARGO_HOME" ]; then + rm -rf $CARGO_HOME +fi + check_unignored_build_artifacts save_good_tree
Signature · 1 line
gitgitgadget
PATCH 4/15 win+Meson: do allow linking with the Rust-built xdiff
In reply to Ezekiel Newren via GitGitGadgetFrom: Johannes Schindelin <[email protected]>
When linking against the Rust-built xdiff, there is now a new required
dependency: Without _also_ linking to the system library userenv, the compile would fail with this error message:
xdiff.lib(std-c85e9beb7923f636.std.df32d1bc89881d89-cgu.0.rcgu.o) :
error LNK2019: unresolved external symbol __imp_GetUserProfileDirectoryW referenced in function _ZN3std3env8home_dir17hfd1c3b6676cd78f6E
Therefore, just like we do in case of Makefile-based builds on Windows, we now also link to that library when building with Meson.
Note that if we only have Rust depend upon libuserenv then at link time GCC would complain about:
undefined reference to `GetUserProfileDirectoryW'
Apparently there is _some_ closure that gets compiled in that requires this function, and that in turn forces Git to link to libuserenv.
This is a new requirement, and therefore has not been made part of the "minimal Git for Windows SDK".
In the near future, I intend to include it, but for now let's just ensure that the file is added manually if it is missing.
[en: Squashed a few of Johannes's patches, and moved lib userenv
handling from an earlier patch]
--- .github/workflows/main.yml | 8 ++++++++ config.mak.uname | 4 ++++ meson.build | 1 + 3 files changed, 13 insertions(+)
.github/workflows/main.yml +8 -0
@@ -123,6 +123,14 @@ jobs: steps: - uses: actions/checkout@v4 - uses: git-for-windows/setup-git-for-windows-sdk@v1 + - name: ensure that libuserenv.a is present + shell: bash + run: | + cd /mingw64/lib && { + test -f libuserenv.a || + /c/Program\ Files/Git/mingw64/bin/curl -Lo libuserenv.a \ + https://github.com/git-for-windows/git-sdk-64/raw/HEAD/mingw64/lib/libuserenv.a + } - name: Install rustup via github actions uses: actions-rs/toolchain@v1 with:
config.mak.uname +4 -0
@@ -740,6 +740,10 @@ ifeq ($(uname_S),MINGW) COMPAT_CFLAGS += -D_USE_32BIT_TIME_T BASIC_LDFLAGS += -Wl,--large-address-aware endif + + # Unfortunately now needed because of Rust + EXTLIBS += -luserenv + CC = gcc COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \ -fstack-protector-strong
meson.build +1 -0
@@ -1267,6 +1267,7 @@ elif host_machine.system() == 'windows' ] libgit_dependencies += compiler.find_library('ntdll') + libgit_dependencies += compiler.find_library('userenv') libgit_include_directories += 'compat/win32' if compiler.get_id() == 'msvc' libgit_include_directories += 'compat/vcbuild/include'
Signature · 1 line
gitgitgadget
PATCH 5/15 github workflows: upload Cargo.lock
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Make each ci workflow upload its Cargo.lock file as a build artifact so that we can audit build dependencies.
--- .github/workflows/main.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
.github/workflows/main.yml +20 -0
@@ -156,6 +156,11 @@ jobs: with: name: windows-artifacts path: artifacts + - name: upload Cargo.lock + uses: actions/upload-artifact@v4 + with: + name: cargo-lock-windows + path: rust/Cargo.lock windows-test: name: win test runs-on: windows-latest
@@ -317,6 +322,11 @@ jobs: with: name: windows-meson-artifacts path: build + - name: Upload Cargo.lock + uses: actions/upload-artifact@v4 + with: + name: cargo-lock-windows-meson + path: rust/Cargo.lock windows-meson-test: name: win+Meson test runs-on: windows-latest
@@ -399,6 +409,11 @@ jobs: with: name: failed-tests-${{matrix.vector.jobname}} path: ${{env.FAILED_TEST_ARTIFACTS}} + - name: Upload Cargo.lock + uses: actions/upload-artifact@v4 + with: + name: cargo-lock-${{matrix.vector.jobname}} + path: rust/Cargo.lock fuzz-smoke-test: name: fuzz smoke test needs: ci-config
@@ -509,6 +524,11 @@ jobs: with: name: failed-tests-${{matrix.vector.jobname}} path: ${{env.FAILED_TEST_ARTIFACTS}} + - name: Upload Cargo.lock + uses: actions/upload-artifact@v4 + with: + name: cargo-lock-${{matrix.vector.jobname}} + path: rust/Cargo.lock static-analysis: needs: ci-config if: needs.ci-config.outputs.enabled == 'yes'
Signature · 1 line
gitgitgadget
PATCH 6/15 ivec: create a vector type that is interoperable between C and Rust
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Trying to use Rust's Vec in C, or git's ALLOC_GROW() macros (via wrapper functions) in Rust is painful because:
* C doing vector things the Rust way would require wrapper functions, and Rust doing vector things the C way would require wrapper functions, so ivec was created to ensure a consistent contract between the 2 languages for how to manipulate a vector.
* Currently, Rust defines its own 'Vec' type that is generic, but its memory allocator and struct layout weren't designed for interoperability with C (or any language for that matter), meaning that the C side cannot push to or expand a 'Vec' without defining wrapper functions in Rust that C can call. Without special care, the two languages might use different allocators (malloc/free on the C side, and possibly something else in Rust), which would make it difficult for a function in one language to free elements allocated by a call from a function in the other language.
* Similarly, git defines ALLOC_GROW() and related macros in git-compat-util.h. While we could add functions allowing Rust to invoke something similar to those macros, passing three variables (pointer, length, allocated_size) instead of a single variable (vector) across the language boundary requires more cognitive overhead for readers to keep track of and makes it easier to make mistakes. Further, for low-level components that we want to eventually convert to pure Rust, such triplets would feel very out of place.
To address these issue, introduce a new type, ivec -- short for interoperable vector. (We refer to it as 'ivec' generally, though on the Rust side the struct is called IVec to match Rust style.) This new type is specifically designed for FFI purposes, so that both languages handle the vector in the same way, though it could be used on either side independently. This type is designed such that it can easily be replaced by a standard Rust 'Vec' once interoperability is no longer a concern.
One particular item to note is that Git's macros to handle vec operations infer the amount that a vec needs to grow from the size of a pointer, but that makes it somewhat specific to the macros used in C. To avoid defining every ivec function as a macro I opted to also include an element_size field that allows concrete functions like push() to know how much to grow the memory. This element_size also helps in verifying that the ivec is correct when passing from C to Rust.
--- Makefile | 14 +- interop/ivec.c | 180 ++++++++++++++ interop/ivec.h | 60 +++++ meson.build | 1 + rust/interop/src/ivec.rs | 516 +++++++++++++++++++++++++++++++++++++++ rust/interop/src/lib.rs | 10 + 6 files changed, 778 insertions(+), 3 deletions(-) create mode 100644 interop/ivec.c create mode 100644 interop/ivec.h create mode 100644 rust/interop/src/ivec.rs
Makefile +11 -3
@@ -672,6 +672,7 @@ BUILTIN_OBJS = BUILT_INS = COMPAT_CFLAGS = COMPAT_OBJS = +INTEROP_OBJS = XDIFF_OBJS = GENERATED_H = EXTRA_CPPFLAGS =
@@ -918,6 +919,7 @@ export PYTHON_PATH TEST_SHELL_PATH = $(SHELL_PATH) LIB_FILE = libgit.a +INTEROP_LIB = interop/lib.a XDIFF_LIB = xdiff/lib.a EXTLIBS =
@@ -1412,7 +1414,7 @@ UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o # xdiff and reftable libs may in turn depend on what is in libgit.a -GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE) +GITLIBS = common-main.o $(LIB_FILE) $(INTEROP_LIB) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE) GIT_USER_AGENT = git/$(GIT_VERSION)
@@ -2747,6 +2749,8 @@ reconfigure config.mak.autogen: config.status .PHONY: reconfigure # This is a convenience target. endif +INTEROP_OBJS += interop/ivec.o + XDIFF_OBJS += xdiff/xdiffi.o XDIFF_OBJS += xdiff/xemit.o XDIFF_OBJS += xdiff/xhistogram.o
@@ -2791,6 +2795,7 @@ OBJECTS += $(GIT_OBJS) OBJECTS += $(SCALAR_OBJS) OBJECTS += $(PROGRAM_OBJS) OBJECTS += $(TEST_OBJS) +OBJECTS += $(INTEROP_OBJS) OBJECTS += $(XDIFF_OBJS) OBJECTS += $(FUZZ_OBJS) OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS)
@@ -2945,7 +2950,10 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS) compile_rust $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ -$(XDIFF_LIB): $(XDIFF_OBJS) +$(INTEROP_LIB): $(INTEROP_OBJS) + $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ + +$(XDIFF_LIB): $(INTEROP_OBJS) $(XDIFF_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
@@ -3790,7 +3798,7 @@ clean: profile-clean coverage-clean cocciclean rustclean $(RM) git.rc git.res $(RM) $(OBJECTS) $(RM) headless-git.o - $(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) + $(RM) $(LIB_FILE) $(INTEROP_LIB) $(XDIFF_LIB) $(REFTABLE_LIB) $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) $(RM) $(TEST_PROGRAMS) $(RM) $(FUZZ_PROGRAMS)
interop/ivec.c new file +180 -0
180 lines not on this page · raw message
interop/ivec.h new file +60 -0
60 lines not on this page · raw message
meson.build +1 -0
@@ -395,6 +395,7 @@ libgit_sources = [ 'hex-ll.c', 'hook.c', 'ident.c', + 'interop/ivec.c', 'json-writer.c', 'kwset.c', 'levenshtein.c',
rust/interop/src/ivec.rs new file +516 -0
516 lines not on this page · raw message
rust/interop/src/lib.rs +10 -0
@@ -0,0 +1,10 @@ +pub mod ivec; + +use std::ffi::c_void; + +extern "C" { +pub fn malloc (size:usize ) -> *mut c_void ; +pub fn calloc (nmemb:usize , size:usize ) -> *mut c_void ; +pub fn realloc (ptr: *mut c_void , size:usize ) -> *mut c_void ; +pub fn free (ptr: *mut c_void ); +}
Signature · 1 line
gitgitgadget
PATCH 7/15 xdiff/xprepare: remove superfluous forward declarations
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Move xdl_prepare_env() later in the file to avoid the need for forward declarations.
--- xdiff/xprepare.c | 116 ++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 66 deletions(-)
xdiff/xprepare.c +50 -66
@@ -53,21 +53,6 @@ typedef struct s_xdlclassifier { -static int xdl_init_classifier (xdlclassifier_t *cf,long size,long flags); -static void xdl_free_classifier (xdlclassifier_t *cf); -static int xdl_classify_record (unsigned int pass,xdlclassifier_t *cf,xrecord_t **rhash, -unsigned int hbits,xrecord_t *rec); -static int xdl_prepare_ctx (unsigned int pass,mmfile_t *mf,long narec,xpparam_t const *xpp, -xdlclassifier_t *cf,xdfile_t *xdf); -static void xdl_free_ctx (xdfile_t *xdf); -static int xdl_clean_mmatch (char const *dis,long i,long s,long e); -static int xdl_cleanup_records (xdlclassifier_t *cf,xdfile_t *xdf1,xdfile_t *xdf2); -static int xdl_trim_ends (xdfile_t *xdf1,xdfile_t *xdf2); -static int xdl_optimize_ctxs (xdlclassifier_t *cf,xdfile_t *xdf1,xdfile_t *xdf2); - - - -static int xdl_init_classifier (xdlclassifier_t *cf,long size,long flags) { cf->flags = flags;
@@ -242,57 +227,6 @@ static void xdl_free_ctx(xdfile_t *xdf) { } -int xdl_prepare_env (mmfile_t *mf1,mmfile_t *mf2,xpparam_t const *xpp, -xdfenv_t *xe) { -long enl1, enl2, sample; -xdlclassifier_t cf; - -memset (&cf,0 ,sizeof (cf)); - -/* -* For histogram diff, we can afford a smaller sample size and -* thus a poorer estimate of the number of lines, as the hash -* table (rhash) won't be filled up/grown. The number of lines -* (nrecs) will be updated correctly anyway by -* xdl_prepare_ctx(). -*/ - sample = (XDF_DIFF_ALG (xpp->flags) ==XDF_HISTOGRAM_DIFF - ?XDL_GUESS_NLINES2 :XDL_GUESS_NLINES1 ); - - enl1 =xdl_guess_lines (mf1, sample) +1 ; - enl2 =xdl_guess_lines (mf2, sample) +1 ; - -if (xdl_init_classifier (&cf, enl1 + enl2 +1 , xpp->flags) <0 ) -return -1 ; - -if (xdl_prepare_ctx (1 , mf1, enl1, xpp, &cf, &xe->xdf1) <0 ) { - -xdl_free_classifier (&cf); -return -1 ; - } -if (xdl_prepare_ctx (2 , mf2, enl2, xpp, &cf, &xe->xdf2) <0 ) { - -xdl_free_ctx (&xe->xdf1); -xdl_free_classifier (&cf); -return -1 ; - } - -if ((XDF_DIFF_ALG (xpp->flags) !=XDF_PATIENCE_DIFF ) && - (XDF_DIFF_ALG (xpp->flags) !=XDF_HISTOGRAM_DIFF ) && -xdl_optimize_ctxs (&cf, &xe->xdf1, &xe->xdf2) <0 ) { - -xdl_free_ctx (&xe->xdf2); -xdl_free_ctx (&xe->xdf1); -xdl_free_classifier (&cf); -return -1 ; - } - -xdl_free_classifier (&cf); - -return 0 ; -} - -void xdl_free_env (xdfenv_t *xe) {xdl_free_ctx (&xe->xdf2);
@@ -460,3 +394,53 @@ static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2return 0 ; } + +int xdl_prepare_env (mmfile_t *mf1,mmfile_t *mf2,xpparam_t const *xpp, +xdfenv_t *xe) { +long enl1, enl2, sample; +xdlclassifier_t cf; + +memset (&cf,0 ,sizeof (cf)); + +/* +* For histogram diff, we can afford a smaller sample size and +* thus a poorer estimate of the number of lines, as the hash +* table (rhash) won't be filled up/grown. The number of lines +* (nrecs) will be updated correctly anyway by +* xdl_prepare_ctx(). +*/ + sample = (XDF_DIFF_ALG (xpp->flags) ==XDF_HISTOGRAM_DIFF + ?XDL_GUESS_NLINES2 :XDL_GUESS_NLINES1 ); + + enl1 =xdl_guess_lines (mf1, sample) +1 ; + enl2 =xdl_guess_lines (mf2, sample) +1 ; + +if (xdl_init_classifier (&cf, enl1 + enl2 +1 , xpp->flags) <0 ) +return -1 ; + +if (xdl_prepare_ctx (1 , mf1, enl1, xpp, &cf, &xe->xdf1) <0 ) { + +xdl_free_classifier (&cf); +return -1 ; + } +if (xdl_prepare_ctx (2 , mf2, enl2, xpp, &cf, &xe->xdf2) <0 ) { + +xdl_free_ctx (&xe->xdf1); +xdl_free_classifier (&cf); +return -1 ; + } + +if ((XDF_DIFF_ALG (xpp->flags) !=XDF_PATIENCE_DIFF ) && + (XDF_DIFF_ALG (xpp->flags) !=XDF_HISTOGRAM_DIFF ) && +xdl_optimize_ctxs (&cf, &xe->xdf1, &xe->xdf2) <0 ) { + +xdl_free_ctx (&xe->xdf2); +xdl_free_ctx (&xe->xdf1); +xdl_free_classifier (&cf); +return -1 ; + } + +xdl_free_classifier (&cf); + +return 0 ; +}
Signature · 1 line
gitgitgadget
PATCH 8/15 xdiff: delete unnecessary fields from xrecord_t and xdfile_t
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
xrecord_t.next, xdfile_t.hbits, xdfile_t.rhash are initialized, but never used for anything by the code. Remove them.
--- xdiff/xprepare.c | 24 +++--------------------- xdiff/xtypes.h | 3 --- 2 files changed, 3 insertions(+), 24 deletions(-)
xdiff/xprepare.c +3 -21
@@ -91,8 +91,7 @@ static void xdl_free_classifier(xdlclassifier_t *cf) { } -static int xdl_classify_record (unsigned int pass,xdlclassifier_t *cf,xrecord_t **rhash, -unsigned int hbits,xrecord_t *rec) { +static int xdl_classify_record (unsigned int pass,xdlclassifier_t *cf,xrecord_t *rec) {long hi;char const *line;xdlclass_t *rcrec;
@@ -126,23 +125,17 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t rec->ha = (unsigned long ) rcrec->idx; - hi = (long )XDL_HASHLONG (rec->ha, hbits); - rec->next = rhash[hi]; - rhash[hi] = rec; -return 0 ; }static int xdl_prepare_ctx (unsigned int pass,mmfile_t *mf,long narec,xpparam_t const *xpp,xdlclassifier_t *cf,xdfile_t *xdf) { -unsigned int hbits; -long nrec, hsize, bsize; +long nrec, bsize;unsigned long hav;char const *blk, *cur, *top, *prev;xrecord_t *crec;xrecord_t **recs; -xrecord_t **rhash;unsigned long *ha;char *rchg;long *rindex;
@@ -150,7 +143,6 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ ha =NULL ; rindex =NULL ; rchg =NULL ; - rhash =NULL ; recs =NULL ;if (xdl_cha_init (&xdf->rcha,sizeof (xrecord_t), narec /4 +1 ) <0 )
@@ -158,11 +150,6 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_if (!XDL_ALLOC_ARRAY (recs, narec)) goto abort; - hbits =xdl_hashbits ((unsigned int ) narec); - hsize =1 << hbits; -if (!XDL_CALLOC_ARRAY (rhash, hsize)) - goto abort; - nrec =0 ;if ((cur = blk =xdl_mmfile_first (mf, &bsize))) {for (top = blk + bsize; cur < top; ) {
@@ -176,7 +163,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ crec->size = (long ) (cur - prev); crec->ha = hav; recs[nrec++] = crec; -if (xdl_classify_record (pass, cf, rhash, hbits, crec) <0 ) +if (xdl_classify_record (pass, cf, crec) <0 ) goto abort; } }
@@ -194,8 +181,6 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ xdf->nrec = nrec; xdf->recs = recs; - xdf->hbits = hbits; - xdf->rhash = rhash; xdf->rchg = rchg +1 ; xdf->rindex = rindex; xdf->nreff =0 ;
@@ -209,7 +194,6 @@ abort:xdl_free (ha);xdl_free (rindex);xdl_free (rchg); -xdl_free (rhash);xdl_free (recs);xdl_cha_free (&xdf->rcha);return -1 ;
@@ -217,8 +201,6 @@ abort:static void xdl_free_ctx (xdfile_t *xdf) { - -xdl_free (xdf->rhash);xdl_free (xdf->rindex);xdl_free (xdf->rchg -1 );xdl_free (xdf->ha);
xdiff/xtypes.h +0 -3
@@ -39,7 +39,6 @@ typedef struct s_chastore { } chastore_t; typedef struct s_xrecord { - struct s_xrecord *next; char const *ptr; long size; unsigned long ha;
@@ -48,8 +47,6 @@ typedef struct s_xrecord { typedef struct s_xdfile { chastore_t rcha; long nrec; - unsigned int hbits; - xrecord_t **rhash; long dstart, dend; xrecord_t **recs; char *rchg;
Signature · 1 line
gitgitgadget
PATCH 9/15 xdiff: make fields of xrecord_t Rust friendly
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
A few commits ago, we added definitions for Rust primitive types, to facilitate interoperability between C and Rust. Switch a few variables to use these types. Which, for now, will require adding some casts.
Also change xdlclass_t::ha to be u64 to match xrecord_t::ha, as pointed out by Johannes.
--- xdiff/xdiffi.c | 8 ++++---- xdiff/xemit.c | 2 +- xdiff/xmerge.c | 14 +++++++------- xdiff/xpatience.c | 2 +- xdiff/xprepare.c | 8 ++++---- xdiff/xtypes.h | 6 +++--- xdiff/xutils.c | 4 ++-- 7 files changed, 22 insertions(+), 22 deletions(-)
xdiff/xdiffi.c +4 -4
@@ -418,7 +418,7 @@ static int get_indent(xrecord_t *rec)long i;int ret =0 ; -for (i =0 ; i < rec->size; i++) { +for (i =0 ; i < (long ) rec->size; i++) {char c = rec->ptr[i];if (!XDL_ISSPACE (c))
@@ -1005,11 +1005,11 @@ static void xdl_mark_ignorable_lines(xdchange_t *xscr, xdfenv_t *xe, long flags) rec = &xe->xdf1.recs[xch->i1];for (i =0 ; i < xch->chg1 && ignore; i++) - ignore =xdl_blankline (rec[i]->ptr, rec[i]->size, flags); + ignore =xdl_blankline ((const char *) rec[i]->ptr, rec[i]->size, flags); rec = &xe->xdf2.recs[xch->i2];for (i =0 ; i < xch->chg2 && ignore; i++) - ignore =xdl_blankline (rec[i]->ptr, rec[i]->size, flags); + ignore =xdl_blankline ((const char *)rec[i]->ptr, rec[i]->size, flags); xch->ignore = ignore; }
@@ -1020,7 +1020,7 @@ static int record_matches_regex(xrecord_t *rec, xpparam_t const *xpp) {size_t i;for (i =0 ; i < xpp->ignore_regex_nr; i++) -if (!regexec_buf (xpp->ignore_regex[i], rec->ptr, rec->size,1 , +if (!regexec_buf (xpp->ignore_regex[i], (const char *) rec->ptr, rec->size,1 , ®match,0 ))return 1 ;
xdiff/xemit.c +1 -1
@@ -24,7 +24,7 @@static long xdl_get_rec (xdfile_t *xdf,long ri,char const **rec) { - *rec = xdf->recs[ri]->ptr; + *rec = (char const *) xdf->recs[ri]->ptr;return xdf->recs[ri]->size; }
xdiff/xmerge.c +7 -7
@@ -101,8 +101,8 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,xrecord_t **rec2 = xe2->xdf2.recs + i2;for (i =0 ; i < line_count; i++) { -int result =xdl_recmatch (rec1[i]->ptr, rec1[i]->size, - rec2[i]->ptr, rec2[i]->size, flags); +int result =xdl_recmatch ((const char *) rec1[i]->ptr, rec1[i]->size, + (const char *) rec2[i]->ptr, rec2[i]->size, flags);if (!result)return -1 ; }
@@ -324,8 +324,8 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,static int recmatch (xrecord_t *rec1,xrecord_t *rec2,unsigned long flags) { -return xdl_recmatch (rec1->ptr, rec1->size, - rec2->ptr, rec2->size, flags); +return xdl_recmatch ((char const *) rec1->ptr, rec1->size, + (char const *) rec2->ptr, rec2->size, flags); }/*
@@ -383,10 +383,10 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,*/ t1.ptr = (char *)xe1->xdf2.recs[m->i1]->ptr; t1.size = xe1->xdf2.recs[m->i1 + m->chg1 -1 ]->ptr - + xe1->xdf2.recs[m->i1 + m->chg1 -1 ]->size - t1.ptr; + + xe1->xdf2.recs[m->i1 + m->chg1 -1 ]->size - (u8 const *) t1.ptr; t2.ptr = (char *)xe2->xdf2.recs[m->i2]->ptr; t2.size = xe2->xdf2.recs[m->i2 + m->chg2 -1 ]->ptr - + xe2->xdf2.recs[m->i2 + m->chg2 -1 ]->size - t2.ptr; + + xe2->xdf2.recs[m->i2 + m->chg2 -1 ]->size - (u8 const *) t2.ptr;if (xdl_do_diff (&t1, &t2, xpp, &xe) <0 )return -1 ; if (xdl_change_compact(&xe.xdf1, &xe.xdf2, xpp->flags) < 0 ||
@@ -440,7 +440,7 @@ static int line_contains_alnum(const char *ptr, long size)static int lines_contain_alnum (xdfenv_t *xe,int i,int chg) {for (; chg; chg--, i++) -if (line_contains_alnum (xe->xdf2.recs[i]->ptr, +if (line_contains_alnum ((char const *) xe->xdf2.recs[i]->ptr, xe->xdf2.recs[i]->size))return 1 ;return 0 ;
xdiff/xpatience.c +1 -1
@@ -121,7 +121,7 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,return ; map->entries[index].line1 = line; map->entries[index].hash = record->ha; - map->entries[index].anchor =is_anchor (xpp, map->env->xdf1.recs[line -1 ]->ptr); + map->entries[index].anchor =is_anchor (xpp, (const char *) map->env->xdf1.recs[line -1 ]->ptr);if (!map->first) map->first = map->entries + index;if (map->last) {
xdiff/xprepare.c +4 -4
@@ -32,7 +32,7 @@ typedef struct s_xdlclass { struct s_xdlclass *next; - unsigned long ha; + u64 ha; char const *line; long size; long idx;
@@ -96,12 +96,12 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_tchar const *line;xdlclass_t *rcrec; - line = rec->ptr; + line = (char const *) rec->ptr; hi = (long )XDL_HASHLONG (rec->ha, cf->hbits);for (rcrec = cf->rchash[hi]; rcrec; rcrec = rcrec->next)if (rcrec->ha == rec->ha &&xdl_recmatch (rcrec->line, rcrec->size, - rec->ptr, rec->size, cf->flags)) + (const char *) rec->ptr, rec->size, cf->flags))break ;if (!rcrec) {
@@ -159,7 +159,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ goto abort;if (!(crec =xdl_cha_alloc (&xdf->rcha))) goto abort; - crec->ptr = prev; + crec->ptr = (u8 const *) prev; crec->size = (long ) (cur - prev); crec->ha = hav; recs[nrec++] = crec;
xdiff/xtypes.h +3 -3
@@ -39,9 +39,9 @@ typedef struct s_chastore { } chastore_t;typedef struct s_xrecord { -char const *ptr; -long size; -unsigned long ha; +u8 const * ptr; +usize size; +u64 ha; }xrecord_t ; typedef struct s_xdfile {
xdiff/xutils.c +2 -2
@@ -418,10 +418,10 @@ int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp, subfile1.ptr = (char *)diff_env->xdf1.recs[line1 -1 ]->ptr; subfile1.size = diff_env->xdf1.recs[line1 + count1 -2 ]->ptr + - diff_env->xdf1.recs[line1 + count1 -2 ]->size - subfile1.ptr; + diff_env->xdf1.recs[line1 + count1 -2 ]->size - (u8 const *) subfile1.ptr; subfile2.ptr = (char *)diff_env->xdf2.recs[line2 -1 ]->ptr; subfile2.size = diff_env->xdf2.recs[line2 + count2 -2 ]->ptr + - diff_env->xdf2.recs[line2 + count2 -2 ]->size - subfile2.ptr; + diff_env->xdf2.recs[line2 + count2 -2 ]->size - (u8 const *) subfile2.ptr;if (xdl_do_diff (&subfile1, &subfile2, xpp, &env) <0 )return -1 ;
Signature · 1 line
gitgitgadget
PATCH 10/15 xdiff: use one definition for freeing xdfile_t
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Simplify xdl_prepare_ctx() by using xdl_free_ctx() instead of using local variables with hand rolled memory management.
--- xdiff/xprepare.c | 60 +++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 36 deletions(-)
xdiff/xprepare.c +24 -36
@@ -129,86 +129,74 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t } +static void xdl_free_ctx (xdfile_t *xdf) { +xdl_free (xdf->rindex); +xdl_free (xdf->rchg -1 ); +xdl_free (xdf->ha); +xdl_free (xdf->recs); +xdl_cha_free (&xdf->rcha); +} + +static int xdl_prepare_ctx (unsigned int pass,mmfile_t *mf,long narec,xpparam_t const *xpp,xdlclassifier_t *cf,xdfile_t *xdf) { -long nrec, bsize; +long bsize;unsigned long hav;char const *blk, *cur, *top, *prev;xrecord_t *crec; -xrecord_t **recs; -unsigned long *ha; -char *rchg; -long *rindex; - ha =NULL ; - rindex =NULL ; - rchg =NULL ; - recs =NULL ; + xdf->ha =NULL ; + xdf->rindex =NULL ; + xdf->rchg =NULL ; + xdf->recs =NULL ; + xdf->nrec =0 ;if (xdl_cha_init (&xdf->rcha,sizeof (xrecord_t), narec /4 +1 ) <0 ) goto abort; -if (!XDL_ALLOC_ARRAY (recs, narec)) +if (!XDL_ALLOC_ARRAY (xdf->recs, narec)) goto abort; - nrec =0 ;if ((cur = blk =xdl_mmfile_first (mf, &bsize))) {for (top = blk + bsize; cur < top; ) { prev = cur; hav =xdl_hash_record (&cur, top, xpp->flags); -if (XDL_ALLOC_GROW (recs, nrec +1 , narec)) +if (XDL_ALLOC_GROW (xdf->recs, xdf->nrec +1 , narec)) goto abort;if (!(crec =xdl_cha_alloc (&xdf->rcha))) goto abort; crec->ptr = (u8 const *) prev; crec->size = (long ) (cur - prev); crec->ha = hav; - recs[nrec++] = crec; + xdf->recs[xdf->nrec++] = crec;if (xdl_classify_record (pass, cf, crec) <0 ) goto abort; } } -if (!XDL_CALLOC_ARRAY (rchg, nrec +2 )) +if (!XDL_CALLOC_ARRAY (xdf->rchg, xdf->nrec +2 )) goto abort;if ((XDF_DIFF_ALG (xpp->flags) !=XDF_PATIENCE_DIFF ) && (XDF_DIFF_ALG (xpp->flags) !=XDF_HISTOGRAM_DIFF )) { -if (!XDL_ALLOC_ARRAY (rindex, nrec +1 )) +if (!XDL_ALLOC_ARRAY (xdf->rindex, xdf->nrec +1 )) goto abort; -if (!XDL_ALLOC_ARRAY (ha, nrec +1 )) +if (!XDL_ALLOC_ARRAY (xdf->ha, xdf->nrec +1 )) goto abort; } - xdf->nrec = nrec; - xdf->recs = recs; - xdf->rchg = rchg +1 ; - xdf->rindex = rindex; + xdf->rchg +=1 ; xdf->nreff =0 ; - xdf->ha = ha; xdf->dstart =0 ; - xdf->dend = nrec -1 ; + xdf->dend = xdf->nrec -1 ;return 0 ; abort: -xdl_free (ha); -xdl_free (rindex); -xdl_free (rchg); -xdl_free (recs); -xdl_cha_free (&xdf->rcha); +xdl_free_ctx (xdf);return -1 ; } -static void xdl_free_ctx (xdfile_t *xdf) { -xdl_free (xdf->rindex); -xdl_free (xdf->rchg -1 ); -xdl_free (xdf->ha); -xdl_free (xdf->recs); -xdl_cha_free (&xdf->rcha); -} - -void xdl_free_env (xdfenv_t *xe) {xdl_free_ctx (&xe->xdf2);
Signature · 1 line
gitgitgadget
PATCH 11/15 xdiff: replace chastore with an ivec in xdfile_t
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
xdfile_t currently uses a chastore which functions as a memory pool and a vector which maps to the allocations created by the chastore. It seems like xrecord_t used to be a linked list until the recs and nrec fields were added. I think that xrecord_t.next was meant to be removed, but was overlooked. This dual data structure setup make the code somewhat confusing.
Additionally the C type chastore_t isn't FFI friendly. While it could be implemented in Rust, since the data structure is confusing anyway, replace it with an ivec whose purpose is to be interoperable. This makes the fields nrec and recs in xdfile_t redundant, which will be removed in the next 2 commits.
--- xdiff/xprepare.c | 34 +++++++++++++++++----------------- xdiff/xtypes.h | 6 ++++-- 2 files changed, 21 insertions(+), 19 deletions(-)
xdiff/xprepare.c +17 -17
@@ -130,11 +130,11 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_tstatic void xdl_free_ctx (xdfile_t *xdf) { +ivec_free (&xdf->record);xdl_free (xdf->rindex);xdl_free (xdf->rchg -1 );xdl_free (xdf->ha);xdl_free (xdf->recs); -xdl_cha_free (&xdf->rcha); }
@@ -143,35 +143,35 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_long bsize;unsigned long hav;char const *blk, *cur, *top, *prev; -xrecord_t *crec; xdf->ha =NULL ; xdf->rindex =NULL ; xdf->rchg =NULL ; xdf->recs =NULL ; xdf->nrec =0 ; - -if (xdl_cha_init (&xdf->rcha,sizeof (xrecord_t), narec /4 +1 ) <0 ) - goto abort; -if (!XDL_ALLOC_ARRAY (xdf->recs, narec)) - goto abort; +IVEC_INIT (xdf->record);if ((cur = blk =xdl_mmfile_first (mf, &bsize))) {for (top = blk + bsize; cur < top; ) { +xrecord_t crec; prev = cur; hav =xdl_hash_record (&cur, top, xpp->flags); -if (XDL_ALLOC_GROW (xdf->recs, xdf->nrec +1 , narec)) - goto abort; -if (!(crec =xdl_cha_alloc (&xdf->rcha))) - goto abort; - crec->ptr = (u8 const *) prev; - crec->size = (long ) (cur - prev); - crec->ha = hav; - xdf->recs[xdf->nrec++] = crec; -if (xdl_classify_record (pass, cf, crec) <0 ) - goto abort; + crec.ptr = (u8 const *) prev; + crec.size = cur - prev; + crec.ha = hav; +ivec_push (&xdf->record, &crec); } } +ivec_shrink_to_fit (&xdf->record); + + xdf->nrec = (long ) xdf->record.length; +if (!XDL_ALLOC_ARRAY (xdf->recs, xdf->record.length)) + goto abort; +for (usize i =0 ; i < xdf->record.length; i++) { +if (xdl_classify_record (pass, cf, &xdf->record.ptr[i]) <0 ) + goto abort; + xdf->recs[i] = &xdf->record.ptr[i]; + }if (!XDL_CALLOC_ARRAY (xdf->rchg, xdf->nrec +2 )) goto abort;
xdiff/xtypes.h +4 -2
@@ -23,7 +23,7 @@ #if !defined(XTYPES_H) #define XTYPES_H - +#include "../interop/ivec.h" typedef struct s_chanode { struct s_chanode *next;
@@ -44,8 +44,10 @@ typedef struct s_xrecord {u64 ha; } xrecord_t; +DEFINE_IVEC_TYPE (xrecord_t, xrecord); + typedef struct s_xdfile { - chastore_t rcha; + struct ivec_xrecord record; long nrec; long dstart, dend; xrecord_t **recs;
Signature · 1 line
gitgitgadget
PATCH 12/15 xdiff: delete nrec field from xdfile_t
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Because of the data structure cleanup in the previous commit, the nrec field is no longer necessary. Use record.length in place of nrec.
This commit is best viewed with --color-words.
--- xdiff/xdiffi.c | 10 +++++----- xdiff/xemit.c | 20 ++++++++++---------- xdiff/xmerge.c | 10 +++++----- xdiff/xpatience.c | 2 +- xdiff/xprepare.c | 34 ++++++++++++++++------------------ xdiff/xtypes.h | 1 - 6 files changed, 37 insertions(+), 40 deletions(-)
xdiff/xdiffi.c +5 -5
@@ -496,7 +496,7 @@ static void measure_split(const xdfile_t *xdf, long split, {long i; -if (split >= xdf->nrec) { +if (split >= (long ) xdf->record.length) { m->end_of_file =1 ; m->indent =-1 ; }else {
@@ -519,7 +519,7 @@ static void measure_split(const xdfile_t *xdf, long split, m->post_blank =0 ; m->post_indent =-1 ; -for (i = split +1 ; i < xdf->nrec; i++) { +for (i = split +1 ; i < (long ) xdf->record.length; i++) { m->post_indent =get_indent (xdf->recs[i]);if (m->post_indent !=-1 )break ;
@@ -730,7 +730,7 @@ static void group_init(xdfile_t *xdf, struct xdlgroup *g)*/ static inline int group_next (xdfile_t *xdf,struct xdlgroup *g) { -if (g->end == xdf->nrec) +if (g->end == (long ) xdf->record.length)return -1 ; g->start = g->end +1 ;
@@ -763,7 +763,7 @@ static inline int group_previous(xdfile_t *xdf, struct xdlgroup *g)*/ static int group_slide_down (xdfile_t *xdf,struct xdlgroup *g) { -if (g->end < xdf->nrec && +if (g->end < (long ) xdf->record.length &&recs_match (xdf->recs[g->start], xdf->recs[g->end])) { xdf->rchg[g->start++] =0 ; xdf->rchg[g->end++] =1 ;
@@ -950,7 +950,7 @@ int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr) {/* * Trivial. Collects "groups" of changes and creates an edit script. */ -for (i1 = xe->xdf1.nrec, i2 = xe->xdf2.nrec; i1 >=0 || i2 >=0 ; i1--, i2--) +for (i1 = xe->xdf1.record.length, i2 = xe->xdf2.record.length; i1 >=0 || i2 >=0 ; i1--, i2--)if (rchg1[i1 -1 ] || rchg2[i2 -1 ]) {for (l1 = i1; rchg1[i1 -1 ]; i1--);for (l2 = i2; rchg2[i2 -1 ]; i2--);
xdiff/xemit.c +10 -10
@@ -147,7 +147,7 @@ static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, buf = func_line ? func_line->buf : dummy; size = func_line ?sizeof (func_line->buf) :sizeof (dummy); -for (l = start; l != limit &&0 <= l && l < xe->xdf1.nrec; l += step) { +for (l = start; l != limit &&0 <= l && l < (long ) xe->xdf1.record.length; l += step) {long len =match_func_rec (&xe->xdf1, xecfg, l, buf, size);if (len >=0 ) {if (func_line)
@@ -191,14 +191,14 @@ pre_context_calculation:long fs1, i1 = xch->i1;/* Appended chunk? */ -if (i1 >= xe->xdf1.nrec) { +if (i1 >= (long ) xe->xdf1.record.length) {long i2 = xch->i2;/* * We don't need additional context if * a whole function was added. */ -while (i2 < xe->xdf2.nrec) { +while (i2 < (long ) xe->xdf2.record.length) {if (is_func_rec (&xe->xdf2, xecfg, i2)) goto post_context_calculation; i2++;
@@ -208,7 +208,7 @@ pre_context_calculation:* Otherwise get more context from the * pre-image. */ - i1 = xe->xdf1.nrec -1 ; + i1 = xe->xdf1.record.length -1 ; } fs1 =get_func_line (xe, xecfg,NULL , i1,-1 );
@@ -240,8 +240,8 @@ pre_context_calculation: post_context_calculation: lctx = xecfg->ctxlen; - lctx =XDL_MIN (lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1)); - lctx =XDL_MIN (lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2)); + lctx =XDL_MIN (lctx, (long ) xe->xdf1.record.length - (xche->i1 + xche->chg1)); + lctx =XDL_MIN (lctx, (long ) xe->xdf2.record.length - (xche->i2 + xche->chg2)); e1 = xche->i1 + xche->chg1 + lctx; e2 = xche->i2 + xche->chg2 + lctx;
@@ -249,13 +249,13 @@ pre_context_calculation:if (xecfg->flags &XDL_EMIT_FUNCCONTEXT ) {long fe1 =get_func_line (xe, xecfg,NULL , xche->i1 + xche->chg1, - xe->xdf1.nrec); + xe->xdf1.record.length);while (fe1 >0 &&is_empty_rec (&xe->xdf1, fe1 -1 )) fe1--;if (fe1 <0 ) - fe1 = xe->xdf1.nrec; + fe1 = xe->xdf1.record.length;if (fe1 > e1) { - e2 =XDL_MIN (e2 + (fe1 - e1), xe->xdf2.nrec); + e2 =XDL_MIN (e2 + (fe1 - e1), (long ) xe->xdf2.record.length); e1 = fe1; }
@@ -266,7 +266,7 @@ pre_context_calculation:*/ if (xche->next) {long l =XDL_MIN (xche->next->i1, - xe->xdf1.nrec -1 ); + (long ) xe->xdf1.record.length -1 );if (l - xecfg->ctxlen <= e1 ||get_func_line (xe, xecfg,NULL , l, e1) <0 ) { xche = xche->next;
xdiff/xmerge.c +5 -5
@@ -158,11 +158,11 @@ static int is_eol_crlf(xdfile_t *file, int i) {long size; -if (i < file->nrec -1 ) +if (i < (isize ) file->record.length -1 )/* All lines before the last *must* end in LF */ return (size = file->recs[i]->size) >1 && file->recs[i]->ptr[size -2 ] =='\r' ; -if (!file->nrec) +if (!file->record.length)/* Cannot determine eol style from empty file */ return -1 ; if ((size = file->recs[i]->size) &&
@@ -317,7 +317,7 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,continue ; i = m->i1 + m->chg1; } - size +=xdl_recs_copy (xe1, i, xe1->xdf2.nrec - i,0 ,0 , + size +=xdl_recs_copy (xe1, i, (int ) xe1->xdf2.record.length - i,0 ,0 , dest ? dest + size :NULL );return size; }
@@ -622,7 +622,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, changes = c; i0 = xscr1->i1; i1 = xscr1->i2; - i2 = xscr1->i1 + xe2->xdf2.nrec - xe2->xdf1.nrec; + i2 = xscr1->i1 + xe2->xdf2.record.length - xe2->xdf1.record.length; chg0 = xscr1->chg1; chg1 = xscr1->chg2; chg2 = xscr1->chg1;
@@ -637,7 +637,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,if (!changes) changes = c; i0 = xscr2->i1; - i1 = xscr2->i1 + xe1->xdf2.nrec - xe1->xdf1.nrec; + i1 = xscr2->i1 + xe1->xdf2.record.length - xe1->xdf1.record.length; i2 = xscr2->i2; chg0 = xscr2->chg1; chg1 = xscr2->chg1;
xdiff/xpatience.c +1 -1
@@ -370,5 +370,5 @@ static int patience_diff(xpparam_t const *xpp, xdfenv_t *env,int xdl_do_patience_diff (xpparam_t const *xpp,xdfenv_t *env) { -return patience_diff (xpp, env,1 , env->xdf1.nrec,1 , env->xdf2.nrec); +return patience_diff (xpp, env,1 , env->xdf1.record.length,1 , env->xdf2.record.length); }
xdiff/xprepare.c +16 -18
@@ -138,7 +138,7 @@ static void xdl_free_ctx(xdfile_t *xdf) { } -static int xdl_prepare_ctx (unsigned int pass,mmfile_t *mf,long narec,xpparam_t const *xpp, +static int xdl_prepare_ctx (unsigned int pass,mmfile_t *mf,xpparam_t const *xpp,xdlclassifier_t *cf,xdfile_t *xdf) {long bsize;unsigned long hav;
@@ -148,7 +148,6 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ xdf->rindex =NULL ; xdf->rchg =NULL ; xdf->recs =NULL ; - xdf->nrec =0 ;IVEC_INIT (xdf->record);if ((cur = blk =xdl_mmfile_first (mf, &bsize))) {
@@ -164,7 +163,6 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ }ivec_shrink_to_fit (&xdf->record); - xdf->nrec = (long ) xdf->record.length;if (!XDL_ALLOC_ARRAY (xdf->recs, xdf->record.length)) goto abort;for (usize i =0 ; i < xdf->record.length; i++) {
@@ -173,21 +171,21 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ xdf->recs[i] = &xdf->record.ptr[i]; } -if (!XDL_CALLOC_ARRAY (xdf->rchg, xdf->nrec +2 )) +if (!XDL_CALLOC_ARRAY (xdf->rchg, xdf->record.length +2 )) goto abort;if ((XDF_DIFF_ALG (xpp->flags) !=XDF_PATIENCE_DIFF ) && (XDF_DIFF_ALG (xpp->flags) !=XDF_HISTOGRAM_DIFF )) { -if (!XDL_ALLOC_ARRAY (xdf->rindex, xdf->nrec +1 )) +if (!XDL_ALLOC_ARRAY (xdf->rindex, xdf->record.length +1 )) goto abort; -if (!XDL_ALLOC_ARRAY (xdf->ha, xdf->nrec +1 )) +if (!XDL_ALLOC_ARRAY (xdf->ha, xdf->record.length +1 )) goto abort; } xdf->rchg +=1 ; xdf->nreff =0 ; xdf->dstart =0 ; - xdf->dend = xdf->nrec -1 ; + xdf->dend = xdf->record.length -1 ;return 0 ;
@@ -274,12 +272,12 @@ static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdchar *dis, *dis1, *dis2;int need_min = !!(cf->flags &XDF_NEED_MINIMAL ); -if (!XDL_CALLOC_ARRAY (dis, xdf1->nrec + xdf2->nrec +2 )) +if (!XDL_CALLOC_ARRAY (dis, xdf1->record.length + xdf2->record.length +2 ))return -1 ; dis1 = dis; - dis2 = dis1 + xdf1->nrec +1 ; + dis2 = dis1 + xdf1->record.length +1 ; -if ((mlim =xdl_bogosqrt (xdf1->nrec)) >XDL_MAX_EQLIMIT ) +if ((mlim =xdl_bogosqrt (xdf1->record.length)) >XDL_MAX_EQLIMIT ) mlim =XDL_MAX_EQLIMIT ;for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) { rcrec = cf->rcrecs[(*recs)->ha];
@@ -287,7 +285,7 @@ static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xd dis1[i] = (nm ==0 ) ?0 : (nm >= mlim && !need_min) ?2 :1 ; } -if ((mlim =xdl_bogosqrt (xdf2->nrec)) >XDL_MAX_EQLIMIT ) +if ((mlim =xdl_bogosqrt (xdf2->record.length)) >XDL_MAX_EQLIMIT ) mlim =XDL_MAX_EQLIMIT ;for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) { rcrec = cf->rcrecs[(*recs)->ha];
@@ -334,21 +332,21 @@ static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2) { recs1 = xdf1->recs; recs2 = xdf2->recs; -for (i =0 , lim =XDL_MIN (xdf1->nrec, xdf2->nrec); i < lim; +for (i =0 , lim =XDL_MIN (xdf1->record.length, xdf2->record.length); i < lim; i++, recs1++, recs2++)if ((*recs1)->ha != (*recs2)->ha)break ; xdf1->dstart = xdf2->dstart = i; - recs1 = xdf1->recs + xdf1->nrec -1 ; - recs2 = xdf2->recs + xdf2->nrec -1 ; + recs1 = xdf1->recs + xdf1->record.length -1 ; + recs2 = xdf2->recs + xdf2->record.length -1 ;for (lim -= i, i =0 ; i < lim; i++, recs1--, recs2--)if ((*recs1)->ha != (*recs2)->ha)break ; - xdf1->dend = xdf1->nrec - i -1 ; - xdf2->dend = xdf2->nrec - i -1 ; + xdf1->dend = xdf1->record.length - i -1 ; + xdf2->dend = xdf2->record.length - i -1 ;return 0 ; }
@@ -388,12 +386,12 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,if (xdl_init_classifier (&cf, enl1 + enl2 +1 , xpp->flags) <0 )return -1 ; -if (xdl_prepare_ctx (1 , mf1, enl1, xpp, &cf, &xe->xdf1) <0 ) { +if (xdl_prepare_ctx (1 , mf1, xpp, &cf, &xe->xdf1) <0 ) {xdl_free_classifier (&cf);return -1 ; } -if (xdl_prepare_ctx (2 , mf2, enl2, xpp, &cf, &xe->xdf2) <0 ) { +if (xdl_prepare_ctx (2 , mf2, xpp, &cf, &xe->xdf2) <0 ) {xdl_free_ctx (&xe->xdf1);xdl_free_classifier (&cf);
xdiff/xtypes.h +0 -1
@@ -48,7 +48,6 @@ DEFINE_IVEC_TYPE(xrecord_t, xrecord); typedef struct s_xdfile { struct ivec_xrecord record; - long nrec; long dstart, dend; xrecord_t **recs; char *rchg;
Signature · 1 line
gitgitgadget
PATCH 13/15 xdiff: delete recs field from xdfile_t
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Because of the change from chastore to ivec a few commits ago, recs now points to record's elements in a 1:1 mapping. Since both recs and record are vectors, this additional mapping is superfluous. Remove recs.
This commit is best viewed with --color-words.
--- xdiff/xdiffi.c | 30 ++++++++++++------------ xdiff/xemit.c | 4 ++-- xdiff/xhistogram.c | 2 +- xdiff/xmerge.c | 58 +++++++++++++++++++++++----------------------- xdiff/xpatience.c | 14 +++++------ xdiff/xprepare.c | 37 +++++++++++++---------------- xdiff/xtypes.h | 1 - xdiff/xutils.c | 12 +++++----- 8 files changed, 76 insertions(+), 82 deletions(-)
xdiff/xdiffi.c +15 -15
@@ -501,13 +501,13 @@ static void measure_split(const xdfile_t *xdf, long split, m->indent =-1 ; }else { m->end_of_file =0 ; - m->indent =get_indent (xdf->recs[split]); + m->indent =get_indent (&xdf->record.ptr[split]); } m->pre_blank =0 ; m->pre_indent =-1 ;for (i = split -1 ; i >=0 ; i--) { - m->pre_indent =get_indent (xdf->recs[i]); + m->pre_indent =get_indent (&xdf->record.ptr[i]);if (m->pre_indent !=-1 )break ; m->pre_blank +=1 ;
@@ -520,7 +520,7 @@ static void measure_split(const xdfile_t *xdf, long split, m->post_blank =0 ; m->post_indent =-1 ;for (i = split +1 ; i < (long ) xdf->record.length; i++) { - m->post_indent =get_indent (xdf->recs[i]); + m->post_indent =get_indent (&xdf->record.ptr[i]);if (m->post_indent !=-1 )break ; m->post_blank +=1 ;
@@ -764,7 +764,7 @@ static inline int group_previous(xdfile_t *xdf, struct xdlgroup *g)static int group_slide_down (xdfile_t *xdf,struct xdlgroup *g) {if (g->end < (long ) xdf->record.length && -recs_match (xdf->recs[g->start], xdf->recs[g->end])) { +recs_match (&xdf->record.ptr[g->start], &xdf->record.ptr[g->end])) { xdf->rchg[g->start++] =0 ; xdf->rchg[g->end++] =1 ;
@@ -785,7 +785,7 @@ static int group_slide_down(xdfile_t *xdf, struct xdlgroup *g)static int group_slide_up (xdfile_t *xdf,struct xdlgroup *g) {if (g->start >0 && -recs_match (xdf->recs[g->start -1 ], xdf->recs[g->end -1 ])) { +recs_match (&xdf->record.ptr[g->start -1 ], &xdf->record.ptr[g->end -1 ])) { xdf->rchg[--g->start] =1 ; xdf->rchg[--g->end] =0 ;
@@ -1000,16 +1000,16 @@ static void xdl_mark_ignorable_lines(xdchange_t *xscr, xdfenv_t *xe, long flags)for (xch = xscr; xch; xch = xch->next) {int ignore =1 ; -xrecord_t **rec; +xrecord_t *rec;long i; - rec = &xe->xdf1.recs[xch->i1]; + rec = &xe->xdf1.record.ptr[xch->i1];for (i =0 ; i < xch->chg1 && ignore; i++) - ignore =xdl_blankline ((const char *) rec[i]->ptr, rec[i]->size, flags); + ignore =xdl_blankline ((const char *) rec[i].ptr, rec[i].size, flags); - rec = &xe->xdf2.recs[xch->i2]; + rec = &xe->xdf2.record.ptr[xch->i2];for (i =0 ; i < xch->chg2 && ignore; i++) - ignore =xdl_blankline ((const char *)rec[i]->ptr, rec[i]->size, flags); + ignore =xdl_blankline ((const char *)rec[i].ptr, rec[i].size, flags); xch->ignore = ignore; }
@@ -1033,7 +1033,7 @@ static void xdl_mark_ignorable_regex(xdchange_t *xscr, const xdfenv_t *xe,xdchange_t *xch;for (xch = xscr; xch; xch = xch->next) { -xrecord_t **rec; +xrecord_t *rec;int ignore =1 ;long i;
@@ -1043,13 +1043,13 @@ static void xdl_mark_ignorable_regex(xdchange_t *xscr, const xdfenv_t *xe,if (xch->ignore)continue ; - rec = &xe->xdf1.recs[xch->i1]; + rec = &xe->xdf1.record.ptr[xch->i1];for (i =0 ; i < xch->chg1 && ignore; i++) - ignore =record_matches_regex (rec[i], xpp); + ignore =record_matches_regex (&rec[i], xpp); - rec = &xe->xdf2.recs[xch->i2]; + rec = &xe->xdf2.record.ptr[xch->i2];for (i =0 ; i < xch->chg2 && ignore; i++) - ignore =record_matches_regex (rec[i], xpp); + ignore =record_matches_regex (&rec[i], xpp); xch->ignore = ignore; }
xdiff/xemit.c +2 -2
@@ -24,9 +24,9 @@static long xdl_get_rec (xdfile_t *xdf,long ri,char const **rec) { - *rec = (char const *) xdf->recs[ri]->ptr; + *rec = (char const *) xdf->record.ptr[ri].ptr; -return xdf->recs[ri]->size; +return xdf->record.ptr[ri].size; }
xdiff/xhistogram.c +1 -1
@@ -86,7 +86,7 @@ struct region { ((LINE_MAP(index, ptr))->cnt)#define REC (env, s, l) \ - (env->xdf##s.recs[l - 1]) + (&env->xdf##s.record.ptr[l - 1])static int cmp_recs (xrecord_t *r1,xrecord_t *r2) {
xdiff/xmerge.c +29 -29
125 lines not on this page · raw message
xdiff/xpatience.c +7 -7
@@ -88,9 +88,9 @@ static int is_anchor(xpparam_t const *xpp, const char *line)static void insert_record (xpparam_t const *xpp,int line,struct hashmap *map,int pass) { -xrecord_t **records = pass ==1 ? - map->env->xdf1.recs : map->env->xdf2.recs; -xrecord_t *record = records[line -1 ]; +xrecord_t *records = pass ==1 ? + map->env->xdf1.record.ptr : map->env->xdf2.record.ptr; +xrecord_t *record = &records[line -1 ];/* * After xdl_prepare_env() (or more precisely, due to * xdl_classify_record()), the "ha" member of the records (AKA lines)
@@ -121,7 +121,7 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,return ; map->entries[index].line1 = line; map->entries[index].hash = record->ha; - map->entries[index].anchor =is_anchor (xpp, (const char *) map->env->xdf1.recs[line -1 ]->ptr); + map->entries[index].anchor =is_anchor (xpp, (const char *) map->env->xdf1.record.ptr[line -1 ].ptr);if (!map->first) map->first = map->entries + index;if (map->last) {
@@ -246,9 +246,9 @@ static int find_longest_common_sequence(struct hashmap *map, struct entry **res)static int match (struct hashmap *map,int line1,int line2) { -xrecord_t *record1 = map->env->xdf1.recs[line1 -1 ]; -xrecord_t *record2 = map->env->xdf2.recs[line2 -1 ]; -return record1->ha == record2->ha; +u64 mph1 = map->env->xdf1.record.ptr[line1 -1 ].ha; +u64 mph2 = map->env->xdf2.record.ptr[line2 -1 ].ha; +return mph1 == mph2; } static int patience_diff(xpparam_t const *xpp, xdfenv_t *env,
xdiff/xprepare.c +16 -21
@@ -134,7 +134,6 @@ static void xdl_free_ctx(xdfile_t *xdf) {xdl_free (xdf->rindex);xdl_free (xdf->rchg -1 );xdl_free (xdf->ha); -xdl_free (xdf->recs); }
@@ -147,7 +146,6 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, xpparam_t const *xpp xdf->ha =NULL ; xdf->rindex =NULL ; xdf->rchg =NULL ; - xdf->recs =NULL ;IVEC_INIT (xdf->record);if ((cur = blk =xdl_mmfile_first (mf, &bsize))) {
@@ -163,12 +161,9 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, xpparam_t const *xpp }ivec_shrink_to_fit (&xdf->record); -if (!XDL_ALLOC_ARRAY (xdf->recs, xdf->record.length)) - goto abort;for (usize i =0 ; i < xdf->record.length; i++) {if (xdl_classify_record (pass, cf, &xdf->record.ptr[i]) <0 ) goto abort; - xdf->recs[i] = &xdf->record.ptr[i]; }if (!XDL_CALLOC_ARRAY (xdf->rchg, xdf->record.length +2 ))
@@ -267,7 +262,7 @@ static int xdl_clean_mmatch(char const *dis, long i, long s, long e) {*/ static int xdl_cleanup_records (xdlclassifier_t *cf,xdfile_t *xdf1,xdfile_t *xdf2) {long i, nm, nreff, mlim; -xrecord_t **recs; +xrecord_t *recs;xdlclass_t *rcrec;char *dis, *dis1, *dis2;int need_min = !!(cf->flags &XDF_NEED_MINIMAL );
@@ -279,38 +274,38 @@ static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdif ((mlim =xdl_bogosqrt (xdf1->record.length)) >XDL_MAX_EQLIMIT ) mlim =XDL_MAX_EQLIMIT ; -for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) { - rcrec = cf->rcrecs[(*recs)->ha]; +for (i = xdf1->dstart, recs = &xdf1->record.ptr[xdf1->dstart]; i <= xdf1->dend; i++, recs++) { + rcrec = cf->rcrecs[recs->ha]; nm = rcrec ? rcrec->len2 :0 ; dis1[i] = (nm ==0 ) ?0 : (nm >= mlim && !need_min) ?2 :1 ; }if ((mlim =xdl_bogosqrt (xdf2->record.length)) >XDL_MAX_EQLIMIT ) mlim =XDL_MAX_EQLIMIT ; -for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) { - rcrec = cf->rcrecs[(*recs)->ha]; +for (i = xdf2->dstart, recs = &xdf2->record.ptr[xdf2->dstart]; i <= xdf2->dend; i++, recs++) { + rcrec = cf->rcrecs[recs->ha]; nm = rcrec ? rcrec->len1 :0 ; dis2[i] = (nm ==0 ) ?0 : (nm >= mlim && !need_min) ?2 :1 ; } -for (nreff =0 , i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; +for (nreff =0 , i = xdf1->dstart, recs = &xdf1->record.ptr[xdf1->dstart]; i <= xdf1->dend; i++, recs++) {if (dis1[i] ==1 || (dis1[i] ==2 && !xdl_clean_mmatch (dis1, i, xdf1->dstart, xdf1->dend))) { xdf1->rindex[nreff] = i; - xdf1->ha[nreff] = (*recs)->ha; + xdf1->ha[nreff] = recs->ha; nreff++; }else xdf1->rchg[i] =1 ; } xdf1->nreff = nreff; -for (nreff =0 , i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; +for (nreff =0 , i = xdf2->dstart, recs = &xdf2->record.ptr[xdf2->dstart]; i <= xdf2->dend; i++, recs++) {if (dis2[i] ==1 || (dis2[i] ==2 && !xdl_clean_mmatch (dis2, i, xdf2->dstart, xdf2->dend))) { xdf2->rindex[nreff] = i; - xdf2->ha[nreff] = (*recs)->ha; + xdf2->ha[nreff] = recs->ha; nreff++; }else xdf2->rchg[i] =1 ;
@@ -328,21 +323,21 @@ static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xd*/ static int xdl_trim_ends (xdfile_t *xdf1,xdfile_t *xdf2) {long i, lim; -xrecord_t **recs1, **recs2; +xrecord_t *recs1, *recs2; - recs1 = xdf1->recs; - recs2 = xdf2->recs; + recs1 = xdf1->record.ptr; + recs2 = xdf2->record.ptr;for (i =0 , lim =XDL_MIN (xdf1->record.length, xdf2->record.length); i < lim; i++, recs1++, recs2++) -if ((*recs1)->ha != (*recs2)->ha) +if (recs1->ha != recs2->ha)break ; xdf1->dstart = xdf2->dstart = i; - recs1 = xdf1->recs + xdf1->record.length -1 ; - recs2 = xdf2->recs + xdf2->record.length -1 ; + recs1 = xdf1->record.ptr + xdf1->record.length -1 ; + recs2 = xdf2->record.ptr + xdf2->record.length -1 ;for (lim -= i, i =0 ; i < lim; i++, recs1--, recs2--) -if ((*recs1)->ha != (*recs2)->ha) +if (recs1->ha != recs2->ha)break ; xdf1->dend = xdf1->record.length - i -1 ;
xdiff/xtypes.h +0 -1
@@ -49,7 +49,6 @@ DEFINE_IVEC_TYPE(xrecord_t, xrecord); typedef struct s_xdfile { struct ivec_xrecord record; long dstart, dend; - xrecord_t **recs; char *rchg; long *rindex; long nreff;
xdiff/xutils.c +6 -6
@@ -416,12 +416,12 @@ int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,mmfile_t subfile1, subfile2;xdfenv_t env; - subfile1.ptr = (char *)diff_env->xdf1.recs[line1 -1 ]->ptr; - subfile1.size = diff_env->xdf1.recs[line1 + count1 -2 ]->ptr + - diff_env->xdf1.recs[line1 + count1 -2 ]->size - (u8 const *) subfile1.ptr; - subfile2.ptr = (char *)diff_env->xdf2.recs[line2 -1 ]->ptr; - subfile2.size = diff_env->xdf2.recs[line2 + count2 -2 ]->ptr + - diff_env->xdf2.recs[line2 + count2 -2 ]->size - (u8 const *) subfile2.ptr; + subfile1.ptr = (char *)diff_env->xdf1.record.ptr[line1 -1 ].ptr; + subfile1.size = diff_env->xdf1.record.ptr[line1 + count1 -2 ].ptr + + diff_env->xdf1.record.ptr[line1 + count1 -2 ].size - (u8 const *) subfile1.ptr; + subfile2.ptr = (char *)diff_env->xdf2.record.ptr[line2 -1 ].ptr; + subfile2.size = diff_env->xdf2.record.ptr[line2 + count2 -2 ].ptr + + diff_env->xdf2.record.ptr[line2 + count2 -2 ].size - (u8 const *) subfile2.ptr;if (xdl_do_diff (&subfile1, &subfile2, xpp, &env) <0 )return -1 ;
Signature · 1 line
gitgitgadget
PATCH 14/15 xdiff: make xdfile_t more rust friendly
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Convert the remaining ambiguous fields in xdfile_t from C types to Rust types for interoperability.
--- xdiff/xdiffi.c | 16 ++++++++-------- xdiff/xdiffi.h | 8 ++++---- xdiff/xtypes.h | 10 +++++----- 3 files changed, 17 insertions(+), 17 deletions(-)
xdiff/xdiffi.c +8 -8
@@ -42,8 +42,8 @@ typedef struct s_xdpsplit {* using this algorithm, so a little bit of heuristic is needed to cut the * search and to return a suboptimal point. */ -static long xdl_split (unsigned long const *ha1,long off1,long lim1, -unsigned long const *ha2,long off2,long lim2, +static long xdl_split (u64 const *ha1,long off1,long lim1, +u64 const *ha2,long off2,long lim2,long *kvdf,long *kvdb,int need_min,xdpsplit_t *spl,xdalgoenv_t *xenv) {long dmin = off1 - lim2, dmax = lim1 - off2;
@@ -260,7 +260,7 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,int xdl_recs_cmp (diffdata_t *dd1,long off1,long lim1,diffdata_t *dd2,long off2,long lim2,long *kvdf,long *kvdb,int need_min,xdalgoenv_t *xenv) { -unsigned long const *ha1 = dd1->ha, *ha2 = dd2->ha; +u64 const *ha1 = dd1->ha, *ha2 = dd2->ha;/* * Shrink the box by walking through each diagonal snake (SW and NE).
@@ -273,14 +273,14 @@ int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1,* be obviously changed. */ if (off1 == lim1) { -char *rchg2 = dd2->rchg; -long *rindex2 = dd2->rindex; +u8 *rchg2 = dd2->rchg; +usize *rindex2 = dd2->rindex;for (; off2 < lim2; off2++) rchg2[rindex2[off2]] =1 ; }else if (off2 == lim2) { -char *rchg1 = dd1->rchg; -long *rindex1 = dd1->rindex; +u8 *rchg1 = dd1->rchg; +usize *rindex1 = dd1->rindex;for (; off1 < lim1; off1++) rchg1[rindex1[off1]] =1 ;
@@ -944,7 +944,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {int xdl_build_script (xdfenv_t *xe,xdchange_t **xscr) {xdchange_t *cscr =NULL , *xch; -char *rchg1 = xe->xdf1.rchg, *rchg2 = xe->xdf2.rchg; +u8 *rchg1 = xe->xdf1.rchg, *rchg2 = xe->xdf2.rchg;long i1, i2, l1, l2;/*
xdiff/xdiffi.h +4 -4
@@ -25,10 +25,10 @@typedef struct s_diffdata { -long nrec; -unsigned long const *ha; -long *rindex; -char *rchg; +usize nrec; +u64 const *ha; +usize *rindex; +u8 *rchg; }diffdata_t ; typedef struct s_xdalgoenv {
xdiff/xtypes.h +5 -5
@@ -48,11 +48,11 @@ DEFINE_IVEC_TYPE(xrecord_t, xrecord);typedef struct s_xdfile {struct ivec_xrecord record; -long dstart, dend; -char *rchg; -long *rindex; -long nreff; -unsigned long *ha; +isize dstart, dend; +u8 *rchg; +usize *rindex; +usize nreff; +u64 *ha; }xdfile_t ; typedef struct s_xdfenv {
Signature · 1 line
gitgitgadget
PATCH 15/15 xdiff: implement xdl_trim_ends() in Rust
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Replace the C implementation of xdl_trim_ends() with a Rust implementation.
--- rust/xdiff/src/lib.rs | 15 +++++++++++++++ rust/xdiff/src/xprepare.rs | 27 +++++++++++++++++++++++++++ rust/xdiff/src/xtypes.rs | 19 +++++++++++++++++++ xdiff/xprepare.c | 28 +--------------------------- 4 files changed, 62 insertions(+), 27 deletions(-) create mode 100644 rust/xdiff/src/xprepare.rs create mode 100644 rust/xdiff/src/xtypes.rs
rust/xdiff/src/lib.rs +15 -0
@@ -0,0 +1,15 @@ +pub mod xprepare; +pub mod xtypes; + +use crate ::xprepare::trim_ends; +use crate ::xtypes::xdfile; + +#[no_mangle] +unsafe extern "C" fn xdl_trim_ends (xdf1: *mut xdfile , xdf2: *mut xdfile ) ->i32 { +let xdf1 = xdf1.as_mut ().expect ("null pointer" ); +let xdf2 = xdf2.as_mut ().expect ("null pointer" ); + +trim_ends (xdf1, xdf2); + +0 +}
rust/xdiff/src/xprepare.rs new file +27 -0
@@ -0,0 +1,27 @@ +use crate ::xtypes::xdfile; + +/// +/// Early trim initial and terminal matching records. +/// +pub (crate )fn trim_ends (xdf1: &mut xdfile , xdf2: &mut xdfile ) { +let mut lim = std::cmp::min (xdf1.record.len (), xdf2.record.len ()); + +for iin 0 ..lim { +if xdf1.record[i].ha != xdf2.record[i].ha { + xdf1.dstart = ias isize ; + xdf2.dstart = ias isize ; + lim -= i; +break ; + } + } + +for iin 0 ..lim { +let f1i = xdf1.record.len () -1 - i; +let f2i = xdf2.record.len () -1 - i; +if xdf1.record[f1i].ha != xdf2.record[f2i].ha { + xdf1.dend = f1ias isize ; + xdf2.dend = f2ias isize ; +break ; + } + } +}
rust/xdiff/src/xtypes.rs new file +19 -0
@@ -0,0 +1,19 @@ +use interop::ivec::IVec ; + +#[repr( C )] +pub (crate )struct xrecord { +pub (crate ) ptr: *const u8 , +pub (crate ) size:usize , +pub (crate ) ha:u64 , +} + +#[repr( C )] +pub (crate )struct xdfile { +pub (crate ) record:IVec <xrecord >, +pub (crate ) dstart:isize , +pub (crate ) dend:isize , +pub (crate ) rchg: *mut u8 , +pub (crate ) rindex: *mut usize , +pub (crate ) nreff:usize , +pub (crate ) ha: *mut u64 , +}
xdiff/xprepare.c +1 -27
@@ -318,33 +318,7 @@ static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xd } -/* -* Early trim initial and terminal matching records. -*/ -static int xdl_trim_ends (xdfile_t *xdf1,xdfile_t *xdf2) { -long i, lim; -xrecord_t *recs1, *recs2; - - recs1 = xdf1->record.ptr; - recs2 = xdf2->record.ptr; -for (i =0 , lim =XDL_MIN (xdf1->record.length, xdf2->record.length); i < lim; - i++, recs1++, recs2++) -if (recs1->ha != recs2->ha) -break ; - - xdf1->dstart = xdf2->dstart = i; - - recs1 = xdf1->record.ptr + xdf1->record.length -1 ; - recs2 = xdf2->record.ptr + xdf2->record.length -1 ; -for (lim -= i, i =0 ; i < lim; i++, recs1--, recs2--) -if (recs1->ha != recs2->ha) -break ; - - xdf1->dend = xdf1->record.length - i -1 ; - xdf2->dend = xdf2->record.length - i -1 ; - -return 0 ; -} +extern i32 xdl_trim_ends (xdfile_t *xdf1,xdfile_t *xdf2);static int xdl_optimize_ctxs (xdlclassifier_t *cf,xdfile_t *xdf1,xdfile_t *xdf2) {
Signature · 1 line
gitgitgadget
v2 cover Introduce rust: In xdiff
In reply to Ezekiel Newren via GitGitGadgetThis is a continuation of
https://lore.kernel.org/git/[email protected]/,
but I am removing the RFC label.
Suggestions on changes that I could make to this series is appreciated.
Changes in v2: High level overview:
* patch 1: cleanup: rename variables that collide with Rust primitive type names
* patches 2-4: Makefile now produces libgit.a correctly
* patches 5,6: Documentation from Brian and Patrick
* patches 7,8: Introduce Rust
* patches 9-11: github workflows
* patches 12-14: introduce crates build-helper, and cbindgen
* patches 15-18: varint test balloon
I would like feed back in two categories: big changes, and little changes. Is my patch series even going in the right direction, and what are the little details that I've missed? I know Brian asked for cbindgen and it made the series several commits longer, but I think it's a great idea to have. I am not happy with every choice that I made, but I currently don't see a better way or at least an easier alternative to my approach in bringing Rust to Git.
Build results for these changes:
https://github.com/git/git/actions/runs/17783386212?pr=2043. Some of these are failing.
Changes in v1: Changes since the last RFC patch series (range-diff added below):
* Addressed feedback:
* Use self instead of this
* Update ivec to use Git code style
* Remove environment variable CI_IS_DOCKER from github workflows
* Remove PHONY target interop-objs
* Removed left over asserts in Rust and fix near by code
* Other changes:
* Avoid name mangling of ivec if c++ compiler used
* Fixed a typo in patch 11 commit message
High level overview:
* patch 1: add a policy for using Rust (brian's patch, with a small tweak)
* patch 2: introduce Rust to the codebase
* patches 3-5: adapt CI (github workflows) to build Git with Rust
* patch 6: introduce the ivec type
* patches 7-14: xdiff code cleanup in preparation for translating to Rust
* patch 15: translate a C function into Rust and call it from C
Ezekiel Newren (12):
cleanup: rename variables that collide with Rust primitive type names
make: add -fPIE flag
make: merge xdiff lib into libgit.a
make: merge reftable lib into libgit.a
build: introduce rust
github workflows: install rust
github workflows: upload Cargo.lock
build: new crate, build-helper
build-helper: link against libgit.a and any other required C libraries
build-helper: cbindgen, let crates generate a header file
build: new crate, misc
misc: use BuildHelper
Johannes Schindelin (1):
win+Meson: do allow linking with the Rust-built xdiff
Patrick Steinhardt (4):
BreakingChanges: announce Rust becoming mandatory
help: report on whether or not Rust is enabled
varint: use explicit width for integers misc::varint: reimplement as test balloon for Rust
brian m. carlson (1):
doc: add a policy for using Rust
.github/workflows/main.yml | 82 +++++++++- .gitignore | 4 + Documentation/BreakingChanges.adoc | 35 +++++ Documentation/Makefile | 1 + Documentation/technical/platform-support.adoc | 2 + Documentation/technical/rust-support.adoc | 142 +++++++++++++++++ Makefile | 148 +++++++++++------- build_rust.sh | 60 +++++++ ci/install-dependencies.sh | 14 +- ci/install-rust-toolchain.sh | 30 ++++ ci/install-rustup.sh | 25 +++ ci/lib.sh | 1 + ci/make-test-artifacts.sh | 9 ++ ci/run-build-and-tests.sh | 13 ++ config.mak.uname | 4 + dir.c | 18 ++- help.c | 6 + meson.build | 79 ++++++++-- meson_options.txt | 2 + odb.c | 8 +- read-cache.c | 6 +- reftable/record.c | 6 +- rust/Cargo.toml | 6 + rust/build-helper/Cargo.toml | 11 ++ rust/build-helper/src/lib.rs | 126 +++++++++++++++ rust/cbindgen-template.toml | 16 ++ rust/misc/Cargo.toml | 17 ++ rust/misc/build.rs | 6 + rust/misc/src/lib.rs | 1 + rust/misc/src/varint.rs | 92 +++++++++++ t/helper/test-parse-options.c | 12 +- varint.c | 6 +- varint.h | 4 +- xdiff/xtypes.h | 2 +- xdiff/xutils.c | 8 +- xdiff/xutils.h | 2 +- 36 files changed, 899 insertions(+), 105 deletions(-) create mode 100644 Documentation/technical/rust-support.adoc create mode 100755 build_rust.sh create mode 100755 ci/install-rust-toolchain.sh create mode 100755 ci/install-rustup.sh create mode 100644 rust/Cargo.toml create mode 100644 rust/build-helper/Cargo.toml create mode 100644 rust/build-helper/src/lib.rs create mode 100644 rust/cbindgen-template.toml create mode 100644 rust/misc/Cargo.toml create mode 100644 rust/misc/build.rs create mode 100644 rust/misc/src/lib.rs create mode 100644 rust/misc/src/varint.rs
base-commit: c44beea485f0f2feaf460e2ac87fdd5608d63cf0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2043%2Fezekielnewren%2Fintroduce_rust-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2043/ezekielnewren/introduce_rust-v2
Pull-Request: https://github.com/git/git/pull/2043
Range-diff vs v1:
-: ---------- > 1: 5f77f1bd5d cleanup: rename variables that collide with Rust primitive type names
-: ---------- > 2: 7082e32c59 make: add -fPIE flag
-: ---------- > 3: 7fe85f0eac make: merge xdiff lib into libgit.a
10: 0cd2168512 ! 4: 3061cc46c1 xdiff: use one definition for freeing xdfile_t
@@ Metadata
Author: Ezekiel Newren <[email protected]>
## Commit message ##
- xdiff: use one definition for freeing xdfile_t
-
- Simplify xdl_prepare_ctx() by using xdl_free_ctx() instead of using
- local variables with hand rolled memory management.
+ make: merge reftable lib into libgit.a
Signed-off-by: Ezekiel Newren <[email protected]>
- ## xdiff/xprepare.c ##
-@@ xdiff/xprepare.c: static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t
- }
-
+ ## Makefile ##
+@@ Makefile: export PYTHON_PATH
+ TEST_SHELL_PATH = $(SHELL_PATH)
-+static void xdl_free_ctx(xdfile_t *xdf) {
-+ xdl_free(xdf->rindex);
-+ xdl_free(xdf->rchg - 1);
-+ xdl_free(xdf->ha);
-+ xdl_free(xdf->recs);
-+ xdl_cha_free(&xdf->rcha);
-+}
-+
-+
- static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
- xdlclassifier_t *cf, xdfile_t *xdf) {
-- long nrec, bsize;
-+ long bsize;
- unsigned long hav;
- char const *blk, *cur, *top, *prev;
- xrecord_t *crec;
-- xrecord_t **recs;
-- unsigned long *ha;
-- char *rchg;
-- long *rindex;
+ LIB_FILE = libgit.a
+-REFTABLE_LIB = reftable/libreftable.a
-- ha = NULL;
-- rindex = NULL;
-- rchg = NULL;
-- recs = NULL;
-+ xdf->ha = NULL;
-+ xdf->rindex = NULL;
-+ xdf->rchg = NULL;
-+ xdf->recs = NULL;
-+ xdf->nrec = 0;
+ GENERATED_H += command-list.h
+ GENERATED_H += config-list.h
+@@ Makefile: LIB_OBJS += rebase.o
+ LIB_OBJS += ref-filter.o
+ LIB_OBJS += reflog-walk.o
+ LIB_OBJS += reflog.o
++LIB_OBJS += reftable/basics.o
++LIB_OBJS += reftable/error.o
++LIB_OBJS += reftable/block.o
++LIB_OBJS += reftable/blocksource.o
++LIB_OBJS += reftable/iter.o
++LIB_OBJS += reftable/merged.o
++LIB_OBJS += reftable/pq.o
++LIB_OBJS += reftable/record.o
++LIB_OBJS += reftable/stack.o
++LIB_OBJS += reftable/system.o
++LIB_OBJS += reftable/table.o
++LIB_OBJS += reftable/tree.o
++LIB_OBJS += reftable/writer.o
+ LIB_OBJS += refs.o
+ LIB_OBJS += refs/debug.o
+ LIB_OBJS += refs/files-backend.o
+@@ Makefile: CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o
- if (xdl_cha_init(&xdf->rcha, sizeof(xrecord_t), narec / 4 + 1) < 0)
- goto abort;
-- if (!XDL_ALLOC_ARRAY(recs, narec))
-+ if (!XDL_ALLOC_ARRAY(xdf->recs, narec))
- goto abort;
+ UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
-- nrec = 0;
- if ((cur = blk = xdl_mmfile_first(mf, &bsize))) {
- for (top = blk + bsize; cur < top; ) {
- prev = cur;
- hav = xdl_hash_record(&cur, top, xpp->flags);
-- if (XDL_ALLOC_GROW(recs, nrec + 1, narec))
-+ if (XDL_ALLOC_GROW(xdf->recs, xdf->nrec + 1, narec))
- goto abort;
- if (!(crec = xdl_cha_alloc(&xdf->rcha)))
- goto abort;
- crec->ptr = (u8 const*) prev;
- crec->size = (long) (cur - prev);
- crec->ha = hav;
-- recs[nrec++] = crec;
-+ xdf->recs[xdf->nrec++] = crec;
- if (xdl_classify_record(pass, cf, crec) < 0)
- goto abort;
- }
- }
+-# reftable lib may depend on what is in libgit.a
+-GITLIBS = common-main.o $(LIB_FILE) $(REFTABLE_LIB) $(LIB_FILE)
++GITLIBS = common-main.o $(LIB_FILE)
+ EXTLIBS =
-- if (!XDL_CALLOC_ARRAY(rchg, nrec + 2))
-+ if (!XDL_CALLOC_ARRAY(xdf->rchg, xdf->nrec + 2))
- goto abort;
+ GIT_USER_AGENT = git/$(GIT_VERSION)
+@@ Makefile: reconfigure config.mak.autogen: config.status
+ .PHONY: reconfigure # This is a convenience target.
+ endif
- if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) &&
- (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF)) {
-- if (!XDL_ALLOC_ARRAY(rindex, nrec + 1))
-+ if (!XDL_ALLOC_ARRAY(xdf->rindex, xdf->nrec + 1))
- goto abort;
-- if (!XDL_ALLOC_ARRAY(ha, nrec + 1))
-+ if (!XDL_ALLOC_ARRAY(xdf->ha, xdf->nrec + 1))
- goto abort;
- }
+-REFTABLE_OBJS += reftable/basics.o
+-REFTABLE_OBJS += reftable/error.o
+-REFTABLE_OBJS += reftable/block.o
+-REFTABLE_OBJS += reftable/blocksource.o
+-REFTABLE_OBJS += reftable/iter.o
+-REFTABLE_OBJS += reftable/merged.o
+-REFTABLE_OBJS += reftable/pq.o
+-REFTABLE_OBJS += reftable/record.o
+-REFTABLE_OBJS += reftable/stack.o
+-REFTABLE_OBJS += reftable/system.o
+-REFTABLE_OBJS += reftable/table.o
+-REFTABLE_OBJS += reftable/tree.o
+-REFTABLE_OBJS += reftable/writer.o
+-
+ TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
-- xdf->nrec = nrec;
-- xdf->recs = recs;
-- xdf->rchg = rchg + 1;
-- xdf->rindex = rindex;
-+ xdf->rchg += 1;
- xdf->nreff = 0;
-- xdf->ha = ha;
- xdf->dstart = 0;
-- xdf->dend = nrec - 1;
-+ xdf->dend = xdf->nrec - 1;
+ .PHONY: test-objs
+@@ Makefile: OBJECTS += $(SCALAR_OBJS)
+ OBJECTS += $(PROGRAM_OBJS)
+ OBJECTS += $(TEST_OBJS)
+ OBJECTS += $(FUZZ_OBJS)
+-OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS)
++OBJECTS += $(REFTABLE_TEST_OBJS)
+ OBJECTS += $(UNIT_TEST_OBJS)
+ OBJECTS += $(CLAR_TEST_OBJS)
+ OBJECTS += $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
+@@ Makefile: scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
+ $(LIB_FILE): $(LIB_OBJS)
+ $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
- return 0;
+-$(REFTABLE_LIB): $(REFTABLE_OBJS)
+- $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
+-
+ export DEFAULT_EDITOR DEFAULT_PAGER
- abort:
-- xdl_free(ha);
-- xdl_free(rindex);
-- xdl_free(rchg);
-- xdl_free(recs);
-- xdl_cha_free(&xdf->rcha);
-+ xdl_free_ctx(xdf);
- return -1;
- }
+ Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
+@@ Makefile: clean: profile-clean coverage-clean cocciclean
+ $(RM) git.rc git.res
+ $(RM) $(OBJECTS)
+ $(RM) headless-git.o
+- $(RM) $(LIB_FILE) $(REFTABLE_LIB)
++ $(RM) $(LIB_FILE)
+ $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
+ $(RM) $(TEST_PROGRAMS)
+ $(RM) $(FUZZ_PROGRAMS)
+@@ Makefile: endif
+ LIBGIT_PUB_OBJS += contrib/libgit-sys/public_symbol_export.o
+ LIBGIT_PUB_OBJS += libgit.a
+-LIBGIT_PUB_OBJS += reftable/libreftable.a
--static void xdl_free_ctx(xdfile_t *xdf) {
-- xdl_free(xdf->rindex);
-- xdl_free(xdf->rchg - 1);
-- xdl_free(xdf->ha);
-- xdl_free(xdf->recs);
-- xdl_cha_free(&xdf->rcha);
--}
--
--
- void xdl_free_env(xdfenv_t *xe) {
+ LIBGIT_PARTIAL_EXPORT = contrib/libgit-sys/partial_symbol_export.o
- xdl_free_ctx(&xe->xdf2);
1: 6d065f550f ! 5: 0fc89c3ec3 doc: add a policy for using Rust
@@ Documentation/technical/rust-support.adoc (new)
+these crates, but for now we omit them.
+
+Tools like bindgen and cbindgen create C-styled unsafe Rust code rather than
-+idiomatic Rust; where possible, we prefer to switch to idiomatic Rust. Any
-+standard C library functions that are needed can be manually wrapped on the
-+Rust side.
++idiomatic Rust; where possible, we prefer to switch to idiomatic Rust.
++However, we may use bindgen and cbindgen to share existing Git types as an
++interim step.
+
+Rust upstream releases every six weeks and only supports the latest stable
+release. While it is nice that upstream is active, we would like our software
-: ---------- > 6: 8e030170dd BreakingChanges: announce Rust becoming mandatory
2: cc9cf87775 ! 7: 6032a8740c xdiff: introduce rust
@@ Metadata
Author: Ezekiel Newren <[email protected]>
## Commit message ##
- xdiff: introduce rust
+ build: introduce rust
Upcoming patches will simplify xdiff, while also porting parts of it to
Rust. In preparation, add some stubs and setup the Rust build. For now,
it is easier to let cargo build rust and have make or meson merely link
against the static library that cargo builds. In line with ongoing
libification efforts, use multiple crates to allow more modularity on
- the Rust side. xdiff is the crate that this series will focus on, but
- we also introduce the interop crate for future patch series.
+ the Rust side. The xdiff and ivec crates are the focal point for this
+ series.
- In order to facilitate interoperability between C and Rust, introduce C
- definitions for Rust primitive types in git-compat-util.h.
+ cbindgen will be used to generate header files for each Rust crate for
+ C interoperability.
Signed-off-by: Ezekiel Newren <[email protected]>
@@ .gitignore: Release/
/contrib/buildsystems/out
/contrib/libgit-rs/target
/contrib/libgit-sys/target
-+/.idea/
++.idea/
+/rust/target/
+/rust/Cargo.lock
## Makefile ##
+@@ Makefile: include shared.mak
+ # Define LIBPCREDIR=/foo/bar if your PCRE header and library files are
+ # in /foo/bar/include and /foo/bar/lib directories.
+ #
++# == Optional Rust support ==
++#
++# Define WITH_RUST=false if you don't want to include features and subsystems
++# written in Rust into Git. For now, Rust is still an optional feature of the
++# build process. With Git 3.0 though, Rust will be mandatory.
++#
++# Building Rust code requires Cargo.
++#
+ # == SHA-1 and SHA-256 defines ==
+ #
+ # === SHA-1 backend ===
@@ Makefile: TEST_SHELL_PATH = $(SHELL_PATH)
LIB_FILE = libgit.a
- XDIFF_LIB = xdiff/lib.a
-+
+
+EXTLIBS =
+
++GIT_BUILD_DIR := $(CURDIR)
++export GIT_BUILD_DIR
++
++RUST_CRATES :=
++.PHONY: compile_rust rustclean
++
++WITH_RUST ?= true
++ifeq ($(WITH_RUST),true)
++
+ifeq ($(DEBUG), 1)
-+ RUST_BUILD_MODE = debug
++ RUST_BUILD_MODE := debug
+else
-+ RUST_BUILD_MODE = release
++ RUST_BUILD_MODE := release
+endif
+
-+RUST_TARGET_DIR = rust/target/$(RUST_BUILD_MODE)
-+RUST_FLAGS_FOR_C = -L$(RUST_TARGET_DIR)
++RUST_TARGET_DIR := $(GIT_BUILD_DIR)/$(RUST_BUILD_MODE)
+
-+.PHONY: compile_rust
-+compile_rust:
-+ ./build_rust.sh . $(RUST_BUILD_MODE) xdiff
++RUST_LIBS := $(foreach c,$(RUST_CRATES),$(GIT_BUILD_DIR)/lib$(c).a)
++
++EXTLIBS += $(RUST_LIBS)
+
-+EXTLIBS += ./$(RUST_TARGET_DIR)/libxdiff.a
++compile_rust: $(RUST_LIBS)
++rustclean:
++ $(RM) $(RUST_LIBS)
++ cd rust && cargo clean
++
++$(GIT_BUILD_DIR)/lib%.a:
++ ./build_rust.sh $(GIT_BUILD_DIR) $(RUST_BUILD_MODE) $*
+
+UNAME_S := $(shell uname -s)
+ifeq ($(UNAME_S),Linux)
-+ EXTLIBS += -ldl
++ EXTLIBS += -ldl
++endif
++
++else ifeq ($(WITH_RUST),false)
++compile_rust:
++ :
++rustclean:
++ :
++else
++$(error 'WITH_RUST' must be true or false)
+endif
+
- REFTABLE_LIB = reftable/libreftable.a
-
GENERATED_H += command-list.h
-@@ Makefile: UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o
+ GENERATED_H += config-list.h
+ GENERATED_H += hook-list.h
+@@ Makefile: CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o
+ UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
- # xdiff and reftable libs may in turn depend on what is in libgit.a
- GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE)
+ GITLIBS = common-main.o $(LIB_FILE)
-EXTLIBS =
-+
GIT_USER_AGENT = git/$(GIT_VERSION)
+@@ Makefile: CC_LD_DYNPATH = -Wl,-rpath,
+ BASIC_CFLAGS = -I. -fPIE
+ BASIC_LDFLAGS =
+
++ifeq ($(WITH_RUST),true)
++BASIC_CFLAGS += -DWITH_RUST
++endif
+ # library flags
+ ARFLAGS = rcs
+ PTHREAD_CFLAGS =
@@ Makefile: git.sp git.s git.o: EXTRA_CPPFLAGS = \
'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
'-DGIT_INFO_PATH="$(infodir_relative_SQ)"'
@@ Makefile: $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(LIBS)
-@@ Makefile: $(LIB_FILE): $(LIB_OBJS)
- $(XDIFF_LIB): $(XDIFF_OBJS)
- $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-
-+
- $(REFTABLE_LIB): $(REFTABLE_OBJS)
- $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-
@@ Makefile: perf: all
t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) $(UNIT_TEST_DIR)/test-lib.o
@@ Makefile: cocciclean:
$(RM) contrib/coccinelle/*.cocci.patch
-clean: profile-clean coverage-clean cocciclean
-+rustclean:
-+ cd rust && cargo clean
-+
+clean: profile-clean coverage-clean cocciclean rustclean
$(RM) -r .build $(UNIT_TEST_BIN)
$(RM) GIT-TEST-SUITES
@@ build_rust.sh (new)
@@
+#!/bin/sh
+
-+
+rustc -vV || exit $?
+cargo --version || exit $?
+
@@ build_rust.sh (new)
+ exit 1
+fi
+
-+cd $dir_rust && cargo clean && pwd && cargo build -p $crate $rust_args; cd $dir_git_root
-+
+libfile="lib${crate}.a"
+if rustup show active-toolchain | grep windows-msvc; then
+ libfile="${crate}.lib"
++ PATH="$(echo $PATH | tr ':' '\n' | grep -Ev "^(/mingw64/bin|/usr/bin)$" | paste -sd: -):/mingw64/bin:/usr/bin"
+fi
-+dst=$dir_build/$libfile
+
-+if [ "$dir_git_root" != "$dir_build" ]; then
-+ src=$dir_rust/target/$rust_build_profile/$libfile
-+ if [ ! -f $src ]; then
-+ echo >&2 "::error:: cannot find path of static library $src is not a file or does not exist"
-+ exit 5
-+ fi
++CARGO_TARGET_DIR=$dir_git_root/.build/rust/$crate
++export CARGO_TARGET_DIR
++
++cd $dir_rust && cargo clean && pwd && USE_LINKING="false" cargo build -p $crate $rust_args; cd $dir_git_root
++
++src=$CARGO_TARGET_DIR/$rust_build_profile/$libfile
++dst=$dir_build/$libfile
+
-+ rm $dst 2>/dev/null
-+ mv $src $dst
++if [ ! -f $src ]; then
++ echo >&2 "::error:: cannot find path of static library $src is not a file or does not exist"
++ exit 5
+fi
-
- ## git-compat-util.h ##
-@@ git-compat-util.h: static inline int is_xplatform_dir_sep(int c)
- #include "compat/msvc.h"
- #endif
-
-+/* rust types */
-+typedef uint8_t u8;
-+typedef uint16_t u16;
-+typedef uint32_t u32;
-+typedef uint64_t u64;
-+
-+typedef int8_t i8;
-+typedef int16_t i16;
-+typedef int32_t i32;
-+typedef int64_t i64;
-+
-+typedef float f32;
-+typedef double f64;
-+
-+typedef size_t usize;
-+typedef ptrdiff_t isize;
-+
- /* used on Mac OS X */
- #ifdef PRECOMPOSE_UNICODE
- #include "compat/precompose_utf8.h"
++
++rm $dst 2>/dev/null
++echo mv $src $dst
++mv $src $dst
## meson.build ##
@@ meson.build: version_gen_environment.set('GIT_DATE', get_option('build_date'))
version_gen_environment.set('GIT_USER_AGENT', get_option('user_agent'))
version_gen_environment.set('GIT_VERSION', get_option('version'))
-+if get_option('optimization') in ['2', '3', 's', 'z']
-+ rust_build_profile = 'release'
-+else
-+ rust_build_profile = 'debug'
-+endif
++rust_crates = []
+
-+# Run `rustup show active-toolchain` and capture output
-+rustup_out = run_command('rustup', 'show', 'active-toolchain',
-+ check: true).stdout().strip()
-+
-+rust_crates = ['xdiff']
+rust_builds = []
++with_rust = get_option('with_rust')
++if with_rust
++ rustc = find_program('rustc', required : false)
++ cargo = find_program('cargo', required : false)
+
-+foreach crate : rust_crates
-+ if rustup_out.contains('windows-msvc')
-+ libfile = crate + '.lib'
++ if not rustc.found() or not cargo.found()
++ error('Rust toolchain not found. Reconfigure with -Dwith_rust=false')
++ endif
++
++ if get_option('optimization') in ['2', '3', 's', 'z']
++ rust_build_profile = 'release'
+ else
-+ libfile = 'lib' + crate + '.a'
++ rust_build_profile = 'debug'
+ endif
+
-+ rust_builds += custom_target(
-+ 'rust_build_'+crate,
-+ output: libfile,
-+ build_by_default: true,
-+ build_always_stale: true,
-+ command: [
-+ meson.project_source_root() / 'build_rust.sh',
-+ meson.current_build_dir(), rust_build_profile, crate,
-+ ],
-+ install: false,
-+ )
-+endforeach
++ # Run `rustup show active-toolchain` and capture output
++ rustup_out = run_command('rustup', 'show', 'active-toolchain',
++ check: true).stdout().strip()
++
++ rust_environment = script_environment
++
++ foreach crate : rust_crates
++ if rustup_out.contains('windows-msvc')
++ libfile = crate + '.lib'
++ else
++ libfile = 'lib' + crate + '.a'
++ endif
++
++ rust_builds += custom_target(
++ 'rust_build_'+crate,
++ output: libfile,
++ build_by_default: true,
++ build_always_stale: true,
++ command: [
++ meson.project_source_root() / 'build_rust.sh',
++ meson.current_build_dir(), rust_build_profile, crate,
++ ],
++ install: false,
++ env: rust_environment,
++ )
++ endforeach
++else
++ message('Rust components disabled (-Dwith_rust=false)')
++endif
+
+
compiler = meson.get_compiler('c')
libgit_sources = [
+@@ meson.build: libgit_c_args = [
+ '-DSHELL_PATH="' + fs.as_posix(target_shell.full_path()) + '"',
+ ]
+
++if with_rust
++ libgit_c_args += '-DWITH_RUST'
++endif
++
+ system_attributes = get_option('gitattributes')
+ if system_attributes != ''
+ libgit_c_args += '-DETC_GITATTRIBUTES="' + system_attributes + '"'
+@@ meson.build: elif host_machine.system() == 'windows'
+ ]
+
+ libgit_dependencies += compiler.find_library('ntdll')
++ libgit_dependencies += compiler.find_library('userenv')
+ libgit_include_directories += 'compat/win32'
+ if compiler.get_id() == 'msvc'
+ libgit_include_directories += 'compat/vcbuild/include'
@@ meson.build: version_def_h = custom_target(
libgit_sources += version_def_h
@@ meson.build: version_def_h = custom_target(
dependencies: libgit_dependencies,
include_directories: libgit_include_directories,
+ ## meson_options.txt ##
+@@ meson_options.txt: option('zlib_backend', type: 'combo', choices: ['auto', 'zlib', 'zlib-ng'], valu
+ description: 'The backend used for compressing objects and other data.')
+
+ # Build tweaks.
++option('with_rust', type: 'boolean', value: true,
++ description: 'Enable building with Rust, true by default.')
+ option('breaking_changes', type: 'boolean', value: false,
+ description: 'Enable upcoming breaking changes.')
+ option('macos_use_homebrew_gettext', type: 'boolean', value: true,
+
## rust/Cargo.toml (new) ##
@@
+[workspace]
-+members = [
-+ "xdiff",
-+ "interop",
-+]
++members = []
+resolver = "2"
-
- ## rust/interop/Cargo.toml (new) ##
-@@
-+[package]
-+name = "interop"
-+version = "0.1.0"
-+edition = "2021"
-+
-+[lib]
-+name = "interop"
-+path = "src/lib.rs"
-+## staticlib to generate xdiff.a for use by gcc
-+## cdylib (optional) to generate xdiff.so for use by gcc
-+## rlib is required by the rust unit tests
-+crate-type = ["staticlib", "rlib"]
-+
-+[dependencies]
-
- ## rust/interop/src/lib.rs (new) ##
-
- ## rust/xdiff/Cargo.toml (new) ##
-@@
-+[package]
-+name = "xdiff"
-+version = "0.1.0"
-+edition = "2021"
-+
-+[lib]
-+name = "xdiff"
-+path = "src/lib.rs"
-+## staticlib to generate xdiff.a for use by gcc
-+## cdylib (optional) to generate xdiff.so for use by gcc
-+## rlib is required by the rust unit tests
-+crate-type = ["staticlib", "rlib"]
-+
-+[dependencies]
-+interop = { path = "../interop" }
-
- ## rust/xdiff/src/lib.rs (new) ##
-: ---------- > 8: cd04ed5aa7 help: report on whether or not Rust is enabled
3: 6c47401ba0 ! 9: fcdfc55fb7 github workflows: install rust @@ Commit message
the Rust toolchain, the Rust target triple must be set to x86_64-pc-windows-gnu for make (win build), and
x86_64-pc-windows-msvc for meson (win+Meson build).
+ * MSVC builds: Rearrange PATH to look in /mingw64/bin and /usr/bin
+ last.
* On musl: libc differences, such as ftruncate64 vs ftruncate, were
not accounted for until Rust version 1.72.0. No older version of
Rust will work on musl for our needs.
@@ .github/workflows/main.yml: jobs:
outputs:
enabled: ${{ steps.check-ref.outputs.enabled }}${{ steps.skip-if-redundant.outputs.enabled }}
skip_concurrent: ${{ steps.check-ref.outputs.skip_concurrent }}
-+ rust_version_minimum: 1.61.0
++ rust_version_minimum: 1.63.0
+ rust_version_windows: 1.78.0
+ rust_version_musl: 1.72.0
+ ## the rust target is inferred by rustup unless specified
@@ .github/workflows/main.yml: jobs:
steps:
- uses: actions/checkout@v4
- uses: git-for-windows/setup-git-for-windows-sdk@v1
++ with:
++ flavor: full
+ - name: Install rustup via github actions
+ uses: actions-rs/toolchain@v1
+ with:
4: 8e350700bc ! 10: 6eeef4081c win+Meson: do allow linking with the Rust-built xdiff
@@ Commit message
handling from an earlier patch]
- ## .github/workflows/main.yml ##
-@@ .github/workflows/main.yml: jobs:
- steps:
- - uses: actions/checkout@v4
- - uses: git-for-windows/setup-git-for-windows-sdk@v1
-+ - name: ensure that libuserenv.a is present
-+ shell: bash
-+ run: |
-+ cd /mingw64/lib && {
-+ test -f libuserenv.a ||
-+ /c/Program\ Files/Git/mingw64/bin/curl -Lo libuserenv.a \
-+ https://github.com/git-for-windows/git-sdk-64/raw/HEAD/mingw64/lib/libuserenv.a
-+ }
- - name: Install rustup via github actions
- uses: actions-rs/toolchain@v1
- with:
-
## config.mak.uname ##
@@ config.mak.uname: ifeq ($(uname_S),MINGW)
COMPAT_CFLAGS += -D_USE_32BIT_TIME_T
@@ config.mak.uname: ifeq ($(uname_S),MINGW)
CC = gcc
COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
-fstack-protector-strong
-
- ## meson.build ##
-@@ meson.build: elif host_machine.system() == 'windows'
- ]
-
- libgit_dependencies += compiler.find_library('ntdll')
-+ libgit_dependencies += compiler.find_library('userenv')
- libgit_include_directories += 'compat/win32'
- if compiler.get_id() == 'msvc'
- libgit_include_directories += 'compat/vcbuild/include'
5: a00cbf7bcb = 11: 1e13d6c45f github workflows: upload Cargo.lock
6: 922d506ed6 < -: ---------- ivec: create a vector type that is interoperable between C and Rust
-: ---------- > 12: 1c923a71f2 build: new crate, build-helper
7: 3a6f822e2a ! 13: 6a27e07e63 xdiff/xprepare: remove superfluous forward declarations
@@ Metadata
Author: Ezekiel Newren <[email protected]>
## Commit message ##
- xdiff/xprepare: remove superfluous forward declarations
+ build-helper: link against libgit.a and any other required C libraries
- Move xdl_prepare_env() later in the file to avoid the need
- for forward declarations.
+ Don't link against the C libraries when building with Make or Meson.
+ Run cargo tests like this:
+ cd rust && cargo clean && USE_LINKING=true cargo test
Signed-off-by: Ezekiel Newren <[email protected]>
- ## xdiff/xprepare.c ##
-@@ xdiff/xprepare.c: typedef struct s_xdlclassifier {
+ ## rust/build-helper/Cargo.toml ##
+@@ rust/build-helper/Cargo.toml: version = "0.1.0"
+ edition = "2021"
-
-
--static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags);
--static void xdl_free_classifier(xdlclassifier_t *cf);
--static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
-- unsigned int hbits, xrecord_t *rec);
--static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
-- xdlclassifier_t *cf, xdfile_t *xdf);
--static void xdl_free_ctx(xdfile_t *xdf);
--static int xdl_clean_mmatch(char const *dis, long i, long s, long e);
--static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
--static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2);
--static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
--
--
--
--
- static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) {
- cf->flags = flags;
-
-@@ xdiff/xprepare.c: static void xdl_free_ctx(xdfile_t *xdf) {
- }
-
-
--int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
-- xdfenv_t *xe) {
-- long enl1, enl2, sample;
-- xdlclassifier_t cf;
--
-- memset(&cf, 0, sizeof(cf));
--
-- /*
-- * For histogram diff, we can afford a smaller sample size and
-- * thus a poorer estimate of the number of lines, as the hash
-- * table (rhash) won't be filled up/grown. The number of lines
-- * (nrecs) will be updated correctly anyway by
-- * xdl_prepare_ctx().
-- */
-- sample = (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF
-- ? XDL_GUESS_NLINES2 : XDL_GUESS_NLINES1);
--
-- enl1 = xdl_guess_lines(mf1, sample) + 1;
-- enl2 = xdl_guess_lines(mf2, sample) + 1;
--
-- if (xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0)
-- return -1;
--
-- if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
--
-- xdl_free_classifier(&cf);
-- return -1;
-- }
-- if (xdl_prepare_ctx(2, mf2, enl2, xpp, &cf, &xe->xdf2) < 0) {
--
-- xdl_free_ctx(&xe->xdf1);
-- xdl_free_classifier(&cf);
-- return -1;
-- }
+ [dependencies]
-
-- if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) &&
-- (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) &&
-- xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) {
--
-- xdl_free_ctx(&xe->xdf2);
-- xdl_free_ctx(&xe->xdf1);
-- xdl_free_classifier(&cf);
-- return -1;
-- }
--
-- xdl_free_classifier(&cf);
--
-- return 0;
--}
--
--
- void xdl_free_env(xdfenv_t *xe) {
-
- xdl_free_ctx(&xe->xdf2);
-@@ xdiff/xprepare.c: static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2
-
- return 0;
- }
+
+ ## rust/build-helper/src/lib.rs ##
+@@
++use std::collections::HashMap;
++use std::path::PathBuf;
+
-+int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
-+ xdfenv_t *xe) {
-+ long enl1, enl2, sample;
-+ xdlclassifier_t cf;
+
-+ memset(&cf, 0, sizeof(cf));
++fn parse_bool_from_str(value: &str) -> bool {
++ match value {
++ "1" | "true" | "yes" | "on" => true,
++ "0" | "false" | "no" | "off" => false,
++ _ => false
++ }
++}
++
++fn parse_bool_from_option(value: Option<&String>, default: bool) -> bool {
++ match value {
++ Some(v) => {
++ parse_bool_from_str(v.as_str())
++ },
++ None => default,
++ }
++}
+
-+ /*
-+ * For histogram diff, we can afford a smaller sample size and
-+ * thus a poorer estimate of the number of lines, as the hash
-+ * table (rhash) won't be filled up/grown. The number of lines
-+ * (nrecs) will be updated correctly anyway by
-+ * xdl_prepare_ctx().
-+ */
-+ sample = (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF
-+ ? XDL_GUESS_NLINES2 : XDL_GUESS_NLINES1);
++/// To build without linking against C libraries run `USE_LINKING=false cargo build`
++/// To run tests set GIT_BUILD_DIR and run `USE_LINKING=true cargo test`
++pub struct BuildHelper {
++ crate_env: HashMap<String, String>,
++}
+
-+ enl1 = xdl_guess_lines(mf1, sample) + 1;
-+ enl2 = xdl_guess_lines(mf2, sample) + 1;
+
-+ if (xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0)
-+ return -1;
++impl BuildHelper {
++ pub fn new(crate_env: HashMap<String, String>) -> Self {
++ let it = Self {crate_env};
+
-+ if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
++ let dir_crate = it.dir_crate();
++ let dir_workspace = dir_crate.parent().unwrap();
++ let dir_git = dir_workspace.parent().unwrap();
++ let dir_interop = dir_git.join("interop");
++ if !dir_interop.exists() {
++ std::fs::create_dir(dir_interop.clone()).unwrap();
++ }
+
-+ xdl_free_classifier(&cf);
-+ return -1;
-+ }
-+ if (xdl_prepare_ctx(2, mf2, enl2, xpp, &cf, &xe->xdf2) < 0) {
++ it
++ }
+
-+ xdl_free_ctx(&xe->xdf1);
-+ xdl_free_classifier(&cf);
-+ return -1;
-+ }
++ pub fn crate_name(&self) -> String {
++ self.crate_env["CARGO_PKG_NAME"].clone()
++ }
+
-+ if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) &&
-+ (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) &&
-+ xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) {
++ pub fn dir_crate(&self) -> PathBuf {
++ PathBuf::from(self.crate_env["CARGO_MANIFEST_DIR"].clone())
++ }
+
-+ xdl_free_ctx(&xe->xdf2);
-+ xdl_free_ctx(&xe->xdf1);
-+ xdl_free_classifier(&cf);
-+ return -1;
-+ }
++ pub fn build(self) {
++ let use_linking = parse_bool_from_option(self.crate_env.get("USE_LINKING"), self.crate_env.get("CARGO_TARGET_DIR").is_none());
++ let dir_crate = self.dir_crate();
++ let dir_git = dir_crate.parent().unwrap().parent().unwrap();
+
-+ xdl_free_classifier(&cf);
++ println!("cargo:rerun-if-changed={}", dir_git.display());
+
-+ return 0;
++ if use_linking {
++ if let Some(git_build_dir) = self.crate_env.get("GIT_BUILD_DIR") {
++ let mut path_git_build_dir = PathBuf::from(git_build_dir);
++ path_git_build_dir = path_git_build_dir.canonicalize().unwrap();
++ if !path_git_build_dir.is_dir() {
++ panic!("'GIT_BUILD_DIR' is not a directory: {}", path_git_build_dir.display());
++ }
++ println!("cargo:rustc-link-search=native={}", git_build_dir);
++ } else {
++ panic!("environment variable 'GIT_BUILD_DIR' is not set");
++ }
++
++ println!("cargo:rustc-link-lib=static=git");
++ println!("cargo:rustc-link-lib=pcre2-8");
++ if self.crate_env.get("ZLIB_NG").is_some() {
++ println!("cargo:rustc-link-lib=z-ng");
++ } else {
++ println!("cargo:rustc-link-lib=z");
++ }
++ } else {
++ println!("cargo:warning={} is not linking against C objects, `USE_LINKING=true cargo test`", self.crate_env["CARGO_PKG_NAME"]);
++ }
++ }
+}
++
++
8: c7cd71dae0 < -: ---------- xdiff: delete unnecessary fields from xrecord_t and xdfile_t
9: 1096c8f0a4 < -: ---------- xdiff: make fields of xrecord_t Rust friendly
11: 7ea2dccd71 < -: ---------- xdiff: replace chastore with an ivec in xdfile_t
12: d8f561e173 < -: ---------- xdiff: delete nrec field from xdfile_t
13: 15c2854a32 < -: ---------- xdiff: delete recs field from xdfile_t
14: 3dacb2c09d < -: ---------- xdiff: make xdfile_t more rust friendly
15: 9fdd23acf6 < -: ---------- xdiff: implement xdl_trim_ends() in Rust
-: ---------- > 14: fa33440568 build-helper: cbindgen, let crates generate a header file
-: ---------- > 15: df837fdb4d varint: use explicit width for integers
-: ---------- > 16: 17143ced6f build: new crate, misc
-: ---------- > 17: 89bb7c3613 misc: use BuildHelper
-: ---------- > 18: 3c521fa2e4 misc::varint: reimplement as test balloon for RustSignature · 1 line
gitgitgadget
PATCH v2 1/18 cleanup: rename variables that collide with Rust primitive type names
From: Ezekiel Newren <[email protected]>
Use a regex to find and rename variables that collide with Rust primitive integer and float type names:
git grep -n -E -e '\<([ui](8|16|32|64|size)|(f(32|64)))\>'
Matches were reviewed and renamed. The remaining matches don't count because:
- Rust source files:
contrib/libgit-rs/src/config.rs contrib/libgit-sys/src/lib.rs
t/t4018/rust-impl
t/t4018/rust-trait
- Intentional references:
t/helper/test-parse-options.c (prints Rust int names) t/t0040-parse-options.sh (tests the above)
View with --color-words to highlight the variable renames.
--- odb.c | 8 ++++---- reftable/record.c | 6 +++--- t/helper/test-parse-options.c | 12 ++++++------ xdiff/xtypes.h | 2 +- xdiff/xutils.c | 8 ++++---- xdiff/xutils.h | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-)
odb.c +4 -4
@@ -913,7 +913,7 @@ void *odb_read_object_peeled(struct object_database *odb, {enum object_type type;void *buffer; -unsigned long isize; +unsigned long isize_;struct object_id actual_oid;oidcpy (&actual_oid, oid);
@@ -921,11 +921,11 @@ void *odb_read_object_peeled(struct object_database *odb,int ref_length =-1 ;const char *ref_type =NULL ; - buffer =odb_read_object (odb, &actual_oid, &type, &isize); + buffer =odb_read_object (odb, &actual_oid, &type, &isize_);if (!buffer)return NULL ;if (type == required_type) { - *size = isize; + *size = isize_;if (actual_oid_return)oidcpy (actual_oid_return, &actual_oid);return buffer;
@@ -941,7 +941,7 @@ void *odb_read_object_peeled(struct object_database *odb, } ref_length =strlen (ref_type); -if (ref_length + odb->repo->hash_algo->hexsz > isize || +if (ref_length + odb->repo->hash_algo->hexsz > isize_ ||memcmp (buffer, ref_type, ref_length) ||get_oid_hex_algop ((char *) buffer + ref_length, &actual_oid, odb->repo->hash_algo)) {
reftable/record.c +3 -3
@@ -675,7 +675,7 @@ static int reftable_log_record_key(const void *r, struct reftable_buf *dest)const struct reftable_log_record *rec = (const struct reftable_log_record *)r;int len =strlen (rec->refname), err; -uint8_t i64[8 ]; +uint8_t i64_[8 ];uint64_t ts =0 ;reftable_buf_reset (dest);
@@ -684,9 +684,9 @@ static int reftable_log_record_key(const void *r, struct reftable_buf *dest)return err; ts = (~ts) - rec->update_index; -reftable_put_be64 (&i64[0 ], ts); +reftable_put_be64 (&i64_[0 ], ts); - err =reftable_buf_add (dest, i64,sizeof (i64)); + err =reftable_buf_add (dest, i64_,sizeof (i64_));if (err <0 )return err;
t/helper/test-parse-options.c +6 -6
@@ -120,8 +120,8 @@ int cmd__parse_options(int argc, const char **argv) };struct string_list expect =STRING_LIST_INIT_NODUP ;struct string_list list =STRING_LIST_INIT_NODUP ; -uint16_t u16 =0 ; -int16_t i16 =0 ; +uint16_t u16_ =0 ; +int16_t i16_ =0 ;struct option options[] = {OPT_BOOL (0 ,"yes" , &boolean,"get a boolean" ),
@@ -142,10 +142,10 @@ int cmd__parse_options(int argc, const char **argv)OPT_NEGBIT (0 ,"neg-or4" , &boolean,"same as --no-or4" ,4 ),OPT_GROUP ("" ),OPT_INTEGER ('i' ,"integer" , &integer,"get a integer" ), -OPT_INTEGER (0 ,"i16" , &i16,"get a 16 bit integer" ), +OPT_INTEGER (0 ,"i16" , &i16_,"get a 16 bit integer" ),OPT_INTEGER ('j' ,NULL , &integer,"get a integer, too" ),OPT_UNSIGNED ('u' ,"unsigned" , &unsigned_integer,"get an unsigned integer" ), -OPT_UNSIGNED (0 ,"u16" , &u16,"get a 16 bit unsigned integer" ), +OPT_UNSIGNED (0 ,"u16" , &u16_,"get a 16 bit unsigned integer" ),OPT_SET_INT (0 ,"set23" , &integer,"set integer to 23" ,23 ),OPT_CMDMODE (0 ,"mode1" , &integer,"set integer to 1 (cmdmode option)" ,1 ), OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2),
@@ -225,9 +225,9 @@ int cmd__parse_options(int argc, const char **argv) }show (&expect, &ret,"boolean: %d" , boolean);show (&expect, &ret,"integer: %d" , integer); -show (&expect, &ret,"i16: %" PRIdMAX, (intmax_t ) i16); +show (&expect, &ret,"i16: %" PRIdMAX, (intmax_t ) i16_);show (&expect, &ret,"unsigned: %lu" , unsigned_integer); -show (&expect, &ret,"u16: %" PRIuMAX, (uintmax_t ) u16); +show (&expect, &ret,"u16: %" PRIuMAX, (uintmax_t ) u16_);show (&expect, &ret,"timestamp: %" PRItime, timestamp);show (&expect, &ret,"string: %s" , string ? string :"(not set)" );show (&expect, &ret,"abbrev: %d" , abbrev);
xdiff/xtypes.h +1 -1
@@ -32,7 +32,7 @@ typedef struct s_chanode { typedef struct s_chastore { chanode_t *head, *tail; - long isize, nsize; + long isize_, nsize; chanode_t *ancur; chanode_t *sncur; long scurr;
xdiff/xutils.c +4 -4
@@ -71,11 +71,11 @@ long xdl_mmfile_size(mmfile_t *mmf) } -int xdl_cha_init (chastore_t *cha,long isize,long icount) { +int xdl_cha_init (chastore_t *cha,long isize_,long icount) { cha->head = cha->tail =NULL ; - cha->isize = isize; - cha->nsize = icount * isize; + cha->isize_ = isize_; + cha->nsize = icount * isize_; cha->ancur = cha->sncur =NULL ; cha->scurr =0 ;
@@ -113,7 +113,7 @@ void *xdl_cha_alloc(chastore_t *cha) { } data = (char *) ancur +sizeof (chanode_t) + ancur->icurr; - ancur->icurr += cha->isize; + ancur->icurr += cha->isize_;return data; }
xdiff/xutils.h +1 -1
@@ -28,7 +28,7 @@long xdl_bogosqrt (long n);int xdl_emit_diffrec (char const *rec,long size,char const *pre,long psize,xdemitcb_t *ecb); -int xdl_cha_init (chastore_t *cha,long isize,long icount); +int xdl_cha_init (chastore_t *cha,long isize_,long icount);void xdl_cha_free (chastore_t *cha);void *xdl_cha_alloc (chastore_t *cha);long xdl_guess_lines (mmfile_t *mf,long sample);
Signature · 1 line
gitgitgadget
Re: [PATCH v2 01/18] cleanup: rename variables that collide with Rust primitive type names
Quoted 6 lines · Ezekiel Newren via GitGitGadget
cleanup: rename variables that collide with Rust primitive type names
Use a regex to find and rename variables that collide with Rust primitive integer and float type names:
git grep -n -E -e '\<([ui](8|16|32|64|size)|(f(32|64)))\>'
This explains what the patch is doing but doesn't explain why we want this change. Please update the commit message to describe the problem/issue the patch is trying to address, and then (if necessary) explain what the patch is doing.
Quoted 17 lines
Matches were reviewed and renamed. The remaining matches don't count because:
- Rust source files:
contrib/libgit-rs/src/config.rscontrib/libgit-sys/src/lib.rs
t/t4018/rust-impl
t/t4018/rust-trait
- Intentional references:
t/helper/test-parse-options.c(prints Rust int names)t/t0040-parse-options.sh(tests the above)View with --color-words to highlight the variable renames.
Signed-off-by Ezekiel Newren <[email protected]>---
odb.c void *odb_read_object_peeled(struct object_database *odb, · line 914
Quoted 3 lines
odb.c +1
-1@@ -913,7 +913,7 @@ void *odb_read_object_peeled(struct object_database *odb, { -unsigned long isize; +unsigned long isize_;
Nit: It's minor, but I can't say I'm a fan of this approach to renaming variables. It would be better to come up with a name that is more meaningful if possible rather than merely appending an underscore. In this particular case, the original name, "isize", already fails to convey much meaning, but appears to have been named this way simply to avoid a collision with the existing function argument named "size". So, you could just as easily rename "isize" to "sz" or some such.
Same comment applies to the other renamed variables...
odb.c void *odb_read_object_peeled(struct object_database *odb, · line 915
Quoted 2 lines
odb.c +1
-1- OPT_UNSIGNED(0, "u16", &u16, "get a 16 bit unsigned integer"), + OPT_UNSIGNED(0, "u16", &u16_, "get a 16 bit unsigned integer"),
... though with some of them, such as this one, it is admittedly more difficult to come up with a better name since the original name is already meaningful.
Re: [PATCH v2 01/18] cleanup: rename variables that collide with Rust primitive type names
Quoted 8 lines · Eric Sunshine
Same comment applies to the other renamed variables...
t/helper/test-parse-options.c int cmd__parse_options(int argc, const char **argv) · line 148
Quoted 2 lines
t/helper/test-parse-options.c +1
-1- OPT_UNSIGNED(0, "u16", &u16, "get a 16 bit unsigned integer"), + OPT_UNSIGNED(0, "u16", &u16_, "get a 16 bit unsigned integer"),... though with some of them, such as this one, it is admittedly more difficult to come up with a better name since the original name is already meaningful.
On top of that, just like a name that begins with an underscore is reserved by C standard, a name taht ends with an underscore is used for specific purposes by convention in this project.
Typically 'foo_' appears as a parameter to a function, whose type is specified with our interhal API, and when that type is cumbersome to work with, we have a local equivalent 'foo' of a more appropriate type whose value is populated from 'foo_' before being used, and use of 'foo' thanks to its better type is more ergonomic.
static int compare_pt(const void *a_, const void *b_)
{
struct possible_tag *a = (struct possible_tag *)a_;
struct possible_tag *b = (struct possible_tag *)b_;
if (a->depth != b->depth)
return a->depth - b->depth;
if (a->found_order != b->found_order)
return a->found_order - b->found_order;
return 0;
}
static int path_is_beyond_symlink(struct apply_state *state, const char *name_)
{
int ret;
struct strbuf name = STRBUF_INIT;
assert(*name_ != '\0');
strbuf_addstr(&name, name_);
ret = path_is_beyond_symlink_1(state, &name);
strbuf_release(&name);
return ret;
}are examples.
There are existing crappy code that uses foo_ without corresponding foo; we should clean them up, not emulating or spreading the pattern.
By the way, in this partcular case, why not use "uint16_t u16"?
Isn't the true cause of the trouble the (I might say "misguided") desire to use "u16" as a type in C code? As long as we all agree that the data that can be passed across the ffi barrier should be of the types of known size, and let C side use uint(8|16|32|64)_t and Rust side use u(8|16|32|64) consistently, we do not need to have this "cleanup", do we?
Thanks.
Re: [PATCH v2 01/18] cleanup: rename variables that collide with Rust primitive type names
Quoted 6 lines · Junio C Hamano
Isn't the true cause of the trouble the (I might say "misguided") desire to use "u16" as a type in C code? As long as we all agree that the data that can be passed across the ffi barrier should be of the types of known size, and let C side use uint(8|16|32|64)_t and Rust side use u(8|16|32|64) consistently, we do not need to have this "cleanup", do we?
It appears that I am the only one in favor of using Rust type names in C. Going forward I'll use [ui]int(8|16|32|64)_t types going forward. I'll drop this commit.
PATCH v2 2/18 make: add -fPIE flag
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
--- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Makefile +1 -1
@@ -1402,7 +1402,7 @@ endif CFLAGS = -g -O2 -Wall LDFLAGS = CC_LD_DYNPATH = -Wl,-rpath, -BASIC_CFLAGS = -I. +BASIC_CFLAGS = -I. -fPIE BASIC_LDFLAGS = # library flags
Signature · 1 line
gitgitgadget
Re: [PATCH v2 02/18] make: add -fPIE flag
Makefile endif · line 1404
Quoted 10 lines · Ezekiel Newren via GitGitGadget
make: add -fPIE flag
Signed-off-by Ezekiel Newren <[email protected]>---
Makefile +1
-1@@ -1402,7 +1402,7 @@ endif CC_LD_DYNPATH = -Wl,-rpath, -BASIC_CFLAGS = -I. +BASIC_CFLAGS = -I. -fPIE BASIC_LDFLAGS =
The commit message explains what the patch is doing (which is obvious from the patch itself) but doesn't explain why this change is needed, hence it is very difficult for a reviewer to understand why such a change is necessary.
Re: [PATCH v2 02/18] make: add -fPIE flag
Quoted 4 lines · Eric Sunshine
The commit message explains what the patch is doing (which is obvious from the patch itself) but doesn't explain why this change is needed, hence it is very difficult for a reviewer to understand why such a change is necessary.
I was trying to get the rust compiler to link against libgit.a. Both Meson and Makefile produce libgit.a. No changes were to meson.build were necessary for that to work, but but with Makefile I would get errors like:
relocation R_X86_64_32 against `.rodata' can not be used when making a PIE object; recompile with -fPIE
...
I should have added this to the commit message.
Re: [PATCH v2 02/18] make: add -fPIE flag
Quoted 6 lines · Ezekiel Newren
I was trying to get the rust compiler to link against libgit.a. Both Meson and
Makefileproduce libgit.a. No changes were to meson.build were necessary for that to work, but but withMakefileI would get errors like:
relocationR_X86_64_32against `.rodata' can not be used when making a PIE object; recompile with -fPIE
This sounds like a workaround that is somewhat platform and compiler specific limitation, at least to me. Does this need to be conditional and if so on what?
Thanks.
Re: [PATCH v2 02/18] make: add -fPIE flag
Quoted 10 lines · Junio C Hamano
Quoted 6 lines · Ezekiel Newren
I was trying to get the rust compiler to link against libgit.a. Both Meson and
Makefileproduce libgit.a. No changes were to meson.build were necessary for that to work, but but withMakefileI would get errors like:
relocationR_X86_64_32against `.rodata' can not be used when making a PIE object; recompile with -fPIE
Quoted 3 lines
This sounds like a workaround that is somewhat platform and compiler specific limitation, at least to me. Does this need to be conditional and if so on what?
I don't know, but I have another question to add to yours. Why does Make need -fPIE in order for the Rust compiler to link against libgit.a created by Make, when Meson doesn't seem to specify PIE anywhere and yet the Rust compiler can work with Meson's libgit.a output?
Re: [PATCH v2 02/18] make: add -fPIE flag
Quoted 15 lines · Ezekiel Newren
Quoted 10 lines · Junio C Hamano
Quoted 6 lines · Ezekiel Newren
I was trying to get the rust compiler to link against libgit.a. Both Meson and
Makefileproduce libgit.a. No changes were to meson.build were necessary for that to work, but but withMakefileI would get errors like:
relocationR_X86_64_32against `.rodata' can not be used when making a PIE object; recompile with -fPIEQuoted 3 lines
This sounds like a workaround that is somewhat platform and compiler specific limitation, at least to me. Does this need to be conditional and if so on what?
Quoted 5 lines
I don't know, but I have another question to add to yours. Why does Make need -fPIE in order for the Rust compiler to link against libgit.a created by Make, when Meson doesn't seem to specify PIE anywhere and yet the Rust compiler can work with Meson's libgit.a output?
I do not know what the build procedure using meson exactly does to create a library archive. On the Make side, we do not compile for position independence, and don't do anything other than bog standard "ar rcs". Patrick, any hint?
Re: [PATCH v2 02/18] make: add -fPIE flag
Quoted 23 lines · Junio C Hamano
Quoted 15 lines · Ezekiel Newren
Quoted 10 lines · Junio C Hamano
Quoted 6 lines · Ezekiel Newren
I was trying to get the rust compiler to link against libgit.a. Both Meson and
Makefileproduce libgit.a. No changes were to meson.build were necessary for that to work, but but withMakefileI would get errors like:
relocationR_X86_64_32against `.rodata' can not be used when making a PIE object; recompile with -fPIEQuoted 3 lines
This sounds like a workaround that is somewhat platform and compiler specific limitation, at least to me. Does this need to be conditional and if so on what?
Quoted 5 lines
I don't know, but I have another question to add to yours. Why does Make need -fPIE in order for the Rust compiler to link against libgit.a created by Make, when Meson doesn't seem to specify PIE anywhere and yet the Rust compiler can work with Meson's libgit.a output?
Quoted 4 lines
I do not know what the build procedure using meson exactly does to create a library archive. On the Make side, we do not compile for position independence, and don't do anything other than bog standard "ar rcs". Patrick, any hint?
Not too familiar with Rust, but looks like the answer is here [1]. Specificially, this part:
pic - fully relocatable position independent code, machine instructions need to use relative addressing modes. Equivalent to the "uppercase" -fPIC or -fPIE options in other compilers, depending on the produced crate types. This is the default model for majority of supported targets.
Collin
[1] https://doc.rust-lang.org/rustc/codegen-options/index.html#relocation-model
Re: [PATCH v2 02/18] make: add -fPIE flag
Quoted 24 lines · Collin Funk
Quoted 8 lines · Junio C Hamano
Quoted 5 lines · Ezekiel Newren
I don't know, but I have another question to add to yours. Why does Make need -fPIE in order for the Rust compiler to link against libgit.a created by Make, when Meson doesn't seem to specify PIE anywhere and yet the Rust compiler can work with Meson's libgit.a output?
Quoted 4 lines
I do not know what the build procedure using meson exactly does to create a library archive. On the Make side, we do not compile for position independence, and don't do anything other than bog standard "ar rcs". Patrick, any hint?
Not too familiar with Rust, but looks like the answer is here [1]. Specificially, this part:
pic - fully relocatable position independent code, machine instructions need to use relative addressing modes. Equivalent to the "uppercase" -fPIC or -fPIE options in other compilers, depending on the produced crate types. This is the default model for majority of supported targets.
Quoted 3 lines
Collin
[1] https://doc.rust-lang.org/rustc/codegen-options/index.html#relocation-model
Well, thanks for joining the conversation, but that much I think is already shared by those who are involved in this thread.
The background was that Ezekiel did not have to do anything special as far as he knows to get things compiled in a relocatable way with meson based build, and with make based build, (which I know has never used nor required any PIE-ness) he of course needs to add it in a way that is portable across platforms and compilers we care about if we wanted to have PIE objects.
And the question was what, if anything, does meson do specially to do so in a portable way to enable PIE. We'd want to see if it meets our needs (it could be that Ezekiel is getting lucky and meson based build covered the platform+compiler combinations that he happened to be working with) and if so mimick that on the Makefile side.
Re: [PATCH v2 02/18] make: add -fPIE flag
Quoted 5 lines · Junio C Hamano
Quoted 3 lines · Collin Funk
Quoted 1 line · Junio C Hamano
Ezekiel Newren <[email protected]> writes:
[snip]
Quoted 23 lines
Quoted 9 lines
Not too familiar with Rust, but looks like the answer is here [1]. Specificially, this part:
pic - fully relocatable position independent code, machine instructions need to use relative addressing modes. Equivalent to the "uppercase" -fPIC or -fPIE options in other compilers, depending on the produced crate types. This is the default model for majority of supported targets.
Quoted 3 lines
Collin
[1] https://doc.rust-lang.org/rustc/codegen-options/index.html#relocation-model
Well, thanks for joining the conversation, but that much I think is already shared by those who are involved in this thread.
The background was that Ezekiel did not have to do anything special as far as he knows to get things compiled in a relocatable way with meson based build, and with make based build, (which I know has never used nor required any PIE-ness) he of course needs to add it in a way that is portable across platforms and compilers we care about if we wanted to have PIE objects.
Quoted 5 lines
And the question was what, if anything, does meson do specially to do so in a portable way to enable PIE. We'd want to see if it meets our needs (it could be that Ezekiel is getting lucky and meson based build covered the platform+compiler combinations that he happened to be working with) and if so mimick that on the
Makefileside.
Yes, meson defaults the compiler flags to -fPIC (see e.g. near the end of the original cover letter of say [1]). You can change the compiler flags that meson uses (can't remember off-hand how you do that, but it is documented), you can even set -fPIE, or remove -fPIC etc,. ;)
So, I don't know why rust (seems to) require -fPIC/-fPIE to be able to link to libgit.a; maybe we need to add some flags to rustc to _not_ use the equivalent of -fPIC/-fPIE. (I haven't looked, but I will note that the GNU nm program complains about the rust built library!)
[1] https://lore.kernel.org/git/[email protected]/
ATB,
Ramsay Jones
PATCH v2 3/18 make: merge xdiff lib into libgit.a
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
--- Makefile | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-)
Makefile +10 -20
@@ -670,7 +670,6 @@ BUILTIN_OBJS = BUILT_INS = COMPAT_CFLAGS = COMPAT_OBJS = -XDIFF_OBJS = GENERATED_H = EXTRA_CPPFLAGS = FUZZ_OBJS =
@@ -916,7 +915,6 @@ export PYTHON_PATH TEST_SHELL_PATH = $(SHELL_PATH) LIB_FILE = libgit.a -XDIFF_LIB = xdiff/lib.a REFTABLE_LIB = reftable/libreftable.a GENERATED_H += command-list.h
@@ -1207,6 +1205,13 @@ LIB_OBJS += write-or-die.o LIB_OBJS += ws.o LIB_OBJS += wt-status.o LIB_OBJS += xdiff-interface.o +LIB_OBJS += xdiff/xdiffi.o +LIB_OBJS += xdiff/xemit.o +LIB_OBJS += xdiff/xhistogram.o +LIB_OBJS += xdiff/xmerge.o +LIB_OBJS += xdiff/xpatience.o +LIB_OBJS += xdiff/xprepare.o +LIB_OBJS += xdiff/xutils.o BUILTIN_OBJS += builtin/add.o BUILTIN_OBJS += builtin/am.o
@@ -1385,8 +1390,8 @@ CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o -# xdiff and reftable libs may in turn depend on what is in libgit.a -GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE) +# reftable lib may depend on what is in libgit.a +GITLIBS = common-main.o $(LIB_FILE) $(REFTABLE_LIB) $(LIB_FILE) EXTLIBS = GIT_USER_AGENT = git/$(GIT_VERSION)
@@ -2718,16 +2723,6 @@ reconfigure config.mak.autogen: config.status .PHONY: reconfigure # This is a convenience target. endif -XDIFF_OBJS += xdiff/xdiffi.o -XDIFF_OBJS += xdiff/xemit.o -XDIFF_OBJS += xdiff/xhistogram.o -XDIFF_OBJS += xdiff/xmerge.o -XDIFF_OBJS += xdiff/xpatience.o -XDIFF_OBJS += xdiff/xprepare.o -XDIFF_OBJS += xdiff/xutils.o -.PHONY: xdiff-objs -xdiff-objs: $(XDIFF_OBJS) - REFTABLE_OBJS += reftable/basics.o REFTABLE_OBJS += reftable/error.o REFTABLE_OBJS += reftable/block.o
@@ -2762,7 +2757,6 @@ OBJECTS += $(GIT_OBJS) OBJECTS += $(SCALAR_OBJS) OBJECTS += $(PROGRAM_OBJS) OBJECTS += $(TEST_OBJS) -OBJECTS += $(XDIFF_OBJS) OBJECTS += $(FUZZ_OBJS) OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS) OBJECTS += $(UNIT_TEST_OBJS)
@@ -2916,9 +2910,6 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS) $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ -$(XDIFF_LIB): $(XDIFF_OBJS) - $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ - $(REFTABLE_LIB): $(REFTABLE_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
@@ -3760,7 +3751,7 @@ clean: profile-clean coverage-clean cocciclean $(RM) git.rc git.res $(RM) $(OBJECTS) $(RM) headless-git.o - $(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) + $(RM) $(LIB_FILE) $(REFTABLE_LIB) $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) $(RM) $(TEST_PROGRAMS) $(RM) $(FUZZ_PROGRAMS)
@@ -3955,7 +3946,6 @@ endif LIBGIT_PUB_OBJS += contrib/libgit-sys/public_symbol_export.o LIBGIT_PUB_OBJS += libgit.a LIBGIT_PUB_OBJS += reftable/libreftable.a -LIBGIT_PUB_OBJS += xdiff/lib.a LIBGIT_PARTIAL_EXPORT = contrib/libgit-sys/partial_symbol_export.o
Signature · 1 line
gitgitgadget
Re: [PATCH v2 03/18] make: merge xdiff lib into libgit.a
Quoted 4 lines · Ezekiel Newren via GitGitGadget
make: merge xdiff lib into libgit.a
Signed-off-by Ezekiel Newren <[email protected]>---
Please extend the commit message to explain why this change is desirable.
Re: [PATCH v2 03/18] make: merge xdiff lib into libgit.a
Quoted 1 line · Eric Sunshine
Please extend the commit message to explain why this change is desirable.
This commit continues the effort of making the Rust compiler link against libgit.a. Meson already includes xdiff when it builds libgit.a, but Makefile does not. Rather than telling the Rust compiler to also link against xdiff/lib.a, if Makefile was used as opposed to Meson, seemed like a clunkier solution.
I should have asked for a better way to accomplish this as part of my commit message or as a question on the mailing list.
PATCH v2 4/18 make: merge reftable lib into libgit.a
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
--- Makefile | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-)
Makefile +16 -23
@@ -915,7 +915,6 @@ export PYTHON_PATH TEST_SHELL_PATH = $(SHELL_PATH) LIB_FILE = libgit.a -REFTABLE_LIB = reftable/libreftable.a GENERATED_H += command-list.h GENERATED_H += config-list.h
@@ -1125,6 +1124,19 @@ LIB_OBJS += rebase.o LIB_OBJS += ref-filter.o LIB_OBJS += reflog-walk.o LIB_OBJS += reflog.o +LIB_OBJS += reftable/basics.o +LIB_OBJS += reftable/error.o +LIB_OBJS += reftable/block.o +LIB_OBJS += reftable/blocksource.o +LIB_OBJS += reftable/iter.o +LIB_OBJS += reftable/merged.o +LIB_OBJS += reftable/pq.o +LIB_OBJS += reftable/record.o +LIB_OBJS += reftable/stack.o +LIB_OBJS += reftable/system.o +LIB_OBJS += reftable/table.o +LIB_OBJS += reftable/tree.o +LIB_OBJS += reftable/writer.o LIB_OBJS += refs.o LIB_OBJS += refs/debug.o LIB_OBJS += refs/files-backend.o
@@ -1390,8 +1402,7 @@ CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o -# reftable lib may depend on what is in libgit.a -GITLIBS = common-main.o $(LIB_FILE) $(REFTABLE_LIB) $(LIB_FILE) +GITLIBS = common-main.o $(LIB_FILE) EXTLIBS = GIT_USER_AGENT = git/$(GIT_VERSION)
@@ -2723,20 +2734,6 @@ reconfigure config.mak.autogen: config.status .PHONY: reconfigure # This is a convenience target. endif -REFTABLE_OBJS += reftable/basics.o -REFTABLE_OBJS += reftable/error.o -REFTABLE_OBJS += reftable/block.o -REFTABLE_OBJS += reftable/blocksource.o -REFTABLE_OBJS += reftable/iter.o -REFTABLE_OBJS += reftable/merged.o -REFTABLE_OBJS += reftable/pq.o -REFTABLE_OBJS += reftable/record.o -REFTABLE_OBJS += reftable/stack.o -REFTABLE_OBJS += reftable/system.o -REFTABLE_OBJS += reftable/table.o -REFTABLE_OBJS += reftable/tree.o -REFTABLE_OBJS += reftable/writer.o - TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) .PHONY: test-objs
@@ -2758,7 +2755,7 @@ OBJECTS += $(SCALAR_OBJS) OBJECTS += $(PROGRAM_OBJS) OBJECTS += $(TEST_OBJS) OBJECTS += $(FUZZ_OBJS) -OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS) +OBJECTS += $(REFTABLE_TEST_OBJS) OBJECTS += $(UNIT_TEST_OBJS) OBJECTS += $(CLAR_TEST_OBJS) OBJECTS += $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
@@ -2910,9 +2907,6 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS) $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ -$(REFTABLE_LIB): $(REFTABLE_OBJS) - $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ - export DEFAULT_EDITOR DEFAULT_PAGER Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
@@ -3751,7 +3745,7 @@ clean: profile-clean coverage-clean cocciclean $(RM) git.rc git.res $(RM) $(OBJECTS) $(RM) headless-git.o - $(RM) $(LIB_FILE) $(REFTABLE_LIB) + $(RM) $(LIB_FILE) $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) $(RM) $(TEST_PROGRAMS) $(RM) $(FUZZ_PROGRAMS)
@@ -3945,7 +3939,6 @@ endif LIBGIT_PUB_OBJS += contrib/libgit-sys/public_symbol_export.o LIBGIT_PUB_OBJS += libgit.a -LIBGIT_PUB_OBJS += reftable/libreftable.a LIBGIT_PARTIAL_EXPORT = contrib/libgit-sys/partial_symbol_export.o
Signature · 1 line
gitgitgadget
Re: [PATCH v2 04/18] make: merge reftable lib into libgit.a
Quoted 4 lines · Ezekiel Newren via GitGitGadget
make: merge reftable lib into libgit.a
Signed-off-by Ezekiel Newren <[email protected]>---
Same comment as previous patch... please extend the commit message to explain why this change is desirable.
Re: [PATCH v2 04/18] make: merge reftable lib into libgit.a
In reply to Ezekiel Newren via GitGitGadgetQuoted 6 lines · Ezekiel Newren via GitGitGadget
From: Ezekiel Newren <[email protected]>
Signed-off-by Ezekiel Newren <[email protected]>--- Makefile | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-)
Aside from the comment already given about the fact that the proposed log message does not explain any reason why these change are necessary, this step and the previous step are fairly hostile to merging the topic to play well with other topics, especially given that there would be topics in flight that may want to add, remove, or reorder these two existing lists.
I wonder if these could have been arranged like the following instead?
* Drop "REFTABLE_LIB = reftable/libreftable.a" and the target that runs "ar" to mantain that archive.
* Leave "REFTABLE_OBJS += $objects.o" lines alone.
* Add them into LIB_OBJS so that they are included in libgit.a, perhaps a single line like this:
LIB_OBJS += $(REFTABLE_OBJS)
Wouldn't that have worked equally well for the (unstated) purpose of these two patches without incurring unnecessary risk of mismerges?
Similar arrangement for xdiff.
Thanks.
Re: [PATCH v2 04/18] make: merge reftable lib into libgit.a
Quoted 17 lines · Junio C Hamano
Aside from the comment already given about the fact that the proposed log message does not explain any reason why these change are necessary, this step and the previous step are fairly hostile to merging the topic to play well with other topics, especially given that there would be topics in flight that may want to add, remove, or reorder these two existing lists.
I wonder if these could have been arranged like the following instead?
* Drop "
REFTABLE_LIB= reftable/libreftable.a" and the target that runs "ar" to mantain that archive.* Leave "
REFTABLE_OBJS+= $objects.o" lines alone.* Add them into
LIB_OBJSso that they are included in libgit.a, perhaps a single line like this:
Quoted 6 lines
LIB_OBJS += $(REFTABLE_OBJS)Wouldn't that have worked equally well for the (unstated) purpose of these two patches without incurring unnecessary risk of mismerges?
Similar arrangement for xdiff.
Like the previous two commits; This one continues the effort to get the Rust compiler to link against libgit.a. Meson already includes the reftable in its libgit.a, but Makefile does not.
The reason why I was trying to get the Rust compiler to link against libgit.a is because I wanted to get Rusts unit testing to work. If the Rust code calls a C function from Git then 'cargo test' needs to know about it.
However I think I'll drop these 3 commits since 'cargo test' doesn't need to be part of the introduction of Rust. It would be nice for make to be able to run Rust unit tests at some point though.
Re: [PATCH v2 04/18] make: merge reftable lib into libgit.a
Quoted 20 lines · Ezekiel Newren
Quoted 19 lines · Junio C Hamano
Aside from the comment already given about the fact that the proposed log message does not explain any reason why these change are necessary, this step and the previous step are fairly hostile to merging the topic to play well with other topics, especially given that there would be topics in flight that may want to add, remove, or reorder these two existing lists.
I wonder if these could have been arranged like the following instead?
* Drop "
REFTABLE_LIB= reftable/libreftable.a" and the target that runs "ar" to mantain that archive.* Leave "
REFTABLE_OBJS+= $objects.o" lines alone.* Add them into
LIB_OBJSso that they are included in libgit.a, perhaps a single line like this:LIB_OBJS += $(REFTABLE_OBJS)
Quoted 8 lines
Quoted 4 lines
Wouldn't that have worked equally well for the (unstated) purpose of these two patches without incurring unnecessary risk of mismerges?
Similar arrangement for xdiff.
Like the previous two commits; This one continues the effort to get
...
The reason why ...
Neither answers my main question, though.
Instead of rolling everything into LIB_OBJS directly, wouldn't it have been much easier to work with if reftable-related ones are left in REFTABLE_OBJS and then RERFTABLE_OBJS gets added to LIB_OBJS? Wouldn't it have been less prone to mismerges to do it that way?
Quoted 3 lines
However I think I'll drop these 3 commits since 'cargo test' doesn't need to be part of the introduction of Rust. It would be nice for make to be able to run Rust unit tests at some point though.
As we can always extend things more, getting something close to the minimally viable set with some tests for sanity checking would be a good first goal. If you pare down way too much, however, we may end up to be pretty close to what Patrick sent out originally with the varint conversion, so let's make sure we do not drop below the minimum that still demonstrates that we have Rust integration that is viable going forward.
Thanks.
Re: [PATCH v2 04/18] make: merge reftable lib into libgit.a
Quoted 4 lines · Junio C Hamano
Instead of rolling everything into
LIB_OBJSdirectly, wouldn't it have been much easier to work with if reftable-related ones are left inREFTABLE_OBJSand thenRERFTABLE_OBJSgets added toLIB_OBJS? Wouldn't it have been less prone to mismerges to do it that way?
I didn't do it that way because I didn't think of that. I prefer your way because it's much cleaner.
Quoted 7 lines
As we can always extend things more, getting something close to the minimally viable set with some tests for sanity checking would be a good first goal. If you pare down way too much, however, we may end up to be pretty close to what Patrick sent out originally with the varint conversion, so let's make sure we do not drop below the minimum that still demonstrates that we have Rust integration that is viable going forward.
I'm torn between A and B from [1]:
I'm thinking of choosing A because my approach and Patrick's approach are incompatible. In order to use multiple crates and ensure that Rust is built and tested the same way with Make and Meson I'd have to rip out lots of things from Patrick's patch series.
But maybe I should go with B because there's a lot of prep work that should be done with Git before I can start doing what I'd like to do in Rust. So let Patrick's stuff merge while I work on cleaning up xdiff and updating Makefile's libgit.a build process and then deal with ugly merging later.
I can't decide between the two.
[1] https://lore.kernel.org/git/CABPp-BHJUkSERQon6xx=sHrhN7i=6ekv+Hz1+P+2mh0=Xw15Mg@mail.gmail.com/
PATCH v2 5/18 doc: add a policy for using Rust
In reply to Ezekiel Newren via GitGitGadgetFrom: "brian m. carlson" <[email protected]>
Git has historically been written primarily in C, with some shell and Perl. However, C is not memory safe, which makes it more likely that security vulnerabilities or other bugs will be introduced, and it is also more verbose and less ergonomic than other, more modern languages.
One of the most common modern compiled languages which is easily interoperable with C is Rust. It is popular (the most admired language on the 2024 Stack Overflow Developer Survey), efficient, portable, and robust.
Introduce a document laying out the incremental introduction of Rust to Git and provide a detailed rationale for doing so, including the points above. Propose a design for this approach that addresses the needs of downstreams and distributors, as well as contributors.
Since we don't want to carry both a C and Rust version of code and want to be able to add new features only in Rust, mention that Rust is a required part of our platform support policy.
It should be noted that a recent discussion at the Berlin Git Merge Contributor Summit found widespread support for the addition of Rust to Git. While of course not all contributors were represented, the proposal appeared to have the support of a majority of active contributors.
[en: Added some comments about types, and changed the recommondations
about cbindgen, bindgen, rustix, libc.]
--- Documentation/Makefile | 1 + Documentation/technical/platform-support.adoc | 2 + Documentation/technical/rust-support.adoc | 142 ++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 Documentation/technical/rust-support.adoc
Documentation/Makefile +1 -0
@@ -127,6 +127,7 @@ TECH_DOCS += technical/parallel-checkout TECH_DOCS += technical/partial-clone TECH_DOCS += technical/platform-support TECH_DOCS += technical/racy-git +TECH_DOCS += technical/rust-support TECH_DOCS += technical/reftable TECH_DOCS += technical/scalar TECH_DOCS += technical/send-pack-pipeline
Documentation/technical/platform-support.adoc +2 -0
@@ -33,6 +33,8 @@ meet the following minimum requirements: * Has active security support (taking security releases of dependencies, etc) +* Supports Rust and the toolchain version specified in link:rust-support.adoc[]. + These requirements are a starting point, and not sufficient on their own for the Git community to be enthusiastic about supporting your platform. Maintainers of platforms which do meet these requirements can follow the steps below to make it
Documentation/technical/rust-support.adoc new file +142 -0
142 lines not on this page · raw message
Signature · 1 line
gitgitgadget
PATCH v2 6/18 BreakingChanges: announce Rust becoming mandatory
In reply to Ezekiel Newren via GitGitGadgetFrom: Patrick Steinhardt <[email protected]>
Over the last couple of years the appetite for bringing Rust into the codebase has grown significantly across the developer base. Introducing Rust is a major change though and has ramifications for the whole ecosystem:
- Some platforms have a Rust toolchain available, but have not yet integrated it into their build infrastructure.
- Some platforms don't have any support for Rust at all.
- Some platforms may have to figure out how to fit Rust into their bootstrapping sequence.
Due to this, and given that Git is a critical piece of infrastructure for the whole industry, we cannot just introduce such a heavyweight dependency without doing our due diligence.
Instead, preceding commits have introduced a test balloon into our build infrastructure that convert one tiny subsystem to use Rust. For now, using Rust to build that subsystem is entirely optional -- if no Rust support is available, we continue to use the C implementation. This test balloon has the intention to give distributions time and let them ease into our adoption of Rust.
Having multiple implementations of the same subsystem is not sustainable though, and the plan is to eventually be able to use Rust freely all across our codebase. As such, there is the intent to make Rust become a mandatory part of our build process.
Add an announcement to our breaking changes that Rust will become mandatory in Git 3.0. A (very careful and non-binding) estimate might be that this major release might be released in the second half of next year, which should give distributors enough time to prepare for the change.
--- Documentation/BreakingChanges.adoc | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
Documentation/BreakingChanges.adoc +35 -0
@@ -165,6 +165,41 @@ A prerequisite for this change is that the ecosystem is ready to support the "reftable" format. Most importantly, alternative implementations of Git like JGit, libgit2 and Gitoxide need to support it. +* Git will require Rust as a mandatory part of the build process. While Git + already started to adopt Rust in Git 2.49, all parts written in Rust are + optional for the time being. This includes: ++ + ** Subsystems that have an alternative implementation in Rust to test + interoperability between our C and Rust codebase. + ** Newly written features that are not mission critical for a fully functional + Git client. ++ +These changes are meant as test balloons to allow distributors of Git to prepare +for Rust becoming a mandatory part of the build process. There will be multiple +milestones for the introduction of Rust: ++ +-- +1. In Git 2.52, both build systems will default-enable support for Rust. + Consequently, builds will break by default if Rust is not available on the + build host. The use of Rust can still be explicitly disabled via build + flags. +2. In Git 3.0, the build options will be removed and support for Rust is + mandatory. +-- ++ +Disable building with Rust: +Meson: `meson configure -Dwith_rust=false`. +Makefile: `make WITH_RUST=false`, ++ +The Git project will declare the last version before Git 3.0 to be a long-term +support release. This long-term release will receive important bug fixes for at +least four release cycles and security fixes for six release cycles. The Git +project will hand over maintainership of the long-term release to distributors +in case they need to extend the life of that long-term release even further. In +that case, the backporting process will be handled by these distributors, but +the backported patches will be reviewed on the mailing list and pulled in by the +Git maintainer. + === Removals * Support for grafting commits has long been superseded by git-replace(1).
Signature · 1 line
gitgitgadget
PATCH v2 7/18 build: introduce rust
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Upcoming patches will simplify xdiff, while also porting parts of it to Rust. In preparation, add some stubs and setup the Rust build. For now, it is easier to let cargo build rust and have make or meson merely link against the static library that cargo builds. In line with ongoing libification efforts, use multiple crates to allow more modularity on the Rust side. The xdiff and ivec crates are the focal point for this series.
cbindgen will be used to generate header files for each Rust crate for C interoperability.
--- .gitignore | 3 ++ Makefile | 81 +++++++++++++++++++++++++++++++++++++++-------- build_rust.sh | 60 +++++++++++++++++++++++++++++++++++ meson.build | 72 ++++++++++++++++++++++++++++++++++++----- meson_options.txt | 2 ++ rust/Cargo.toml | 3 ++ 6 files changed, 200 insertions(+), 21 deletions(-) create mode 100755 build_rust.sh create mode 100644 rust/Cargo.toml
.gitignore +3 -0
@@ -254,3 +254,6 @@ Release/ /contrib/buildsystems/out /contrib/libgit-rs/target /contrib/libgit-sys/target +.idea/ +/rust/target/ +/rust/Cargo.lock
Makefile +68 -13
162 lines not on this page · raw message
build_rust.sh new file +60 -0
60 lines not on this page · raw message
meson.build +64 -8
96 lines not on this page · raw message
meson_options.txt +2 -0
@@ -69,6 +69,8 @@ option('zlib_backend', type: 'combo', choices: ['auto', 'zlib', 'zlib-ng'], valu description: 'The backend used for compressing objects and other data.') # Build tweaks. +option('with_rust', type: 'boolean', value: true, + description: 'Enable building with Rust, true by default.') option('breaking_changes', type: 'boolean', value: false, description: 'Enable upcoming breaking changes.') option('macos_use_homebrew_gettext', type: 'boolean', value: true,
rust/Cargo.toml new file +3 -0
@@ -0,0 +1,3 @@ +[workspace] +members = [] +resolver = "2"
Signature · 1 line
gitgitgadget
Re: [PATCH v2 07/18] build: introduce rust
Quoted 15 lines · Ezekiel Newren via GitGitGadget
Upcoming patches will simplify xdiff, while also porting parts of it to Rust. In preparation, add some stubs and setup the Rust build. For now, it is easier to let cargo build rust and have make or meson merely link against the static library that cargo builds. In line with ongoing libification efforts, use multiple crates to allow more modularity on the Rust side. The xdiff and ivec crates are the focal point for this series.
cbindgen will be used to generate header files for each Rust crate for C interoperability.
Signed-off-by Ezekiel Newren <[email protected]>---
.gitignore Release/ · line 259
Quoted 6 lines
.gitignore +3
-0@@ -254,3 +254,6 @@ Release/ /contrib/buildsystems/out /contrib/libgit-rs/target /contrib/libgit-sys/target +.idea/ +/rust/target/ +/rust/Cargo.lock
Is ".idea" directory detritus from your chosen editor? If so, it probably ought not be added to this list since we don't otherwise ignore detritus from foreign tools such as that.
Makefile TEST_SHELL_PATH = $(SHELL_PATH) · line 925
Quoted 4 lines
Makefile +2
-0@@ -916,6 +924,51 @@ TEST_SHELL_PATH = $(SHELL_PATH) +RUST_CRATES := +.PHONY: compile_rust rustclean
This is an extremely tiny nit, but multi-word target names in the Git Makefile are almost universally spelled with a hyphen rather than an underscore, so "compile-rust" would be more consistent and appropriate.
Makefile TEST_SHELL_PATH = $(SHELL_PATH) · line 956
Quoted 2 lines
Makefile +2
-0+$(GIT_BUILD_DIR)/lib%.a: + ./build_rust.sh $(GIT_BUILD_DIR) $(RUST_BUILD_MODE) $*
I wonder if this should follow the convention of most (but not quite all) other local shell script invocations in the Makefile of referencing SHELL_PATH; for instance:
$(QUIET_GEN)$(SHELL_PATH) ./build_rust.sh ...etc...
with or without the $(QUIET_GEN) bit.
build_rust.sh line 4
Quoted 6 lines
build_rust.sh +4
-0@@ -0,0 +1,60 @@ +if [ "$dir_git_root" = "" ]; then + echo "did not specify the directory for the root of git" + exit 1 +fi
Let's follow project style conventions for shell scripts:
if test "$dir_git_root" = ""
then
...
fior even:
if test -z "$dir_git_root"
then
...
fi
Same comment applies to the rest of the script.
Also, should the above error message be sent to stderr rather than stdout? (Genuine question since I'm not sure if other scripts are necessarily consistent in that regard.)
build_rust.sh line 37
Quoted 10 lines
build_rust.sh +10
-0+if [ "$rust_build_profile" = "release" ]; then + rust_args="--release" + export RUSTFLAGS='' +elif [ "$rust_build_profile" = "debug" ]; then + rust_args="" + export RUSTFLAGS='-C debuginfo=2 -C opt-level=1 -C force-frame-pointers=yes' +else + echo "illegal rust_build_profile value $rust_build_profile" + exit 1 +fi
For maximum portability, we don't use the:
export FOO=bar
idiom in this project. Instead, do this:
FOO=bar
export FOO
The same comment applies to the remainder of the patch, as well.
Also, the empty-string assignments to RUSTFLAGS and rust_args above inconsistently use a mix of single and double quotes. However, we also usually just assign nothingness in such cases rather than an empty string:
RUSTFLAGS=
export RUSTFLAGS
...
rust_args=build_rust.sh line 43
Quoted 4 lines
build_rust.sh +4
-0+if rustup show active-toolchain | grep windows-msvc; then + libfile="${crate}.lib" + PATH="$(echo $PATH | tr ':' '\n' | grep -Ev "^(/mingw64/bin|/usr/bin)$" | paste -sd: -):/mingw64/bin:/usr/bin" +fi
Please add either an in-code comment or a sentence/paragraph to the commit message explaining why this PATH munging is needed.
build_rust.sh line 48
Quoted 1 line
build_rust.sh +1
-0+cd $dir_rust && cargo clean && pwd && USE_LINKING="false" cargo build -p $crate $rust_args; cd $dir_git_root
When formatted like this, it is very easy to overlook the fact that the final cd is (correctly) not &&-chained with the preceding commands. Reformatting it like this would help:
cd $dir_rust &&
cargo clean &&
pwd &&
USE_LINKING="false" cargo build -p $crate $rust_args
cd $dir_git_rootAlternatively, use a subshell and drop the final cd:
(
cd $dir_rust &&
cargo clean &&
pwd &&
USE_LINKING="false" cargo build -p $crate $rust_args
)By the way, is the pwd command needed? What is its purpose?
build_rust.sh line 58
Quoted 1 line
build_rust.sh +1
-0+rm $dst 2>/dev/null
I think we typically use rm -f without redirect to /dev/null to do the "right thing".
Quoted 2 lines
build_rust.sh +2
-0+echo mv $src $dst +mv $src $dst
Re: [PATCH v2 07/18] build: introduce rust
Quoted 4 lines · Eric Sunshine
Quoted 4 lines
.gitignore +0
-0@@ -254,3 +254,6 @@ Release/ /contrib/buildsystems/out /contrib/libgit-rs/target
Quoted 8 lines
.gitignore Release/ · line 259
Quoted 4 lines
.gitignore +3
-0/contrib/libgit-sys/target +.idea/ +/rust/target/ +/rust/Cargo.lockIs ".idea" directory detritus from your chosen editor? If so, it probably ought not be added to this list since we don't otherwise ignore detritus from foreign tools such as that.
I knew that the above was our official stance but somehow thought that we loosened at some point to add common ones like *~ and *.sw[op] to make life simpler for majority of developers. But I was wrong. We do not even have *~, which means we haven't officially loosened.
But there are oddballs that violate this policy like ".cache" introduced by a5c01603 (gitignore: ignore clangd .cache directory, 2023-08-04). Three are many other that are *not* our droppings, between /.vscode/ to /contrib/buildsystems/out in .gitignore file.
/.vscode/
/tags
/TAGS
/cscope*
/compile_commands.json
/.cache/
*.hcc
*.obj
*.lib
*.sln
*.sp
*.suo
*.ncb
*.vcproj
*.user
*.idb
*.pdb
*.ilk
*.iobj
*.ipdb
*.dll
.vs/
Debug/
Release/
/UpgradeLog*.htm
/git.VC.VC.opendb
/git.VC.db
*.dSYMSome (like TAGS and *.hcc) are our droppings (in other words, what "make" with some build targets may produce), but most of these are tool specific and according to our original official stance, they should never have been added, but there they are.
I actually do not mind having common ones to the project .gitignore as long as it does not get bloated too much with droppings from esoteric tools that majority of us have never heard of. It seems that we have been punishing needlessly Emacs and vim users while being sloppy about others' droppings. A #leftoverbit may be to have a brief discussion to gain consensus and add a few common ones and/or remove too esoteric ones? I dunno.
Quoted 10 lines
Quoted 2 lines
+$(GIT_BUILD_DIR)/lib%.a:
+ ./build_rust.sh $(GIT_BUILD_DIR) $(RUST_BUILD_MODE) $*I wonder if this should follow the convention of most (but not quite all) other local shell script invocations in the
Makefileof referencingSHELL_PATH; for instance:$(QUIET_GEN)$(SHELL_PATH) ./build_rust.sh ...etc...with or without the $(QUIET_GEN) bit.
Good suggestion. This reminds me of my favorite gripe, which is that "make clean" makes no effort to be quiet by default; perhaps leaving a #leftover bit marker here would help?
Thanks.
Re: [PATCH v2 07/18] build: introduce rust
Quoted 47 lines · Junio C Hamano
Quoted 5 lines · Eric Sunshine
Quoted 1 line
+.idea/
Is ".idea" directory detritus from your chosen editor? If so, it probably ought not be added to this list since we don't otherwise ignore detritus from foreign tools such as that.
I knew that the above was our official stance but somehow thought that we loosened at some point to add common ones like *~ and *.sw[op] to make life simpler for majority of developers. But I was wrong. We do not even have *~, which means we haven't officially loosened.
But there are oddballs that violate this policy like ".cache" introduced by
a5c01603(gitignore: ignore clangd .cache directory, 2023-08-04). Three are many other that are *not* our droppings, between /.vscode/ to /contrib/buildsystems/out in .gitignore file./.vscode/ /tags /TAGS /cscope* /compile_commands.json /.cache/ *.hcc *.obj *.lib *.sln *.sp *.suo *.ncb *.vcproj *.user *.idb *.pdb *.ilk *.iobj *.ipdb *.dll .vs/ Debug/ Release/ /UpgradeLog*.htm /git.VC.VC.opendb /git.VC.db *.dSYM
Quoted 4 lines
Some (like TAGS and *.hcc) are our droppings (in other words, what "make" with some build targets may produce), but most of these are tool specific and according to our original official stance, they should never have been added, but there they are.
It's been a while since I had to build code with Visual Studio (the proprietary Microsoft product, not the open-source VScode), but if I recall correctly, all the entries from ".obj" through "Release/" are build detritus from compiling with that tool. Assuming we still support building Git with Visual Studio (which I believe is the case), then those entries all fall within the same categorization as "our droppings" similar to the make case, so having these in ".gitignore" is probably in line with the project's official stance.
Others, such as "/.vscode/", on the other hand, fall into the other category of "someone's favorite editor or handy tool", which has thus far been frowned upon.
Quoted 7 lines
I actually do not mind having common ones to the project .gitignore as long as it does not get bloated too much with droppings from esoteric tools that majority of us have never heard of. It seems that we have been punishing needlessly Emacs and vim users while being sloppy about others' droppings. A #leftoverbit may be to have a brief discussion to gain consensus and add a few common ones and/or remove too esoteric ones? I dunno.
I don't have a strong opinion aside from avoiding bloat; I've seen (and inherited at $DAYJOBS) far too many projects which grab some overly bloated .gitignore template from somewhere in which most of the entries are meaningless for the project at hand, yet which is used as-is rather than pruning out the unneeded entries (typically >95% of them). As with dead code, those unneeded .gitignore entries tend to be a source of potential confusion, which is rarely or never the case with a well-curated .gitignore (or with well-curated code).
That said, I also probably do not mind having the common ones in Git's .gitignore. A few which come to mind include:
* editor-specific droppings (Emacs, vi / vim, VScode)
* .DS_Store files which macOS's Finder drops into *every* directory it visits, thus which litter the filesystem
Re: [PATCH v2 07/18] build: introduce rust
In reply to Eric SunshineQuoted 3 lines · Eric Sunshine
Is ".idea" directory detritus from your chosen editor? If so, it probably ought not be added to this list since we don't otherwise ignore detritus from foreign tools such as that.
Yes. I use the Jetbrains IDE's CLion and RustRover for C and Rust respectively. Jetbrains has an IDE for MANY languages and all of them use .idea/ as the folder for IDE specific configuration. I'm fine with keeping it out of .gitignore, but I wanted to know what the community thought. Which I should have made it more clear that this patch series was more of an RFC than proposed code to be merged.
Quoted 75 lines
Makefile TEST_SHELL_PATH = $(SHELL_PATH) · line 925
Quoted 4 lines
Makefile +2
-0@@ -916,6 +924,51 @@ TEST_SHELL_PATH = $(SHELL_PATH) +RUST_CRATES := +.PHONY: compile_rust rustcleanThis is an extremely tiny nit, but multi-word target names in the Git
Makefileare almost universally spelled with a hyphen rather than an underscore, so "compile-rust" would be more consistent and appropriate.Makefile TEST_SHELL_PATH = $(SHELL_PATH) · line 956
Quoted 2 lines
Makefile +2
-0+$(GIT_BUILD_DIR)/lib%.a: + ./build_rust.sh $(GIT_BUILD_DIR) $(RUST_BUILD_MODE) $*I wonder if this should follow the convention of most (but not quite all) other local shell script invocations in the
Makefileof referencingSHELL_PATH; for instance:$(QUIET_GEN)$(SHELL_PATH) ./build_rust.sh ...etc...with or without the $(QUIET_GEN) bit.
build_rust.sh line 4
Quoted 6 lines
build_rust.sh +4
-0@@ -0,0 +1,60 @@ +if [ "$dir_git_root" = "" ]; then + echo "did not specify the directory for the root of git" + exit 1 +fiLet's follow project style conventions for shell scripts:
if test "$dir_git_root" = "" then ... fior even:
if test -z "$dir_git_root"
then
...
fiSame comment applies to the rest of the script.
Also, should the above error message be sent to stderr rather than stdout? (Genuine question since I'm not sure if other scripts are necessarily consistent in that regard.)
build_rust.sh line 37
Quoted 10 lines
build_rust.sh +10
-0+if [ "$rust_build_profile" = "release" ]; then + rust_args="--release" + export RUSTFLAGS='' +elif [ "$rust_build_profile" = "debug" ]; then + rust_args="" + export RUSTFLAGS='-C debuginfo=2 -C opt-level=1 -C force-frame-pointers=yes' +else + echo "illegal rust_build_profile value $rust_build_profile" + exit 1 +fiFor maximum portability, we don't use the:
export FOO=bar
idiom in this project. Instead, do this:
FOO=bar
export FOOThe same comment applies to the remainder of the patch, as well.
Also, the empty-string assignments to RUSTFLAGS and
rust_argsabove inconsistently use a mix of single and double quotes. However, we also usually just assign nothingness in such cases rather than an empty string:
Quoted 4 lines
RUSTFLAGS=
export RUSTFLAGS
...
rust_args=I'll try to keep these in mind for the future.
Quoted 7 lines
build_rust.sh line 43
Quoted 4 lines
build_rust.sh +4
-0+if rustup show active-toolchain | grep windows-msvc; then + libfile="${crate}.lib" + PATH="$(echo $PATH | tr ':' '\n' | grep -Ev "^(/mingw64/bin|/usr/bin)$" | paste -sd: -):/mingw64/bin:/usr/bin" +fiPlease add either an in-code comment or a sentence/paragraph to the commit message explaining why this PATH munging is needed.
I will amend the commit with something like:
On windows when building with msvc using shell scripts it looks for link in /mingw64/bin|/usr/bin when it actually needs to look somewhere else for the msvc linker program. Since removing these from PATH would break everything else in the shell; move them to be at the end of PATH.
Quoted 23 lines
build_rust.sh line 48
Quoted 1 line
build_rust.sh +1
-0+cd $dir_rust && cargo clean && pwd && USE_LINKING="false" cargo build -p $crate $rust_args; cd $dir_git_rootWhen formatted like this, it is very easy to overlook the fact that the final
cdis (correctly) not &&-chained with the preceding commands. Reformatting it like this would help:cd $dir_rust && cargo clean && pwd && USE_LINKING="false" cargo build -p $crate $rust_args cd $dir_git_rootAlternatively, use a subshell and drop the final
cd:( cd $dir_rust && cargo clean && pwd && USE_LINKING="false" cargo build -p $crate $rust_args )By the way, is the
pwdcommand needed? What is its purpose?
Quoted 7 lines
build_rust.sh line 58
Quoted 1 line
build_rust.sh +1
-0+rm $dst 2>/dev/nullI think we typically use
rm -fwithout redirect to/dev/nullto do the "right thing".build_rust.sh line 60
Quoted 2 lines
build_rust.sh +2
-0+echo mv $src $dst +mv $src $dst
pwd was for debugging and I forgot to take it out. I'll clean up my script.
Re: [PATCH v2 07/18] build: introduce rust
Quoted 10 lines · Ezekiel Newren
Quoted 3 lines · Eric Sunshine
Is ".idea" directory detritus from your chosen editor? If so, it probably ought not be added to this list since we don't otherwise ignore detritus from foreign tools such as that.
Yes. I use the Jetbrains IDE's CLion and RustRover for C and Rust respectively. Jetbrains has an IDE for MANY languages and all of them use .idea/ as the folder for IDE specific configuration. I'm fine with keeping it out of .gitignore, but I wanted to know what the community thought. [...]
There is a bit of discussion about this later in this same email thread. If the project does ultimately decide to accept these .gitignore entries, adding them would be done via a patch or series of patches specifically aimed at that goal. Hence, I'd recommend omitting the ".idea" entry from this particular patch series.
Quoted 8 lines
Quoted 7 lines
build_rust.sh line 43
Quoted 4 lines
build_rust.sh new file +4
-0+if rustup show active-toolchain | grep windows-msvc; then + libfile="${crate}.lib" + PATH="$(echo $PATH | tr ':' '\n' | grep -Ev "^(/mingw64/bin|/usr/bin)$" | paste -sd: -):/mingw64/bin:/usr/bin" +fiPlease add either an in-code comment or a sentence/paragraph to the commit message explaining why this PATH munging is needed.
Quoted 6 lines
I will amend the commit with something like:
On windows when building with msvc using shell scripts it looks for link in /mingw64/bin|/usr/bin when it actually needs to look somewhere else for the msvc linker program. Since removing these from PATH would break everything else in the shell; move them to be at the end of PATH.
I had to read and reread this several times but I think I get what it is saying. To paraphrase your explanation...
When building with cargo (I presume), and it comes time to link the program, the build process is looking for the Microsoft linker named LINK.exe but, due to PATH order, is instead finding the Unix command link (which is a specialized invocation of the more common ln command). As such, the build process incorrectly invokes the Unix link rather than the Microsoft LINK.exe and fails. To work around this problem, you move the standard Unix command-containing paths to the end of PATH so that the Microsoft LINK.exe is found first.
...does that sound correct?
Re: [PATCH v2 07/18] build: introduce rust
Quoted 8 lines · Eric Sunshine
When building with
cargo(I presume), and it comes time to link the program, the build process is looking for the Microsoft linker named LINK.exe but, due to PATH order, is instead finding the Unix commandlink(which is a specialized invocation of the more commonlncommand). As such, the build process incorrectly invokes the Unixlinkrather than the Microsoft LINK.exe and fails. To work around this problem, you move the standard Unix command-containing paths to the end of PATH so that the Microsoft LINK.exe is found first.
Your understanding is correct.
PATCH v2 8/18 help: report on whether or not Rust is enabled
In reply to Ezekiel Newren via GitGitGadgetFrom: Patrick Steinhardt <[email protected]>
We're about to introduce support for Rust into the core of Git, where some (trivial) subsystems are converted to Rust. These subsystems will also retain a C implementation though as Rust is not yet mandatory. Consequently, it now becomes possible for a Git version to have bugs that are specific to whether or not it is built with Rust support overall.
Expose information about whether or not Git was built with Rust via our build info. This means that both git version --build-options, but also git bugreport will now expose that bit of information. Hopefully, this should make it easier for us to discover any Rust-specific issues.
--- help.c | 6 ++++++ 1 file changed, 6 insertions(+)
help.c +6 -0
@@ -791,6 +791,12 @@ void get_version_info(struct strbuf *buf, int show_build_options)strbuf_addf (buf,"shell-path: %s\n" ,SHELL_PATH );/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */ +#if definedWITH_RUST +strbuf_addstr (buf,"rust: enabled\n" ); +#else +strbuf_addstr (buf,"rust: disabled\n" ); +#endif +if (fsmonitor_ipc__is_supported ())strbuf_addstr (buf,"feature: fsmonitor--daemon\n" );#if definedLIBCURL_VERSION
Signature · 1 line
gitgitgadget
PATCH v2 9/18 github workflows: install rust
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Prefer using actions-rs/toolchain@v1 where possible to install rustup, but for docker targets use a script to install rustup. Consolidate the Rust toolchain definitions in main.yaml. Use install-rust-toolchain.sh to ensure the correct toolchain is used. Five overrides are used in main.yaml:
* On Windows: Rust didn't resolve the bcrypt library on Windows correctly until version 1.78.0. Also since rustup mis-identifies the Rust toolchain, the Rust target triple must be set to x86_64-pc-windows-gnu for make (win build), and x86_64-pc-windows-msvc for meson (win+Meson build).
* MSVC builds: Rearrange PATH to look in /mingw64/bin and /usr/bin last.
* On musl: libc differences, such as ftruncate64 vs ftruncate, were not accounted for until Rust version 1.72.0. No older version of Rust will work on musl for our needs.
* In a 32-bit docker container running on a 64-bit host, we need to override the Rust target triple. This is because rustup asks the kernel for the bitness of the system and it says 64, even though the container is 32-bit. This also allows us to remove the BITNESS environment variable in ci/lib.sh.
The logic for selecting library names was initially provided in a patch from Johannes, but was reworked and squashed into this commit.
--- .github/workflows/main.yml | 62 +++++++++++++++++++++++++++++++++++- ci/install-dependencies.sh | 14 ++++---- ci/install-rust-toolchain.sh | 30 +++++++++++++++++ ci/install-rustup.sh | 25 +++++++++++++++ ci/lib.sh | 1 + ci/make-test-artifacts.sh | 9 ++++++ ci/run-build-and-tests.sh | 13 ++++++++ 7 files changed, 146 insertions(+), 8 deletions(-) create mode 100755 ci/install-rust-toolchain.sh create mode 100755 ci/install-rustup.sh
.github/workflows/main.yml +61 -1
@@ -26,6 +26,13 @@ jobs: outputs: enabled: ${{ steps.check-ref.outputs.enabled }}${{ steps.skip-if-redundant.outputs.enabled }} skip_concurrent: ${{ steps.check-ref.outputs.skip_concurrent }} + rust_version_minimum: 1.63.0 + rust_version_windows: 1.78.0 + rust_version_musl: 1.72.0 + ## the rust target is inferred by rustup unless specified + rust_target_windows_make: x86_64-pc-windows-gnu + rust_target_windows_meson: x86_64-pc-windows-msvc + rust_target_32bit_linux: i686-unknown-linux-gnu steps: - name: try to clone ci-config branch run: |
@@ -108,12 +115,28 @@ jobs: needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' runs-on: windows-latest + env: + CARGO_HOME: "/c/Users/runneradmin/.cargo" concurrency: group: windows-build-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v4 - uses: git-for-windows/setup-git-for-windows-sdk@v1 + with: + flavor: full + - name: Install rustup via github actions + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: false + - name: Install Rust toolchain + shell: bash + env: + RUST_VERSION: ${{ needs.ci-config.outputs.rust_version_windows }} + RUST_TARGET: ${{ needs.ci-config.outputs.rust_target_windows_make }} + run: ci/install-rust-toolchain.sh - name: build shell: bash env:
@@ -254,12 +277,26 @@ jobs: needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' runs-on: windows-latest + env: + CARGO_HOME: "/c/Users/runneradmin/.cargo" concurrency: group: windows-meson-build-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 + - name: Install rustup via github actions + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: false + - name: Install Rust toolchain + shell: bash + env: + RUST_VERSION: ${{ needs.ci-config.outputs.rust_version_windows }} + RUST_TARGET: ${{ needs.ci-config.outputs.rust_target_windows_meson }} + run: ci/install-rust-toolchain.sh - name: Set up dependencies shell: pwsh run: pip install meson ninja
@@ -329,11 +366,24 @@ jobs: jobname: ${{matrix.vector.jobname}} CI_JOB_IMAGE: ${{matrix.vector.pool}} TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t + CARGO_HOME: "/Users/runner/.cargo" runs-on: ${{matrix.vector.pool}} steps: - uses: actions/checkout@v4 - run: ci/install-dependencies.sh - - run: ci/run-build-and-tests.sh + - name: Install rustup via github actions + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: false + - name: Install Rust toolchain + shell: bash + env: + RUST_VERSION: ${{ needs.ci-config.outputs.rust_version_minimum }} + run: ci/install-rust-toolchain.sh + - name: Run build and tests + run: ci/run-build-and-tests.sh - name: print test failures if: failure() && env.FAILED_TEST_ARTIFACTS != '' run: ci/print-test-failures.sh
@@ -393,9 +443,11 @@ jobs: cc: gcc - jobname: linux-musl-meson image: alpine:latest + rust_version_override: ${{ needs.ci-config.outputs.rust_version_musl }} # Supported until 2025-04-02. - jobname: linux32 image: i386/ubuntu:focal + rust_target_override: ${{ needs.ci-config.outputs.rust_target_32bit_linux }} - jobname: pedantic image: fedora:latest # A RHEL 8 compatible distro. Supported until 2029-05-31.
@@ -409,6 +461,7 @@ jobs: CC: ${{matrix.vector.cc}} CI_JOB_IMAGE: ${{matrix.vector.image}} CUSTOM_PATH: /custom + CARGO_HOME: /home/builder/.cargo runs-on: ubuntu-latest container: ${{matrix.vector.image}} steps:
@@ -433,6 +486,13 @@ jobs: - run: ci/install-dependencies.sh - run: useradd builder --create-home - run: chown -R builder . + - name: Install rustup via script + run: sudo --preserve-env --set-home --user=builder ci/install-rustup.sh + - name: Install Rust toolchain + env: + RUST_VERSION: ${{ matrix.vector.rust_version_override || needs.ci-config.outputs.rust_version_minimum }} + RUST_TARGET: ${{ matrix.vector.rust_target_override || '' }} + run: sudo --preserve-env --set-home --user=builder ci/install-rust-toolchain.sh - run: sudo --preserve-env --set-home --user=builder ci/run-build-and-tests.sh - name: print test failures if: failure() && env.FAILED_TEST_ARTIFACTS != ''
ci/install-dependencies.sh +7 -7
@@ -24,14 +24,14 @@ fi case "$distro" in alpine-*) - apk add --update shadow sudo meson ninja-build gcc libc-dev curl-dev openssl-dev expat-dev gettext \ + apk add --update shadow sudo meson ninja-build gcc libc-dev curl curl-dev openssl-dev expat-dev gettext \ zlib-ng-dev pcre2-dev python3 musl-libintl perl-utils ncurses \ apache2 apache2-http2 apache2-proxy apache2-ssl apache2-webdav apr-util-dbd_sqlite3 \ bash cvs gnupg perl-cgi perl-dbd-sqlite perl-io-tty >/dev/null ;; fedora-*|almalinux-*) dnf -yq update >/dev/null && - dnf -yq install shadow-utils sudo make gcc findutils diffutils perl python3 gawk gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null + dnf -yq install shadow-utils sudo make gcc findutils diffutils perl python3 gawk gettext zlib-devel expat-devel openssl-devel curl curl-devel pcre2-devel >/dev/null ;; ubuntu-*|i386/ubuntu-*|debian-*) # Required so that apt doesn't wait for user input on certain packages.
@@ -55,8 +55,8 @@ ubuntu-*|i386/ubuntu-*|debian-*) sudo apt-get -q update sudo apt-get -q -y install \ $LANGUAGES apache2 cvs cvsps git gnupg $SVN \ - make libssl-dev libcurl4-openssl-dev libexpat-dev wget sudo default-jre \ - tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \ + make libssl-dev curl libcurl4-openssl-dev libexpat-dev wget sudo default-jre \ + tcl tk gettext zlib1g zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \ libemail-valid-perl libio-pty-perl libio-socket-ssl-perl libnet-smtp-ssl-perl libdbd-sqlite3-perl libcgi-pm-perl \ libsecret-1-dev libpcre2-dev meson ninja-build pkg-config \ ${CC_PACKAGE:-${CC:-gcc}} $PYTHON_PACKAGE
@@ -121,13 +121,13 @@ ClangFormat) ;; StaticAnalysis) sudo apt-get -q update - sudo apt-get -q -y install coccinelle libcurl4-openssl-dev libssl-dev \ + sudo apt-get -q -y install coccinelle curl libcurl4-openssl-dev libssl-dev \ libexpat-dev gettext make ;; sparse) sudo apt-get -q update -q - sudo apt-get -q -y install libssl-dev libcurl4-openssl-dev \ - libexpat-dev gettext zlib1g-dev sparse + sudo apt-get -q -y install libssl-dev curl libcurl4-openssl-dev \ + libexpat-dev gettext zlib1g zlib1g-dev sparse ;; Documentation) sudo apt-get -q update
ci/install-rust-toolchain.sh new file +30 -0
@@ -0,0 +1,30 @@ +#!/bin/sh + +if [ "$CARGO_HOME" = "" ]; then + echo >&2 "::error:: CARGO_HOME is not set" + exit 2 +fi +export PATH="$CARGO_HOME/bin:$PATH" +rustup -vV || exit $? + +## Enforce the correct Rust toolchain +rustup override unset || true + +## install a specific version of rust +if [ "$RUST_TARGET" != "" ]; then + rustup default --force-non-host "$RUST_VERSION-$RUST_TARGET" || exit $? +else + rustup default "$RUST_VERSION" || exit $? +fi + +rustc -vV || exit $? + +RE_RUST_TARGET="$RUST_TARGET" +if [ "$RUST_TARGET" = "" ]; then + RE_RUST_TARGET="[^ ]+" +fi + +if ! rustup show active-toolchain | grep -E "^$RUST_VERSION-$RE_RUST_TARGET \(default\)$"; then + echo >&2 "::error:: wrong Rust toolchain, active-toolchain: $(rustup show active-toolchain)" + exit 3 +fi
ci/install-rustup.sh new file +25 -0
@@ -0,0 +1,25 @@ +#!/bin/sh + +## github workflows actions-rs/toolchain@v1 doesn't work for docker +## targets. This script should only be used if the ci pipeline +## doesn't support installing rust on a particular target. + +if [ "$(id -u)" -eq 0 ]; then + echo >&2 "::warning:: installing rust as root" +fi + +if [ "$CARGO_HOME" = "" ]; then + echo >&2 "::error:: CARGO_HOME is not set" + exit 2 +fi + +export RUSTUP_HOME=$CARGO_HOME + +## install rustup +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y +if [ ! -f $CARGO_HOME/env ]; then + echo "PATH=$CARGO_HOME/bin:\$PATH" > $CARGO_HOME/env +fi +. $CARGO_HOME/env + +rustup -vV
ci/lib.sh +1 -0
@@ -1,5 +1,6 @@ # Library of functions shared by all CI scripts + if test true = "$GITHUB_ACTIONS" then begin_group () {
ci/make-test-artifacts.sh +9 -0
@@ -7,6 +7,15 @@ mkdir -p "$1" # in case ci/lib.sh decides to quit early . ${0%/*}/lib.sh +## ensure rustup is in the PATH variable +if [ "$CARGO_HOME" = "" ]; then + echo >&2 "::error:: CARGO_HOME is not set" + exit 2 +fi +export PATH="$CARGO_HOME/bin:$PATH" + +rustc -vV + group Build make artifacts-tar ARTIFACTS_DIRECTORY="$1" check_unignored_build_artifacts
ci/run-build-and-tests.sh +13 -0
@@ -5,6 +5,15 @@ . ${0%/*}/lib.sh +## ensure rustup is in the PATH variable +if [ "$CARGO_HOME" = "" ]; then + echo >&2 "::error:: CARGO_HOME is not set" + exit 2 +fi +. $CARGO_HOME/env + +rustc -vV || exit $? + run_tests=t case "$jobname" in
@@ -72,5 +81,9 @@ case "$jobname" in ;; esac +if [ -d "$CARGO_HOME" ]; then + rm -rf $CARGO_HOME +fi + check_unignored_build_artifacts save_good_tree
Signature · 1 line
gitgitgadget
Re: [PATCH v2 09/18] github workflows: install rust
Quoted 6 lines · Ezekiel Newren via GitGitGadget
Prefer using actions-rs/toolchain@v1 where possible to install rustup, but for docker targets use a script to install rustup. Consolidate the Rust toolchain definitions in
main.yaml. Useinstall-rust-toolchain.shto ensure the correct toolchain is used. Five overrides are used inmain.yaml:
Quoted 7 lines
* On Windows: Rust didn't resolve the bcrypt library on Windows correctly until version 1.78.0. Also since rustup mis-identifies the Rust toolchain, the Rust target triple must be set to x86_64-pc-windows-gnu for make (win build), and x86_64-pc-windows-msvc for meson (win+Meson build).
* MSVC builds: Rearrange PATH to look in /mingw64/bin and/usr/binlast.
Please add an explanation as to why it is necessary to rearrange PATH. I saw in patch [7/18] that your "build_rust.sh" does the same but the reason is never spelled out (and it's still a mystery to me).
Also, this patch, [9/18], doesn't seem to touch PATH in the way described here (unless I somehow overlooked it).
Quoted 17 lines
* On musl: libc differences, such as ftruncate64 vs ftruncate, were not accounted for until Rust version 1.72.0. No older version of Rust will work on musl for our needs.
* In a 32-bit docker container running on a 64-bit host, we need to override the Rust target triple. This is because rustup asks the kernel for the bitness of the system and it says 64, even though the container is 32-bit. This also allows us to remove the BITNESS environment variable inci/lib.sh.The logic for selecting library names was initially provided in a patch from Johannes, but was reworked and squashed into this commit.
Helped-by Johannes Schindelin <[email protected]>Signed-off-by Ezekiel Newren <[email protected]>---
ci/install-rust-toolchain.sh line 6
Quoted 6 lines
ci/install-rust-toolchain.sh +6
-0@@ -0,0 +1,30 @@ +#!/bin/sh + +if [ "$CARGO_HOME" = "" ]; then + echo >&2 "::error:: CARGO_HOME is not set" + exit 2 +fi
Let's follow project coding guidelines for shell scripts:
if test "$CARGO_HOME" = ""
then
..
fior even:
if test -z "$CARGO_HOME"
then
...
fi
Same comment applies to the remainder of this script and other scripts in this patch.
ci/install-rustup.sh line 3
Quoted 5 lines
ci/install-rustup.sh +3
-0@@ -0,0 +1,25 @@ +if [ ! -f $CARGO_HOME/env ]; then + echo "PATH=$CARGO_HOME/bin:\$PATH" > $CARGO_HOME/env +fi
Style: drop space after '>' operator
ci/lib.sh line 4
Quoted 6 lines
ci/lib.sh +1
-0@@ -1,5 +1,6 @@ # Library of functions shared by all CI scripts + if test true = "$GITHUB_ACTIONS"
Do we need the extra blank line introduced above the if?
PATCH v2 10/18 win+Meson: do allow linking with the Rust-built xdiff
In reply to Ezekiel Newren via GitGitGadgetFrom: Johannes Schindelin <[email protected]>
When linking against the Rust-built xdiff, there is now a new required
dependency: Without _also_ linking to the system library userenv, the compile would fail with this error message:
xdiff.lib(std-c85e9beb7923f636.std.df32d1bc89881d89-cgu.0.rcgu.o) :
error LNK2019: unresolved external symbol __imp_GetUserProfileDirectoryW referenced in function _ZN3std3env8home_dir17hfd1c3b6676cd78f6E
Therefore, just like we do in case of Makefile-based builds on Windows, we now also link to that library when building with Meson.
Note that if we only have Rust depend upon libuserenv then at link time GCC would complain about:
undefined reference to `GetUserProfileDirectoryW'
Apparently there is _some_ closure that gets compiled in that requires this function, and that in turn forces Git to link to libuserenv.
This is a new requirement, and therefore has not been made part of the "minimal Git for Windows SDK".
In the near future, I intend to include it, but for now let's just ensure that the file is added manually if it is missing.
[en: Squashed a few of Johannes's patches, and moved lib userenv
handling from an earlier patch]
--- config.mak.uname | 4 ++++ 1 file changed, 4 insertions(+)
config.mak.uname +4 -0
@@ -759,6 +759,10 @@ ifeq ($(uname_S),MINGW) COMPAT_CFLAGS += -D_USE_32BIT_TIME_T BASIC_LDFLAGS += -Wl,--large-address-aware endif + + # Unfortunately now needed because of Rust + EXTLIBS += -luserenv + CC = gcc COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \ -fstack-protector-strong
Signature · 1 line
gitgitgadget
PATCH v2 11/18 github workflows: upload Cargo.lock
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Make each ci workflow upload its Cargo.lock file as a build artifact so that we can audit build dependencies.
--- .github/workflows/main.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
.github/workflows/main.yml +20 -0
@@ -150,6 +150,11 @@ jobs: with: name: windows-artifacts path: artifacts + - name: upload Cargo.lock + uses: actions/upload-artifact@v4 + with: + name: cargo-lock-windows + path: rust/Cargo.lock windows-test: name: win test runs-on: windows-latest
@@ -311,6 +316,11 @@ jobs: with: name: windows-meson-artifacts path: build + - name: Upload Cargo.lock + uses: actions/upload-artifact@v4 + with: + name: cargo-lock-windows-meson + path: rust/Cargo.lock windows-meson-test: name: win+Meson test runs-on: windows-latest
@@ -393,6 +403,11 @@ jobs: with: name: failed-tests-${{matrix.vector.jobname}} path: ${{env.FAILED_TEST_ARTIFACTS}} + - name: Upload Cargo.lock + uses: actions/upload-artifact@v4 + with: + name: cargo-lock-${{matrix.vector.jobname}} + path: rust/Cargo.lock fuzz-smoke-test: name: fuzz smoke test needs: ci-config
@@ -503,6 +518,11 @@ jobs: with: name: failed-tests-${{matrix.vector.jobname}} path: ${{env.FAILED_TEST_ARTIFACTS}} + - name: Upload Cargo.lock + uses: actions/upload-artifact@v4 + with: + name: cargo-lock-${{matrix.vector.jobname}} + path: rust/Cargo.lock static-analysis: needs: ci-config if: needs.ci-config.outputs.enabled == 'yes'
Signature · 1 line
gitgitgadget
PATCH v2 12/18 build: new crate, build-helper
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Make a crate that takes care of the boiler-plate code that most build.rs files would need to write.
--- .gitignore | 1 + rust/Cargo.toml | 4 +++- rust/build-helper/Cargo.toml | 7 +++++++ rust/build-helper/src/lib.rs | 0 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 rust/build-helper/Cargo.toml create mode 100644 rust/build-helper/src/lib.rs
.gitignore +1 -0
@@ -257,3 +257,4 @@ Release/ .idea/ /rust/target/ /rust/Cargo.lock +
rust/Cargo.toml +3 -1
@@ -1,3 +1,5 @@ [workspace] -members = [] +members = [ + "build-helper", +] resolver = "2"
rust/build-helper/Cargo.toml new file +7 -0
@@ -0,0 +1,7 @@ +[package] +name = "build-helper" +version = "0.1.0" +edition = "2021" + +[dependencies] +
rust/build-helper/src/lib.rs new file +0 -0
Signature · 1 line
gitgitgadget
Re: [PATCH v2 12/18] build: new crate, build-helper
.gitignore Release/ · line 260
Quoted 11 lines · Ezekiel Newren via GitGitGadget
Make a crate that takes care of the boiler-plate code that most
build.rsfiles would need to write.Signed-off-by Ezekiel Newren <[email protected]>---
.gitignore +1
-0@@ -257,3 +257,4 @@ Release/ .idea/ /rust/target/ /rust/Cargo.lock +
This seems to be adding an unnecessary blank line (for no apparent reason).
rust/build-helper/Cargo.toml line 7
Quoted 9 lines
rust/build-helper/Cargo.toml +7
-0@@ -0,0 +1,7 @@ +[package] +name = "build-helper" +version = "0.1.0" +edition = "2021" + +[dependencies] +
I believe I saw a later patch make the sole change to this file of removing the unnecessary blank line at the end of this file. It would be better to fix this patch to omit the line in the first place.
PATCH v2 13/18 build-helper: link against libgit.a and any other required C libraries
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
Don't link against the C libraries when building with Make or Meson. Run cargo tests like this:
cd rust && cargo clean && USE_LINKING=true cargo test
--- rust/build-helper/Cargo.toml | 1 - rust/build-helper/src/lib.rs | 84 ++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-)
rust/build-helper/Cargo.toml +0 -1
@@ -4,4 +4,3 @@ version = "0.1.0" edition = "2021" [dependencies] -
rust/build-helper/src/lib.rs +84 -0
84 lines not on this page · raw message
Signature · 1 line
gitgitgadget
Re: [PATCH v2 13/18] build-helper: link against libgit.a and any other required C libraries
Quoted 8 lines · Ezekiel Newren via GitGitGadget
build-helper: link against libgit.a and any other required C libraries
Don't link against the C libraries when building with Make or Meson. Run cargo tests like this:
cd rust && cargo clean && USE_LINKING=true cargo testSigned-off-by Ezekiel Newren <[email protected]>---
Perhaps it's because I haven't been following the discussion closely enough, but the above commit message leaves me entirely in the dark. After reading and rereading it several times, I suppose it is trying to address some difference between building with cargo vs. building with Make or Meson, but it gives no explanation of what the differences are or what problem it is trying to solve. So, please enhance the commit message to begin with the "why" and then proceed to the "what" or "how".
rust/build-helper/Cargo.toml version = "0.1.0" · line 7
Quoted 6 lines
rust/build-helper/Cargo.toml +0
-1@@ -4,4 +4,3 @@ version = "0.1.0" edition = "2021" [dependencies] -
This seems merely to be deleting a blank line which probably shouldn't have been present in the first place. Rather than fixing the "problem" here, it would make more sense to eliminate the blank line in the patch which introduced it in the first place.
rust/build-helper/src/lib.rs line 4
Quoted 6 lines
rust/build-helper/src/lib.rs +4
-0@@ -0,0 +1,84 @@ +use std::collections::HashMap ; +use std::path::PathBuf ; + +
If I'm not mistaken, it is uncommon to have two blank lines like this in Rust code.
rust/build-helper/src/lib.rs line 11
Quoted 7 lines
rust/build-helper/src/lib.rs +7
-0+fn parse_bool_from_str (value: &str ) ->bool { +match value { +"1" |"true" |"yes" |"on" =>true , +"0" |"false" |"no" |"off" =>false , + _ =>false + } +}
Or, more simply:
fn parse_bool_from_str(value: &str) -> bool {
match value {
"1" | "true" | "yes" | "on" => true,
_ => false
}
}(Though, admittedly, I'd probably lean toward writing the function the same way you did.)
rust/build-helper/src/lib.rs line 28
Quoted 7 lines
rust/build-helper/src/lib.rs +7
-0+/// To build without linking against C libraries run `USE_LINKING=false cargo build` +/// To run tests set GIT_BUILD_DIR and run `USE_LINKING=true cargo test` +pub struct BuildHelper { + crate_env:HashMap <String ,String >, +} + +
Nit: unnecessary extra blank line
rust/build-helper/src/lib.rs line 79
Quoted 5 lines
rust/build-helper/src/lib.rs +5
-0+impl BuildHelper { +pub fn build (self) { +let use_linking =parse_bool_from_option (self.crate_env.get ("USE_LINKING" ), self.crate_env.get ("CARGO_TARGET_DIR" ).is_none ()); + ... + println!("cargo:warning={} is not linking against C objects, `USE_LINKING=true cargo test`", self.crate_env["CARGO_PKG_NAME"]);
There are more than a few developers on this project (including myself) who still use 80-column editors and terminals. As a general style guideline, this project does recommend wrapping code to fit within 80 columns (except in cases when doing so would severely hurt readability). I imagine that the same sort of guideline would be appreciated in Rust code, as well, by those who still stick with 80 columns.
I bring this up because, although it hasn't been such a big deal with the existing C code, assuming that developers run rustfmt on the code before sending a patch series, then this may become an issue if different developers have rustfmt configured to enforce different maximum column width, especially since rustfmt is likely to reformat the entire file rather than just the region that has just been edited. So, if this code gets checked in as-is with these very wide lines, and then someone else, who has rustfmt configured for 80-columns edits the file, then it becomes a problem.
As such, can we also add a project-wide rustfmt.toml which, at minimum, sets the maximum line width to 80? For instance:
max_width = 80
Re: [PATCH v2 13/18] build-helper: link against libgit.a and any other required C libraries
Quoted 26 lines · Eric Sunshine
On Tue, Sep 16, 2025 at 9:18 PM Ezekiel Newren via GitGitGadget
rust/build-helper/src/lib.rs line 79
Quoted 5 lines
rust/build-helper/src/lib.rs +5
-0+impl BuildHelper { +pub fn build (self) { +let use_linking =parse_bool_from_option (self.crate_env.get ("USE_LINKING" ), self.crate_env.get ("CARGO_TARGET_DIR" ).is_none ()); + ... + println!("cargo:warning={} is not linking against C objects, `USE_LINKING=true cargo test`", self.crate_env["CARGO_PKG_NAME"]);There are more than a few developers on this project (including myself) who still use 80-column editors and terminals. As a general style guideline, this project does recommend wrapping code to fit within 80 columns (except in cases when doing so would severely hurt readability). I imagine that the same sort of guideline would be appreciated in Rust code, as well, by those who still stick with 80 columns.
I bring this up because, although it hasn't been such a big deal with the existing C code, assuming that developers run
rustfmton the code before sending a patch series, then this may become an issue if different developers haverustfmtconfigured to enforce different maximum column width, especially sincerustfmtis likely to reformat the entire file rather than just the region that has just been edited. So, if this code gets checked in as-is with these very wide lines, and then someone else, who hasrustfmtconfigured for 80-columns edits the file, then it becomes a problem.
Quoted 5 lines
As such, can we also add a project-wide
rustfmt.tomlwhich, at minimum, sets the maximum line width to 80? For instance:max_width = 80
I believe rustfmt and Rust generally uses a 100 column limit.
See
- https://github.com/rust-lang/rust/pull/5340
- https://rust-lang.github.io/rustfmt/?version=v1.8.0&search=#max_width
Perhaps you knew this, and are really suggesting we break with Rust style for our own style?
For handling personal configs, we could try to maintain a config here that repeats all the defaults, but that seems like more maintenance headache than noticing unnecessary reformatting and reminding folks we use the defaults (except where we have config that specifies otherwise). Although the docs site doesn’t suggest the configs are layered like for Git, so perhaps a blank config is sufficient to enforce « we use the defaults »?
Signature · 1 line
D. Ben Knoble
Re: [PATCH v2 13/18] build-helper: link against libgit.a and any other required C libraries
Quoted 22 lines · D. Ben Knoble
Quoted 21 lines · Eric Sunshine
There are more than a few developers on this project (including myself) who still use 80-column editors and terminals. As a general style guideline, this project does recommend wrapping code to fit within 80 columns (except in cases when doing so would severely hurt readability). I imagine that the same sort of guideline would be appreciated in Rust code, as well, by those who still stick with 80 columns.
I bring this up because, although it hasn't been such a big deal with the existing C code, assuming that developers run
rustfmton the code before sending a patch series, then this may become an issue if different developers haverustfmtconfigured to enforce different maximum column width, especially sincerustfmtis likely to reformat the entire file rather than just the region that has just been edited. So, if this code gets checked in as-is with these very wide lines, and then someone else, who hasrustfmtconfigured for 80-columns edits the file, then it becomes a problem.As such, can we also add a project-wide
rustfmt.tomlwhich, at minimum, sets the maximum line width to 80? For instance:
Quoted 6 lines
Quoted 1 line
max_width = 80I believe rustfmt and Rust generally uses a 100 column limit.
Perhaps you knew this, and are really suggesting we break with Rust style for our own style?
Correct, I did know that, and I also know that there are a number of developers on the Git project who still adhere to (perhaps archaic) 80-column editor and terminal window sizes.
Project guidelines have long suggested 80 columns as a desirable maximum not only for C code, but for pretty much all other resources, including shell code, Perl code, and documentation files. This suggested maximum works well for adherents of 80-columns and (presumably) hasn't been too onerous for developers who use wider windows; at least we haven't heard people clamoring to increase the suggested maximum column limit. As such, it does not seem far-fetched to expect that the project guidelines should/could/would also apply to Rust code.
Quoted 7 lines
For handling personal configs, we could try to maintain a config here that repeats all the defaults, but that seems like more maintenance headache than noticing unnecessary reformatting and reminding folks we use the defaults (except where we have config that specifies otherwise). Although the docs site doesn’t suggest the configs are layered like for Git, so perhaps a blank config is sufficient to enforce « we use the defaults »?
Sorry, I'm not following what you are asking. I'm simply suggesting the possibility of adding a toplevel "$GIT/.rustfmt.toml" to the project with the single line content:
max_width = 80
That aside, we probably also ought to insist (via documentation) that contributors run rustfmt on Rust code before submitting a patch series.
Re: [PATCH v2 13/18] build-helper: link against libgit.a and any other required C libraries
In reply to Eric SunshineQuoted 12 lines · Eric Sunshine
Quoted 8 lines · Ezekiel Newren via GitGitGadget
build-helper: link against libgit.a and any other required C libraries
Don't link against the C libraries when building with Make or Meson. Run cargo tests like this:
cd rust && cargo clean && USE_LINKING=true cargo testSigned-off-by Ezekiel Newren <[email protected]>---
Quoted 8 lines
Perhaps it's because I haven't been following the discussion closely enough, but the above commit message leaves me entirely in the dark. After reading and rereading it several times, I suppose it is trying to address some difference between building with
cargovs. building with Make or Meson, but it gives no explanation of what the differences are or what problem it is trying to solve. So, please enhance the commit message to begin with the "why" and then proceed to the "what" or "how".
As I partially explained in previous comments about my commits. I was trying to get the Rust compiler to link against libgit.a so that any Rust code that references C code in Git would work in Rust unit tests. The way that Cargo invokes rustc and links to libraries can be controlled through build.rs. To use an example; When build.rs prints the following lines to stdout:
cargo:rustc-link-search=native=/path/to/git/build/dir cargo:rustc-link-lib=static=git
The first line tells cargo to tell the Rust compiler to look in '/path/to/git/build/dir' for objects. The second line tells Cargo to tell the Rust compiler to link against libgit.a. Telling Rust how to link against libgit.a is only needed for Rust unit tests that reference Git defined C code.
I'll drop build-helper for this series, since it only helps with linking against libgit.a for Rust unit tests.
PATCH v2 14/18 build-helper: cbindgen, let crates generate a header file
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
--- rust/build-helper/Cargo.toml | 5 ++++ rust/build-helper/src/lib.rs | 44 +++++++++++++++++++++++++++++++++++- rust/cbindgen-template.toml | 16 +++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 rust/cbindgen-template.toml
rust/build-helper/Cargo.toml +5 -0
@@ -4,3 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] +cbindgen = "0.24.0" +textwrap = "=0.16.1" +once_cell = "=1.20.3" +unicode-width = "=0.1.13" +
rust/build-helper/src/lib.rs +43 -1
78 lines not on this page · raw message
rust/cbindgen-template.toml new file +16 -0
@@ -0,0 +1,16 @@ +## compat/posix.h includes stdbool.h where git-compat-util.h does not +## this is mandatory for correct bool C <-> Rust interop. Though the +## 'includes' (and all other variables in this file) can be +## overridden in build.rs. +sys_includes = ["compat/posix.h"] + +autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" + +language = "C" +no_includes = true +usize_is_size_t = true +style = "tag" +tab_width = 4 + +[parse] +parse_deps = false
Signature · 1 line
gitgitgadget
Re: [PATCH v2 14/18] build-helper: cbindgen, let crates generate a header file
Quoted 4 lines · Ezekiel Newren via GitGitGadget
build-helper: cbindgen, let crates generate a header file
Signed-off-by Ezekiel Newren <[email protected]>---
It would be nice to have a bit more explanation of what this patch is doing and why. I presume that this is adding boilerplate functionality but that there are no clients of this functionality yet. Is that correct?
rust/cbindgen-template.toml line 4
Quoted 6 lines
rust/cbindgen-template.toml +4
-0@@ -0,0 +1,16 @@ +## compat/posix.h includes stdbool.h where git-compat-util.h does not +## this is mandatory for correct bool C <-> Rust interop. Though the +## 'includes' (and all other variables in this file) can be +## overridden in build.rs.
There seems to be some missing punctuation in the above comment, and the final sentence seems to be incomplete, both of which make it difficult to understand what is being said.
rust/cbindgen-template.toml line 13
Quoted 9 lines
rust/cbindgen-template.toml +9
-0+sys_includes = ["compat/posix.h"] + +autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" + +language = "C" +no_includes = true +usize_is_size_t = true +style = "tag" +tab_width = 4
It's a minor thing and probably not super important but I'm wondering if it would be a good idea to follow project guidelines and make the TAB width 8 rather than 4. Doing so might be appreciated by people reading the generated header files.
Re: [PATCH v2 14/18] build-helper: cbindgen, let crates generate a header file
Quoted 4 lines · Eric Sunshine
It would be nice to have a bit more explanation of what this patch is doing and why. I presume that this is adding boilerplate functionality but that there are no clients of this functionality yet. Is that correct?
I included cbindgen at Brian's request. Its job is to generate C header files based on Rust code. This eliminates errors of manually keeping definitions in sync between Rust and C. You are correct that nothing in my code uses cbindgen yet. I wanted people to see what would be required to make cbindgen exist in Git. I think I'll drop cbindgen for this series since varint is so trivial.
I think it would be worthwhile to go over some Rust terminology:
[rustc]: The rust compiler.
[cargo]: Canonical build system + package manager. Even rustc uses cargo to build itself.
[rustup]: Rust toolchain manager. This provides rustc and cargo + other stuff. [crate]: The unit of compilation. In C it's akin to a single library file or executable. It follows the structure ofmy_crate
├── Cargo.toml
├── build.rs
└── src
├── do_that.rs
├── do_this.rs
└── lib.rsWhere src/lib.rs (the entry point) means it's a library crate and main.rs (the entry point) would mean it's an executable crate (though you can define both in the same crate).
This means for each crate there will be lib<crate>.a and optionally interop/<crate>.h. So places like xdiff and reftable would be easy to fit into the concept of a crate. The rest of Git would take some doing to organize into crates.
Quoted 10 lines
rust/cbindgen-template.toml line 4
Quoted 6 lines
rust/cbindgen-template.toml +4
-0@@ -0,0 +1,16 @@ +## compat/posix.h includes stdbool.h where git-compat-util.h does not +## this is mandatory for correct bool C <-> Rust interop. Though the +## 'includes' (and all other variables in this file) can be +## overridden in build.rs.There seems to be some missing punctuation in the above comment, and the final sentence seems to be incomplete, both of which make it difficult to understand what is being said.
I'll fix that wording.
Quoted 6 lines
Quoted 6 lines
rust/cbindgen-template.toml +6
-0+sys_includes = ["compat/posix.h"] + +autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" + +language = "C" +no_includes = true
Quoted 8 lines
rust/cbindgen-template.toml line 13
Quoted 3 lines
rust/cbindgen-template.toml +3
-0+usize_is_size_t = true +style = "tag" +tab_width = 4It's a minor thing and probably not super important but I'm wondering if it would be a good idea to follow project guidelines and make the TAB width 8 rather than 4. Doing so might be appreciated by people reading the generated header files.
I'm fine with changing this value.
I was aware that Git uses a tab width of 8, but the problem is that Git uses tab characters instead of spaces and as far as I can tell cbindgen doesn't support using a tab character for indentation. So tab_width in cbindgen-template.toml means X space characters per indent.
PATCH v2 15/18 varint: use explicit width for integers
In reply to Ezekiel Newren via GitGitGadgetFrom: Patrick Steinhardt <[email protected]>
The varint subsystem currently uses implcit widths for integers. On the one hand we use uintmax_t for the actual value. On the other hand, we use int for the length of the encoded varint.
Both of these have known maximum vaules, as we only support at most 16 bytes when encoding varints. Thus, we know that we won't ever exceed uint64_t for the actual value and uint8_t for the prefix length.
Refactor the code to use explicit widths. Besides making the logic platform-independent, it also makes our life a bit easier in the next commit, where we reimplement "varint.c" in Rust.
--- dir.c | 18 ++++++++++-------- read-cache.c | 6 ++++-- varint.c | 6 +++--- varint.h | 4 ++-- 4 files changed, 19 insertions(+), 15 deletions(-)
dir.c +10 -8
@@ -3579,7 +3579,8 @@ static void write_one_dir(struct untracked_cache_dir *untracked,struct stat_data stat_data;struct strbuf *out = &wd->out;unsigned char intbuf[16 ]; -unsigned int intlen, value; +unsigned int value; +uint8_t intlen;int i = wd->index++;/*
@@ -3632,7 +3633,7 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untrastruct ondisk_untracked_cache *ouc;struct write_data wd;unsigned char varbuf[16 ]; -int varint_len; +uint8_t varint_len;const unsigned hashsz = the_hash_algo->rawsz;CALLOC_ARRAY (ouc,1 );
@@ -3738,7 +3739,7 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,struct untracked_cache_dir ud, *untracked;const unsigned char *data = rd->data, *end = rd->end;const unsigned char *eos; -unsigned int value; +uint64_t value;int i;memset (&ud,0 ,sizeof (ud));
@@ -3830,7 +3831,8 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned longstruct read_data rd;const unsigned char *next = data, *end = (const unsigned char *)data + sz;const char *ident; -int ident_len; +uint64_t ident_len; +uint64_t varint_len;ssize_t len;const char *exclude_per_dir;const unsigned hashsz = the_hash_algo->rawsz;
@@ -3867,8 +3869,8 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned longif (next >= end) goto done2; - len =decode_varint (&next); -if (next > end || len ==0 ) + varint_len =decode_varint (&next); +if (next > end || varint_len ==0 ) goto done2; rd.valid =ewah_new ();
@@ -3877,9 +3879,9 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long rd.data = next; rd.end = end; rd.index =0 ; -ALLOC_ARRAY (rd.ucd, len); +ALLOC_ARRAY (rd.ucd, varint_len); -if (read_one_dir (&uc->root, &rd) || rd.index != len) +if (read_one_dir (&uc->root, &rd) || rd.index != varint_len) goto done; next = rd.data;
read-cache.c +4 -2
@@ -1807,7 +1807,7 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,if (expand_name_field) {const unsigned char *cp = (const unsigned char *)name; -size_t strip_len, previous_len; +uint64_t strip_len, previous_len;/* If we're at the beginning of a block, ignore the previous name */ strip_len =decode_varint (&cp);
@@ -2655,8 +2655,10 @@ static int ce_write_entry(struct hashfile *f, struct cache_entry *ce,hashwrite (f, ce->name, len);hashwrite (f, padding,align_padding_size (size, len)); }else { -int common, to_remove, prefix_size; +int common, to_remove; +uint8_t prefix_size;unsigned char to_remove_vi[16 ]; + for (common = 0; (common < previous_name->len && ce->name[common] &&
varint.c +3 -3
@@ -1,11 +1,11 @@#include "git-compat-util.h" #include "varint.h" -uintmax_t decode_varint (const unsigned char **bufp) +uint64_t decode_varint (const unsigned char **bufp) {const unsigned char *buf = *bufp;unsigned char c = *buf++; -uintmax_t val = c &127 ; +uint64_t val = c &127 ;while (c &128 ) { val +=1 ;if (!val ||MSB (val,7 ))
@@ -17,7 +17,7 @@ uintmax_t decode_varint(const unsigned char **bufp)return val; } -int encode_varint (uintmax_t value,unsigned char *buf) +uint8_t encode_varint (uint64_t value,unsigned char *buf) {unsigned char varint[16 ];unsigned pos =sizeof (varint) -1 ;
varint.h +2 -2
@@ -1,7 +1,7 @@#ifndef VARINT_H #define VARINT_H -int encode_varint (uintmax_t ,unsigned char *); -uintmax_t decode_varint (const unsigned char **); +uint8_t encode_varint (uint64_t ,unsigned char *); +uint64_t decode_varint (const unsigned char **);#endif /* VARINT_H */
Signature · 1 line
gitgitgadget
PATCH v2 16/18 build: new crate, misc
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
--- Makefile | 2 +- meson.build | 2 +- rust/Cargo.toml | 1 + rust/misc/Cargo.toml | 14 ++++++++++++++ rust/misc/src/lib.rs | 0 5 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 rust/misc/Cargo.toml create mode 100644 rust/misc/src/lib.rs
Makefile +1 -1
@@ -929,7 +929,7 @@ EXTLIBS = GIT_BUILD_DIR := $(CURDIR) export GIT_BUILD_DIR -RUST_CRATES := +RUST_CRATES := misc .PHONY: compile_rust rustclean WITH_RUST ?= true
meson.build +1 -1
@@ -267,7 +267,7 @@ version_gen_environment.set('GIT_DATE', get_option('build_date')) version_gen_environment.set('GIT_USER_AGENT', get_option('user_agent')) version_gen_environment.set('GIT_VERSION', get_option('version')) -rust_crates = [] +rust_crates = ['misc'] rust_builds = [] with_rust = get_option('with_rust')
rust/Cargo.toml +1 -0
@@ -1,5 +1,6 @@ [workspace] members = [ "build-helper", + "misc", ] resolver = "2"
rust/misc/Cargo.toml new file +14 -0
@@ -0,0 +1,14 @@ +[package] +name = "misc" +version = "0.1.0" +edition = "2021" + +[lib] +name = "misc" +path = "src/lib.rs" +## staticlib to generate xdiff.a for use by gcc +## cdylib (optional) to generate xdiff.so for use by gcc +## rlib is required by the rust unit tests +crate-type = ["staticlib", "rlib"] + +[dependencies]
rust/misc/src/lib.rs new file +0 -0
Signature · 1 line
gitgitgadget
Re: [PATCH v2 16/18] build: new crate, misc
Quoted 4 lines · Ezekiel Newren via GitGitGadget
build: new crate, misc
Signed-off-by Ezekiel Newren <[email protected]>---
Please extend the commit message to at least give _some_ information about what the "misc" crate is all about since it is not at all apparent based upon the name.
By the way, is "misc" really a good name? It sounds like it's going to be a dumping ground for anything which doesn't fit anywhere else.
rust/misc/src/lib.rs
Quoted 14 lines
rust/misc/Cargo.toml +9
-0@@ -0,0 +1,14 @@ +[lib] +name = "misc" +path = "src/lib.rs" +## staticlib to generate xdiff.a for use by gcc +## cdylib (optional) to generate xdiff.so for use by gcc +## rlib is required by the rust unit tests +crate-type = ["staticlib", "rlib"] + +[dependencies]rust/misc/src/lib.rs new file +0
-0
Do I understand correctly from the comment that this crate has something to do with "xdiff", yet there doesn't actually seem to be anything here referencing "xdiff"? Am I missing something?
Re: [PATCH v2 16/18] build: new crate, misc
In reply to Ezekiel Newren via GitGitGadgetOn Tue, Sep 16, 2025 at 7:17 PM Ezekiel Newren via GitGitGadget <[email protected]> wrote:
To: Eric Sunshine
It looks like my gmail never received your email, so I'll respond to my own patch.
Quoted 6 lines
Please extend the commit message to at least give _some_ information about what the "misc" crate is all about since it is not at all apparent based upon the name.
By the way, is "misc" really a good name? It sounds like it's going to be a dumping ground for anything which doesn't fit anywhere else.
I don't like the name misc either. What should we call the crate that will be the new home for .c and .h files that live in the root of the Git repository? varint is so tiny that creating a crate just for it seems unjustified.
Quoted 3 lines
Do I understand correctly from the comment that this crate has something to do with "xdiff", yet there doesn't actually seem to be anything here referencing "xdiff"? Am I missing something?
This crate has nothing to do with xdiff. I copy pasted the Cargo.toml file from the xdiff crate and forgot to refactor the comment.
Re: [PATCH v2 16/18] build: new crate, misc
Quoted 5 lines · Ezekiel Newren
On Tue, Sep 16, 2025 at 7:17 PM Ezekiel Newren via GitGitGadget <[email protected]> wrote:
To: Eric Sunshine
It looks like my gmail never received your email, so I'll respond to my own patch.
Indeed, by sending reviews about earlier patches in this series, it somehow triggered Gmail to think that I was spamming you, hence Gmail thenceforth refused to deliver all subsequent emails to you (and several other Gmail addresses in the recipient list, including Ben and GitGitGadget). Hence, you would (presumably) have only received my review emails and other responses indirectly via the Git mailing list itself (assuming you are subscribed). As far as I know, Gmail still considers my email address as being a spammer to you, so I'm using a different email address to respond here.
Quoted 11 lines
Quoted 6 lines
Please extend the commit message to at least give _some_ information about what the "misc" crate is all about since it is not at all apparent based upon the name.
By the way, is "misc" really a good name? It sounds like it's going to be a dumping ground for anything which doesn't fit anywhere else.
I don't like the name misc either. What should we call the crate that will be the new home for .c and .h files that live in the root of the Git repository? varint is so tiny that creating a crate just for it seems unjustified.
Would the name gitcore or git-core be suitable?
Re: [PATCH v2 16/18] build: new crate, misc
Quoted 1 line · Eric Sunshine
Would the name
gitcoreorgit-corebe suitable?
The only other name I could think of was util, but I think I prefer gitcore. Does anybody else have any name suggestions?
PATCH v2 17/18 misc: use BuildHelper
In reply to Ezekiel Newren via GitGitGadgetFrom: Ezekiel Newren <[email protected]>
--- rust/misc/Cargo.toml | 3 +++ rust/misc/build.rs | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 rust/misc/build.rs
rust/misc/Cargo.toml +3 -0
@@ -12,3 +12,6 @@ path = "src/lib.rs" crate-type = ["staticlib", "rlib"] [dependencies] + +[build-dependencies] +build-helper = { path = "../build-helper" }
rust/misc/build.rs new file +6 -0
@@ -0,0 +1,6 @@ +use build_helper::BuildHelper ; + +fn main () { +BuildHelper ::new (std::env::vars ().collect ()) + .build (); +}
Signature · 1 line
gitgitgadget
PATCH v2 18/18 misc::varint: reimplement as test balloon for Rust
In reply to Ezekiel Newren via GitGitGadgetFrom: Patrick Steinhardt <[email protected]>
Implement a trivial test balloon for our Rust build infrastructure by reimplementing the "varint.c" subsystem in Rust. This subsystem is chosen because it is trivial to convert and because it doesn't have any dependencies to other components of Git.
If support for Rust is enabled, we stop compiling "varint.c" and instead compile and use "src/varint.rs".
--- Makefile | 2 + meson.build | 7 +++- rust/misc/src/lib.rs | 1 + rust/misc/src/varint.rs | 92 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 rust/misc/src/varint.rs
Makefile +2 -0
@@ -1259,7 +1259,9 @@ LIB_OBJS += urlmatch.o LIB_OBJS += usage.o LIB_OBJS += userdiff.o LIB_OBJS += utf8.o +ifeq ($(WITH_RUST),false) LIB_OBJS += varint.o +endif LIB_OBJS += version.o LIB_OBJS += versioncmp.o LIB_OBJS += walker.o
meson.build +6 -1
@@ -571,7 +571,6 @@ libgit_sources = [ 'usage.c', 'userdiff.c', 'utf8.c', - 'varint.c', 'version.c', 'versioncmp.c', 'walker.c',
@@ -591,6 +590,12 @@ libgit_sources = [ 'xdiff/xutils.c', ] +if not with_rust + libgit_sources += [ + 'varint.c', + ] +endif + libgit_sources += custom_target( input: 'command-list.txt', output: 'command-list.h',
rust/misc/src/lib.rs +1 -0
@@ -0,0 +1 @@ +pub mod varint;
rust/misc/src/varint.rs new file +92 -0
92 lines not on this page · raw message
Signature · 1 line
gitgitgadget
Quoted 25 lines · Ezekiel Newren via GitGitGadget
This is a continuation of
https://lore.kernel.org/git/[email protected]/,
but I am removing the RFC label.Suggestions on changes that I could make to this series is appreciated.
Changes in v2: High level overview:
* patch 1: cleanup: rename variables that collide with Rust primitive type names
* patches 2-4:Makefilenow produces libgit.a correctly
* patches 5,6: Documentation from Brian and Patrick
* patches 7,8: Introduce Rust
* patches 9-11: github workflows
* patches 12-14: introduce crates build-helper, and cbindgen
* patches 15-18: varint test balloonI would like feed back in two categories: big changes, and little changes. Is my patch series even going in the right direction, and what are the little details that I've missed? I know Brian asked for cbindgen and it made the series several commits longer, but I think it's a great idea to have. I am not happy with every choice that I made, but I currently don't see a better way or at least an easier alternative to my approach in bringing Rust to Git.
Quoted 3 lines
Build results for these changes:
https://github.com/git/git/actions/runs/17783386212?pr=2043. Some of these are failing.
Given that this isn't yet ready and given that this patch series is way bigger than the one I have in flight that focusses on introducing the policy [1]: how about we first merge that one down and then rebase your patches on top of it to iterate? It would reduce the scope of your patch series and allow us to make smaller steps towards our goal.
To be clear: I very much think that most of the steps here are quite sensible. We definitely want to introduce cbindgen, we obviously need to introduce support on Windows, and I guess having multiple different workspaces is also something that could provide benefit.
But there is no reason to have that all at once, so hence my suggestion to build out the infra one step at a time.
What do you think?
Patrick
Quoted 11 lines · Patrick Steinhardt
Given that this isn't yet ready and given that this patch series is way bigger than the one I have in flight that focusses on introducing the policy [1]: how about we first merge that one down and then rebase your patches on top of it to iterate? It would reduce the scope of your patch series and allow us to make smaller steps towards our goal.
To be clear: I very much think that most of the steps here are quite sensible. We definitely want to introduce cbindgen, we obviously need to introduce support on Windows, and I guess having multiple different workspaces is also something that could provide benefit.
Quoted 4 lines
But there is no reason to have that all at once, so hence my suggestion to build out the infra one step at a time.
What do you think?
I think I made a big mistake of not making it clear that I intended v2 as more of an RFC. My worry (that I expressed very poorly or not at all) is how hard will it be to apply my patches on top of your foundation? I don't know if minor or major changes to your current path would be needed, so I proposed a different way to Introduce Rust while trying to incorporate work from others.
I wanted feedback on:
* Cleaning up Rust type name collisions
* People don't like it, so I'll drop that
* Have Makefile produce libgit.a correctly.
* I think this is a good idea, but it doesn't belong in this patch series.
* Adding Rust unit test which required fixing Make and adding
build-helper to reduce boilerplate code
* I think this is a good idea, but should be added later.
* Introduce cbindgen to avoid desync errors between Rust and C.
* LIke other points above; This should be added later.
* What should we call the crate that will be the new home for .c and
.h files in the root of Git?
Quoted 15 lines · Ezekiel Newren
Quoted 14 lines · Patrick Steinhardt
Given that this isn't yet ready and given that this patch series is way bigger than the one I have in flight that focusses on introducing the policy [1]: how about we first merge that one down and then rebase your patches on top of it to iterate? It would reduce the scope of your patch series and allow us to make smaller steps towards our goal.
To be clear: I very much think that most of the steps here are quite sensible. We definitely want to introduce cbindgen, we obviously need to introduce support on Windows, and I guess having multiple different workspaces is also something that could provide benefit.
But there is no reason to have that all at once, so hence my suggestion to build out the infra one step at a time.
Quoted 8 lines
Quoted 1 line
What do you think?
I think I made a big mistake of not making it clear that I intended v2 as more of an RFC. My worry (that I expressed very poorly or not at all) is how hard will it be to apply my patches on top of your foundation? I don't know if minor or major changes to your current path would be needed, so I proposed a different way to Introduce Rust while trying to incorporate work from others.
Ah, fair enough. Thanks for clarifying your intentions!
I don't think there'd have to be major changes to the current version of my patch series. The idea of that patch series is very much getting buy-in regarding our roadmap and focus less on the actual build infra. So the changes introduced are mostly an MVC, and I very much think that we'll have to iterate quite a bit on it, but that's intended.
I think that a lot of the steps you outline below are logical next steps to get there. If I can change anything to make these next steps easier for you I'm happy to do so. But I also don't think it's too bad if we have to change the current infra quite significantly to get there.
Quoted 3 lines
I wanted feedback on:
* Cleaning up Rust type name collisions
* People don't like it, so I'll drop that
I don't have a strong opinion on this. If it creates issues I personally don't mind fixing it.
Quoted 7 lines
* Have
Makefileproduce libgit.a correctly.
* I think this is a good idea, but it doesn't belong in this patch series.
* Adding Rust unit test which required fixing Make and adding
build-helper to reduce boilerplate code
* I think this is a good idea, but should be added later.
* Introduce cbindgen to avoid desync errors between Rust and C.
* LIke other points above; This should be added later.
Agreed, these all make sense to me.
Quoted 2 lines
* What should we call the crate that will be the new home for .c and
.h files in the root of Git?
We could call this something like "libgit-ffi", but I don't care too much.
Thanks!
Patrick
Quoted 5 lines · Patrick Steinhardt
I don't think there'd have to be major changes to the current version of my patch series. The idea of that patch series is very much getting buy-in regarding our roadmap and focus less on the actual build infra. So the changes introduced are mostly an MVC, and I very much think that we'll have to iterate quite a bit on it, but that's intended.
So long as you're flexible with the build infra details then I'm ok with rebasing on your work.
What does MVC stand for?
Quoted 4 lines
I think that a lot of the steps you outline below are logical next steps to get there. If I can change anything to make these next steps easier for you I'm happy to do so. But I also don't think it's too bad if we have to change the current infra quite significantly to get there.
I think we can discuss those code and infra changes in a later patch series.
Quoted 6 lines
Quoted 3 lines
I wanted feedback on:
* Cleaning up Rust type name collisions
* People don't like it, so I'll drop thatI don't have a strong opinion on this. If it creates issues I personally don't mind fixing it.
Junio doesn't like it, so I'm not going to do it.
Quoted 9 lines
Quoted 7 lines
* Have
Makefileproduce libgit.a correctly.
* I think this is a good idea, but it doesn't belong in this patch series.
* Adding Rust unit test which required fixing Make and adding
build-helper to reduce boilerplate code
* I think this is a good idea, but should be added later.
* Introduce cbindgen to avoid desync errors between Rust and C.
* LIke other points above; This should be added later.Agreed, these all make sense to me.
I think the changes to Makefile to build ligbit.a correctly can be an orthogonal patch series. The rest can come later.
Quoted 5 lines
Quoted 2 lines
* What should we call the crate that will be the new home for .c and
.h files in the root of Git?We could call this something like "libgit-ffi", but I don't care too much.
I prefer Eric Sunshine's suggestion of gitcore, no hyphen.
Quoted 11 lines · Ezekiel Newren
Quoted 5 lines · Patrick Steinhardt
I don't think there'd have to be major changes to the current version of my patch series. The idea of that patch series is very much getting buy-in regarding our roadmap and focus less on the actual build infra. So the changes introduced are mostly an MVC, and I very much think that we'll have to iterate quite a bit on it, but that's intended.
So long as you're flexible with the build infra details then I'm ok with rebasing on your work.
What does MVC stand for?
Minimum viable... candidate? I guess I rather meant "product", so MVP would be the better term.
[snip]
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
* What should we call the crate that will be the new home for .c and
.h files in the root of Git?We could call this something like "libgit-ffi", but I don't care too much.
I prefer Eric Sunshine's suggestion of gitcore, no hyphen.
Sounds reasonable to me.
Patrick
Quoted 8 lines · Ezekiel Newren
Quoted 6 lines
Quoted 3 lines
I wanted feedback on:
* Cleaning up Rust type name collisions
* People don't like it, so I'll drop thatI don't have a strong opinion on this. If it creates issues I personally don't mind fixing it.
Junio doesn't like it, so I'm not going to do it.
It was not "I do not line u16 as a typename when a perfectly well established uint16_t is available", though.
It was more about asking to explain the reason behind insisting to use u(8|16|32|64) types in C code. Perhaps there is a compelling reason to do so that I was missing.
I know that the kernel has used these types for a long time, but that way predates their more recent flirt with Rust. If your answer was "the kernel uses them", then I'd want that answer to cover a few additional questions, like
- Have they benefitted from their use of u(8|16|32|64) when they started working with Rust and if so how?
- Would we be expected to reap the same benefit if we used these types?
for example.
Thanks.
Quoted 9 lines · Junio C Hamano
Quoted 7 lines · Ezekiel Newren
Quoted 6 lines
Quoted 3 lines
I wanted feedback on:
* Cleaning up Rust type name collisions
* People don't like it, so I'll drop thatI don't have a strong opinion on this. If it creates issues I personally don't mind fixing it.
Quoted 8 lines
Quoted 1 line
Junio doesn't like it, so I'm not going to do it.
It was not "I do not like u16 as a typename when a perfectly well established
uint16_tis available", though.It was more about asking to explain the reason behind insisting to use u(8|16|32|64) types in C code. Perhaps there is a compelling reason to do so that I was missing.
I listed 5 reasons in my commit message[1], and I just thought of another one now.
* Pseudo reserved keywords: 'new' is not a reserved keyword in C,
but Git treats it as such. Since Rust will likely be added to Git, the Rust primitive types should also be treated as reserved keywords. Cbindgen parse's Rust and generates C header files; If a field in a struct uses u16 as the name then Rust won't compile, and cbindgen can't create the C header file. Using [ui](8|16|32|64|size) as the type in C also spreads awareness that those are reserved keywords and should not be used as variable names.
If these 6 reasons are not enough to explain why we should be using the Rust primitive type names in C, then please explain how it is insufficient.
Quoted 7 lines
I know that the kernel has used these types for a long time, but that way predates their more recent flirt with Rust. If your answer was "the kernel uses them", then I'd want that answer to cover a few additional questions, like
- Have they benefited from their use of u(8|16|32|64) when they started working with Rust and if so how?
I did not know this.
Quoted 3 lines · Ezekiel Newren
Cbindgen parse's Rust and generates C header files; If a field in a struct uses u16 as the name then Rust won't compile, and cbindgen can't create the C header file.
I just tried this in Rust and it turns out you actually can use u16 as a struct field name. My bad. I think that's a bad idea and should be discouraged though.
Quoted 8 lines · Ezekiel Newren
Quoted 3 lines · Ezekiel Newren
Cbindgen parse's Rust and generates C header files; If a field in a struct uses u16 as the name then Rust won't compile, and cbindgen can't create the C header file.
I just tried this in Rust and it turns out you actually can use u16 as a struct field name. My bad. I think that's a bad idea and should be discouraged though.
That's a great news.
It means we do not have to worry about existing variables and structure member names at all while working with cbindgen.
Quoted 8 lines · Junio C Hamano
Quoted 3 lines
I just tried this in Rust and it turns out you actually can use u16 as a struct field name. My bad. I think that's a bad idea and should be discouraged though.
That's a great news.
It means we do not have to worry about existing variables and structure member names at all while working with cbindgen.
You've convinced me that we shouldn't use Rust type names in C. I've already refactored my code to use [ui]int(8|16|32|64)_t in part 2 of my xdiff cleanup.
Quoted 2 lines · Ezekiel Newren
already refactored my code to use [ui]int(8|16|32|64)_t in part 2 of my xdiff cleanup.
Noted. I think [u]int(8|16|32|64)_t would be familiar to both C writers and Rust folks who need to peek into C for working with it.
Thanks.
Quoted 3 lines · Ezekiel Newren
If a field in a
struct uses u16 as the name then Rust won't compile, and cbindgen can't create the C header file.
Do you mean that cbindgen fails to help us make a C code we have that says "struct { uint16_t u16; }" to work with Rust?
Declaring "typedef uint16_t u16" would not help such a case at all, as it would not make "struct { u16 u16; }" an invalid C, and would not force us to avoid such names that cbindgen may have problems with.
So regardless of what to do with type names, we would need to adjust some variable names to avoid clashes with Rust, which I am fine with.
Quoted 3 lines
Using [ui](8|16|32|64|size) as the type in C also spreads awareness that those are reserved keywords and should not be used as variable names.
We certainly need to train our developers to avoid problematic names like "u16" just like we do so for "new".
I am skeptical that using u16 as a type would have a good chance to contribute to that effort (otherwise we would have added "new" as a type to solve this issue already), but I am willing to be talked into trying, with a few conditions to prevent unnecessary churning, i.e. We do "typedef uint16_t u16" and friends, and new and old code that are written to directly interact with Rust written code would be better written with u16 and friends, so the same thing is called similarly across the wall, but we want to avoid replacing uint16_t with u16 blindly.
Quoted 3 lines · Ezekiel Newren via GitGitGadget
This is a continuation of
https://lore.kernel.org/git/[email protected]/,
but I am removing the RFC label.
Continuation meaning that these patches build on top of that earlier 15-patch series?
Quoted 13 lines
Suggestions on changes that I could make to this series is appreciated.
Changes in v2: High level overview:
* patch 1: cleanup: rename variables that collide with Rust primitive type names
* patches 2-4:Makefilenow produces libgit.a correctly
* patches 5,6: Documentation from Brian and Patrick
* patches 7,8: Introduce Rust
* patches 9-11: github workflows
* patches 12-14: introduce crates build-helper, and cbindgen
* patches 15-18: varint test balloon
Quoted 1 line
I would like feed back in two categories: big changes, and little changes.
This seems to also mix in some patches from Patrick's series that are already in flight. What's the intention of the inclusion? Do you expect us to discard Patrick's series and replace with this, which would lose some from them and then add more from here? Your "pull request" may target my "master/main" branch, but it needs to play well together with other topics in flight that are cooking in 'next' and also with other topics that are aspiring to be in 'next'.
So I can figure out that these patches are designed to apply cleanly on top of Git v2.51.0, I am somewhat lost what you want to do with the resulting branch. Having duplicate commits that happen to do the same thing in multiple branches "git" the tool can handle just fine, but that certainly is a bad communication among developers that we do not want to particularly encourage.
Before talking about "big" and "little" changes, do we need to talk about the series organization and working well among multiple developers?
Thanks.
Quoted 22 lines · Junio C Hamano
Quoted 3 lines · Ezekiel Newren via GitGitGadget
This is a continuation of
https://lore.kernel.org/git/[email protected]/,
but I am removing the RFC label.Continuation meaning that these patches build on top of that earlier 15-patch series?
Quoted 13 lines
Suggestions on changes that I could make to this series is appreciated.
Changes in v2: High level overview:
* patch 1: cleanup: rename variables that collide with Rust primitive type names
* patches 2-4:Makefilenow produces libgit.a correctly
* patches 5,6: Documentation from Brian and Patrick
* patches 7,8: Introduce Rust
* patches 9-11: github workflows
* patches 12-14: introduce crates build-helper, and cbindgen
* patches 15-18: varint test balloon
Quoted 8 lines
Quoted 1 line
I would like feed back in two categories: big changes, and little changes.
This seems to also mix in some patches from Patrick's series that are already in flight. ...
... Having duplicate commits that happen to do
the same thing in multiple branches "git" the tool can handle just fine, but that certainly is a bad communication among developers that we do not want to particularly encourage.
This seems to be even more confusing than I thought. The text in the breaking changes document may be based on Patrick's patch, but it says something different from any of the five iterations of the original series. Since RFC v2 on Sep 5th [*], the introduction schedule described there had multiple steps before Git 3.0 but the text we see in this series plans to start Rust "on" by default and goes directly to Git 3.0 without any other intermediate steps, for example. How was [v2 06/18], which attributes authorship to Patrick, came into this shape? Is this his update over the [v5 7/9] of his series sent outside the mailing list, or did you and Patrick working together to arrive at this updated text?
[References]
* Patrick's rust-balloon series (various iterations)
https://lore.kernel.org/git/[email protected]/
https://lore.kernel.org/git/[email protected]/
https://lore.kernel.org/git/[email protected]/
https://lore.kernel.org/git/[email protected]/
Quoted 9 lines · Junio C Hamano
Quoted 3 lines · Ezekiel Newren via GitGitGadget
This is a continuation of
https://lore.kernel.org/git/[email protected]/,
but I am removing the RFC label.Continuation meaning that these patches build on top of that earlier 15-patch series?
No, continuation just meaning "this is v4, even if not labelled as such by gitgitgadget". "Replacement for" would have been clearer.
Quoted 15 lines
Quoted 13 lines
Suggestions on changes that I could make to this series is appreciated.
Changes in v2: High level overview:
* patch 1: cleanup: rename variables that collide with Rust primitive type names
* patches 2-4:Makefilenow produces libgit.a correctly
* patches 5,6: Documentation from Brian and Patrick
* patches 7,8: Introduce Rust
* patches 9-11: github workflows
* patches 12-14: introduce crates build-helper, and cbindgen
* patches 15-18: varint test balloonQuoted 1 line
I would like feed back in two categories: big changes, and little changes.
Quoted 7 lines
This seems to also mix in some patches from Patrick's series that are already in flight. What's the intention of the inclusion? Do you expect us to discard Patrick's series and replace with this, which would lose some from them and then add more from here? Your "pull request" may target my "master/main" branch, but it needs to play well together with other topics in flight that are cooking in 'next' and also with other topics that are aspiring to be in 'next'.
The lack of context in the cover letter is a good point; I apologize for not having been available to advise and avoid that problem; Ezekiel's been doing the best he can on his own for a while now with only very sporadic comments from me, due to my daughter's recent medical emergency (and then me being multiple weeks behind on everything else because of that).
Quoted 10 lines
So I can figure out that these patches are designed to apply cleanly on top of Git v2.51.0, I am somewhat lost what you want to do with the resulting branch. Having duplicate commits that happen to do the same thing in multiple branches "git" the tool can handle just fine, but that certainly is a bad communication among developers that we do not want to particularly encourage.
Before talking about "big" and "little" changes, do we need to talk about the series organization and working well among multiple developers?
I think that would be helpful, including some guidance on next steps because even I don't know what to advise at this point. The background so far:
* Ezekiel contributed a series to introduce Rust[1]. Someone contributed a competing series and Ezekiel was asked to target somewhere else[2].
* I made a suggestion for that somewhere else, you agreed that it sounded reasonable[3], and Ezekiel complied and redid the series accordingly.
* Patrick wanted the introduction to be different, which is fair. However, instead of providing feedback or suggesting doing things an alternative way, Patrick submitted a competing series that redid the Rust introduction without incorporating any of Ezekiel's work[3], that was far less complete (e.g. no Makefile support, not running on all CI platforms) and saying he'd personally add that stuff later[5], and the series had a few things that both brian and Ezekiel objected to (e.g. cargo delegation, ambiguous types, minimum version which Ezekiel already demonstrated was insufficient). I think the thought here on Patrick's side may have been that Ezekiel's focus was solely on xdiff, rather than having a dual focus on xdiff and Rust, but Patrick left no guidance for Ezekiel on how he could move forward with the other Rust parts Ezekiel did or even whether he was welcome to make contributions in the area.
* With no feedback on how to move forward, Ezekiel wanted to try to merge the relevant parts of the two series, including playing nice by incorporating some of Patrick's changes -- and commented on Patrick's series to that effect[6]. Linking that email (or even incorporating it) into the cover letter would have been helpful, but he's new and missed that.
(Personally, I think it would have been much better for Patrick to send in a series with _just_ the BreakingChanges stuff, and then send patches to Ezekiel with the help & varint stuff, similar to what Dscho did with git-for-windows & Rust[7], and ask Ezekiel to make a test balloon for introducing Rust. Allowing new contributors to get some credit for their work instead of replacing/discarding it tends to go over better. And, to be fully blunt, I think introducing a competing or replacement series to something actively being worked ought to be more of a last resort whether or not the other contributor is new; but I'll stop there since otherwise folks might dig up my blow up -- that I'm not too proud of -- from some years ago when someone did this to me.)
[1] https://lore.kernel.org/git/[email protected]/
[2] https://lore.kernel.org/git/[email protected]/
[3] https://lore.kernel.org/git/[email protected]/
[4] https://lore.kernel.org/git/[email protected]/
[5] https://lore.kernel.org/git/[email protected]/
[6] https://lore.kernel.org/git/CAH=ZcbB0Qv=b-hdB2EVW-D-dob4NnzyWDYGEThYZm94S0V7OGg@mail.gmail.com/
[7] https://lore.kernel.org/git/[email protected]/
So, how to move forward?
A) Modify Patrick's series to just take patch 7 of his v5. Patrick did say that the roadmap was "the more important discussion compared to the technical discussion", and merging that patch would achieve his goal of getting an initial roadmap. Then Ezekiel could grab other pieces from Patrick's series (e.g. the help and varint stuff) and incorporate it into an "introduce rust" series.[*]
B) Merge Patrick's series and tell Ezekiel to rebase, while noting to Ezekiel that the roadmap is the important bit from Patrick's series[*] and he can suggest changes to any of the other bits.
C) Create a consolidated "introduce Rust" series with bits of both -- what I think Ezekiel was trying to do with this series.
D) Something else?
I think Ezekiel's willing to be flexible here, but was doing the best he could as a new contributor with no guidance. What would you like to see, Junio?
[*] Either of these routes are slightly funny, though because Patrick introduced a one-quarter delay on notification to end users of the upcoming change due to the incompleteness of his series. With Ezekiel's changes to build on all platforms in CI, that delay would serve no purpose (that I see) and only harm users by giving them less notice of an upcoming change; so Ezekiel would likely want to tweak the BreakingChanges document in either of these cases to note that we'll give earlier notification to users.
Quoted 9 lines · Elijah Newren
So, how to move forward?
A) Modify Patrick's series to just take patch 7 of his v5. Patrick did say that the roadmap was "the more important discussion compared to the technical discussion", and merging that patch would achieve his goal of getting an initial roadmap. Then Ezekiel could grab other pieces from Patrick's series (e.g. the help and varint stuff) and incorporate it into an "introduce rust" series.[*]
Quoted 6 lines
B) Merge Patrick's series and tell Ezekiel to rebase, while noting to Ezekiel that the roadmap is the important bit from Patrick's series[*] and he can suggest changes to any of the other bits.
C) Create a consolidated "introduce Rust" series with bits of both -- what I think Ezekiel was trying to do with this series.
Ah, I didn't even realize C was what this series was trying to do.
I do not have particular preference between A and B, but I thought A was closer to what was being done with this series, and as long as Ezekiel and Patrick can join forces that way, it would be perfect.
Thanks.
Quoted 15 lines · Junio C Hamano
Quoted 13 lines · Elijah Newren
So, how to move forward?
A) Modify Patrick's series to just take patch 7 of his v5. Patrick did say that the roadmap was "the more important discussion compared to the technical discussion", and merging that patch would achieve his goal of getting an initial roadmap. Then Ezekiel could grab other pieces from Patrick's series (e.g. the help and varint stuff) and incorporate it into an "introduce rust" series.[*]
B) Merge Patrick's series and tell Ezekiel to rebase, while noting to Ezekiel that the roadmap is the important bit from Patrick's series[*] and he can suggest changes to any of the other bits.
Quoted 8 lines
Quoted 2 lines
C) Create a consolidated "introduce Rust" series with bits of both -- what I think Ezekiel was trying to do with this series.
Ah, I didn't even realize C was what this series was trying to do.
I do not have particular preference between A and B, but I thought A was closer to what was being done with this series, and as long as Ezekiel and Patrick can join forces that way, it would be perfect.
I personally think either (A) or (B) would be good choices. I would slightly lean towards (B) just so that we have something that we can already play around with while building the next steps.
By the way: I'm also happy to change attribution of some of the patches in my patch series to mention Ezekiel as author. I don't care much who is listed for the initial patches that introduce Rust, but would retain my own authorship for the "varint" and "BreakingChanges" commits.
Patrick
Quoted 3 lines · Patrick Steinhardt
I personally think either (A) or (B) would be good choices. I would slightly lean towards (B) just so that we have something that we can already play around with while building the next steps.
I'm fine with B if you fix the wording in your Breaking Changes about Rust being introduced in version 2.52. Rust was introduced to Git in 2.49.
Elijah points this out in 1 and 2:
[1] https://lore.kernel.org/git/CABPp-BFXRbaHk9U3BX+d12bZ+ryGOp+btR0ODMw+HtD7xd+MBQ@mail.gmail.com/
[2] https://lore.kernel.org/git/CABPp-BEiK49f_UB5UPe3qM9O7vQGGFJ8Nshw1f6W_6Lw7HRL6Q@mail.gmail.com/
Quoted 4 lines
By the way: I'm also happy to change attribution of some of the patches in my patch series to mention Ezekiel as author. I don't care much who is listed for the initial patches that introduce Rust, but would retain my own authorship for the "varint" and "BreakingChanges" commits.
My only other concern is with varint. You use usize on the Rust side and then uint64_t on the C side, but I'm ok with fixing that later as it only breaks 'linux32 (i386/ubuntu:focal)' in the github workflows.
Quoted 5 lines · Ezekiel Newren
Quoted 3 lines · Patrick Steinhardt
I personally think either (A) or (B) would be good choices. I would slightly lean towards (B) just so that we have something that we can already play around with while building the next steps.
Quoted 7 lines
I'm fine with B if you fix the wording in your Breaking Changes about Rust being introduced in version 2.52. Rust was introduced to Git in 2.49.
Elijah points this out in 1 and 2:
[1] https://lore.kernel.org/git/CABPp-BFXRbaHk9U3BX+d12bZ+ryGOp+btR0ODMw+HtD7xd+MBQ@mail.gmail.com/
[2] https://lore.kernel.org/git/CABPp-BEiK49f_UB5UPe3qM9O7vQGGFJ8Nshw1f6W_6Lw7HRL6Q@mail.gmail.com/
Will adjust.
Quoted 8 lines
Quoted 4 lines
By the way: I'm also happy to change attribution of some of the patches in my patch series to mention Ezekiel as author. I don't care much who is listed for the initial patches that introduce Rust, but would retain my own authorship for the "varint" and "BreakingChanges" commits.
My only other concern is with varint. You use usize on the Rust side and then
uint64_ton the C side, but I'm ok with fixing that later as it only breaks 'linux32 (i386/ubuntu:focal)' in the github workflows.
Oh, this is actually an oversight, good catch! I refactored "varint.c" to use uint64_t, but then forgot to adjust the Rust side in the same spirit. Will fix.
I suggested in [1] that I can change authorship of the patches that introduce the initial infrastructure into Meson and our Makefile (so I guess patches 1 and 3) to instead list you as author and myself as Co-authored-by. Is that something you want? Given that you have kickstarted the whole effort around introducing Rust again I wouldn't mind that at all.
In any case, I'll send a new version of the series tomorrow.
Thanks!
Patrick
[1]: <[email protected]>
Quoted 10 lines · Patrick Steinhardt
Quoted 9 lines · Ezekiel Newren
Quoted 3 lines · Patrick Steinhardt
I personally think either (A) or (B) would be good choices. I would slightly lean towards (B) just so that we have something that we can already play around with while building the next steps.
I'm fine with B if you fix the wording in your Breaking Changes about Rust being introduced in version 2.52. Rust was introduced to Git in 2.49.
Quoted 5 lines
Quoted 3 lines
Elijah points this out in 1 and 2:
[1] https://lore.kernel.org/git/CABPp-BFXRbaHk9U3BX+d12bZ+ryGOp+btR0ODMw+HtD7xd+MBQ@mail.gmail.com/
[2] https://lore.kernel.org/git/CABPp-BEiK49f_UB5UPe3qM9O7vQGGFJ8Nshw1f6W_6Lw7HRL6Q@mail.gmail.com/Will adjust.
Thank you.
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
By the way: I'm also happy to change attribution of some of the patches in my patch series to mention Ezekiel as author. I don't care much who is listed for the initial patches that introduce Rust, but would retain my own authorship for the "varint" and "BreakingChanges" commits.
Quoted 7 lines
Quoted 3 lines
My only other concern is with varint. You use usize on the Rust side and then
uint64_ton the C side, but I'm ok with fixing that later as it only breaks 'linux32 (i386/ubuntu:focal)' in the github workflows.Oh, this is actually an oversight, good catch! I refactored "
varint.c" to useuint64_t, but then forgot to adjust the Rust side in the same spirit. Will fix.
You also missed updating varint.h.
Quoted 6 lines
I suggested in [1] that I can change authorship of the patches that introduce the initial infrastructure into Meson and our
Makefile(so I guess patches 1 and 3) to instead list you as author and myself as Co-authored-by. Is that something you want? Given that you have kickstarted the whole effort around introducing Rust again I wouldn't mind that at all.
It doesn't make sense to me to list myself as the author of any of your commits, but I would like my name referenced in your commit messages.
Thanks.
Ezekiel.
Quoted 11 lines · Ezekiel Newren
Quoted 10 lines · Patrick Steinhardt
Quoted 8 lines · Ezekiel Newren
Quoted 4 lines
By the way: I'm also happy to change attribution of some of the patches in my patch series to mention Ezekiel as author. I don't care much who is listed for the initial patches that introduce Rust, but would retain my own authorship for the "varint" and "BreakingChanges" commits.
My only other concern is with varint. You use usize on the Rust side and then
uint64_ton the C side, but I'm ok with fixing that later as it only breaks 'linux32 (i386/ubuntu:focal)' in the github workflows.
Quoted 5 lines
Quoted 3 lines
Oh, this is actually an oversight, good catch! I refactored "
varint.c" to useuint64_t, but then forgot to adjust the Rust side in the same spirit. Will fix.You also missed updating
varint.h.
Hm, am I missing anything? It does use uint64_t, and if it didn't it would cause a compiler error due to mismatching declarations.
Quoted 10 lines
Quoted 6 lines
I suggested in [1] that I can change authorship of the patches that introduce the initial infrastructure into Meson and our
Makefile(so I guess patches 1 and 3) to instead list you as author and myself as Co-authored-by. Is that something you want? Given that you have kickstarted the whole effort around introducing Rust again I wouldn't mind that at all.It doesn't make sense to me to list myself as the author of any of your commits, but I would like my name referenced in your commit messages.
Okay, will do. Is it sufficient if I say something "Based-on-patch-by" or "Inspired-by"? Don't really have much of a better idea for how to include it, but please let me know in case you have any preference.
Patrick
Quoted 13 lines · Patrick Steinhardt
Quoted 11 lines · Ezekiel Newren
Quoted 10 lines · Patrick Steinhardt
Quoted 8 lines · Ezekiel Newren
Quoted 4 lines
By the way: I'm also happy to change attribution of some of the patches in my patch series to mention Ezekiel as author. I don't care much who is listed for the initial patches that introduce Rust, but would retain my own authorship for the "varint" and "BreakingChanges" commits.
My only other concern is with varint. You use usize on the Rust side and then
uint64_ton the C side, but I'm ok with fixing that later as it only breaks 'linux32 (i386/ubuntu:focal)' in the github workflows.
Quoted 5 lines
Quoted 5 lines
Quoted 3 lines
Oh, this is actually an oversight, good catch! I refactored "
varint.c" to useuint64_t, but then forgot to adjust the Rust side in the same spirit. Will fix.You also missed updating
varint.h.
Oh, I think when I was editing your patches locally varint.h got out of sync.
Quoted 2 lines
Hm, am I missing anything? It does use
uint64_t, and if it didn't it would cause a compiler error due to mismatching declarations.
unsigned char should be replaced with uint8_t. I don't know the exact location that causes linux32 (i386/ubuntu:focal) to fail, I think it had to do with specifying uint64_t on the C side, and usize on the Rust side. usize is 32-bits on i386/ubuntu:focal.
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
I suggested in [1] that I can change authorship of the patches that introduce the initial infrastructure into Meson and our
Makefile(so I guess patches 1 and 3) to instead list you as author and myself as Co-authored-by. Is that something you want? Given that you have kickstarted the whole effort around introducing Rust again I wouldn't mind that at all.
Quoted 7 lines
Quoted 3 lines
It doesn't make sense to me to list myself as the author of any of your commits, but I would like my name referenced in your commit messages.
Okay, will do. Is it sufficient if I say something "Based-on-patch-by" or "Inspired-by"? Don't really have much of a better idea for how to include it, but please let me know in case you have any preference.
Inspired-by would be my preference.
On Tue, Sep 16, 2025 at 7:16 PM Ezekiel Newren via GitGitGadget <[email protected]> wrote:
DROP PATCH SERIES: I am dropping this patch series in favor of Patrick's. Everything I want to add can be rebased on top of his work.
Quoted 4 lines · Ezekiel Newren
On Tue, Sep 16, 2025 at 7:16 PM Ezekiel Newren via GitGitGadget <[email protected]> wrote:
DROP PATCH SERIES: I am dropping this patch series in favor of Patrick's. Everything I want to add can be rebased on top of his work.
OK. Thanks for expressing intentions clearly. Will adjust my end by ejecting them from 'seen'.