From f2301be0765ef1baad163edcae96df92c5e05074 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 2 Oct 2025 09:29:27 +0200 Subject: Makefile: reorder sources after includes In an upcoming change we'll make some of the sources compile conditionally based on whether or not `WITH_RUST` is defined. To let developers specify that flag in their "config.mak" we'll thus have to reorder our sources so that they come after the include of that file. Do so. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 176 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 88 insertions(+), 88 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 555b7f4dc3..7e52625d75 100644 --- a/Makefile +++ b/Makefile @@ -919,6 +919,94 @@ LIB_FILE = libgit.a XDIFF_LIB = xdiff/lib.a REFTABLE_LIB = reftable/libreftable.a +# 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) +EXTLIBS = + +GIT_USER_AGENT = git/$(GIT_VERSION) + +ifeq ($(wildcard sha1collisiondetection/lib/sha1.h),sha1collisiondetection/lib/sha1.h) +DC_SHA1_SUBMODULE = auto +endif + +# Set CFLAGS, LDFLAGS and other *FLAGS variables. These might be +# tweaked by config.* below as well as the command-line, both of +# which'll override these defaults. +# Older versions of GCC may require adding "-std=gnu99" at the end. +CFLAGS = -g -O2 -Wall +LDFLAGS = +CC_LD_DYNPATH = -Wl,-rpath, +BASIC_CFLAGS = -I. +BASIC_LDFLAGS = + +# library flags +ARFLAGS = rcs +PTHREAD_CFLAGS = + +# For the 'sparse' target +SPARSE_FLAGS ?= -std=gnu99 -D__STDC_NO_VLA__ +SP_EXTRA_FLAGS = + +# For informing GIT-BUILD-OPTIONS of the SANITIZE=leak,address targets +SANITIZE_LEAK = +SANITIZE_ADDRESS = + +# For the 'coccicheck' target +SPATCH_INCLUDE_FLAGS = --all-includes +SPATCH_FLAGS = +SPATCH_TEST_FLAGS = + +# If *.o files are present, have "coccicheck" depend on them, with +# COMPUTE_HEADER_DEPENDENCIES this will speed up the common-case of +# only needing to re-generate coccicheck results for the users of a +# given API if it's changed, and not all files in the project. If +# COMPUTE_HEADER_DEPENDENCIES=no this will be unset too. +SPATCH_USE_O_DEPENDENCIES = YesPlease + +# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci +# files into a single contrib/cocci/ALL.cocci before running +# "coccicheck". +# +# Pros: +# +# - Speeds up a one-shot run of "make coccicheck", as we won't have to +# parse *.[ch] files N times for the N *.cocci rules +# +# Cons: +# +# - Will make incremental development of *.cocci slower, as +# e.g. changing strbuf.cocci will re-run all *.cocci. +# +# - Makes error and performance analysis harder, as rules will be +# applied from a monolithic ALL.cocci, rather than +# e.g. strbuf.cocci. To work around this either undefine this, or +# generate a specific patch, e.g. this will always use strbuf.cocci, +# not ALL.cocci: +# +# make contrib/coccinelle/strbuf.cocci.patch +SPATCH_CONCAT_COCCI = YesPlease + +# Rebuild 'coccicheck' if $(SPATCH), its flags etc. change +TRACK_SPATCH_DEFINES = +TRACK_SPATCH_DEFINES += $(SPATCH) +TRACK_SPATCH_DEFINES += $(SPATCH_INCLUDE_FLAGS) +TRACK_SPATCH_DEFINES += $(SPATCH_FLAGS) +TRACK_SPATCH_DEFINES += $(SPATCH_TEST_FLAGS) +GIT-SPATCH-DEFINES: FORCE + @FLAGS='$(TRACK_SPATCH_DEFINES)'; \ + if test x"$$FLAGS" != x"`cat GIT-SPATCH-DEFINES 2>/dev/null`" ; then \ + echo >&2 " * new spatch flags"; \ + echo "$$FLAGS" >GIT-SPATCH-DEFINES; \ + fi + +include config.mak.uname +-include config.mak.autogen +-include config.mak + +ifdef DEVELOPER +include config.mak.dev +endif + GENERATED_H += command-list.h GENERATED_H += config-list.h GENERATED_H += hook-list.h @@ -1387,94 +1475,6 @@ 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) -EXTLIBS = - -GIT_USER_AGENT = git/$(GIT_VERSION) - -ifeq ($(wildcard sha1collisiondetection/lib/sha1.h),sha1collisiondetection/lib/sha1.h) -DC_SHA1_SUBMODULE = auto -endif - -# Set CFLAGS, LDFLAGS and other *FLAGS variables. These might be -# tweaked by config.* below as well as the command-line, both of -# which'll override these defaults. -# Older versions of GCC may require adding "-std=gnu99" at the end. -CFLAGS = -g -O2 -Wall -LDFLAGS = -CC_LD_DYNPATH = -Wl,-rpath, -BASIC_CFLAGS = -I. -BASIC_LDFLAGS = - -# library flags -ARFLAGS = rcs -PTHREAD_CFLAGS = - -# For the 'sparse' target -SPARSE_FLAGS ?= -std=gnu99 -D__STDC_NO_VLA__ -SP_EXTRA_FLAGS = - -# For informing GIT-BUILD-OPTIONS of the SANITIZE=leak,address targets -SANITIZE_LEAK = -SANITIZE_ADDRESS = - -# For the 'coccicheck' target -SPATCH_INCLUDE_FLAGS = --all-includes -SPATCH_FLAGS = -SPATCH_TEST_FLAGS = - -# If *.o files are present, have "coccicheck" depend on them, with -# COMPUTE_HEADER_DEPENDENCIES this will speed up the common-case of -# only needing to re-generate coccicheck results for the users of a -# given API if it's changed, and not all files in the project. If -# COMPUTE_HEADER_DEPENDENCIES=no this will be unset too. -SPATCH_USE_O_DEPENDENCIES = YesPlease - -# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci -# files into a single contrib/cocci/ALL.cocci before running -# "coccicheck". -# -# Pros: -# -# - Speeds up a one-shot run of "make coccicheck", as we won't have to -# parse *.[ch] files N times for the N *.cocci rules -# -# Cons: -# -# - Will make incremental development of *.cocci slower, as -# e.g. changing strbuf.cocci will re-run all *.cocci. -# -# - Makes error and performance analysis harder, as rules will be -# applied from a monolithic ALL.cocci, rather than -# e.g. strbuf.cocci. To work around this either undefine this, or -# generate a specific patch, e.g. this will always use strbuf.cocci, -# not ALL.cocci: -# -# make contrib/coccinelle/strbuf.cocci.patch -SPATCH_CONCAT_COCCI = YesPlease - -# Rebuild 'coccicheck' if $(SPATCH), its flags etc. change -TRACK_SPATCH_DEFINES = -TRACK_SPATCH_DEFINES += $(SPATCH) -TRACK_SPATCH_DEFINES += $(SPATCH_INCLUDE_FLAGS) -TRACK_SPATCH_DEFINES += $(SPATCH_FLAGS) -TRACK_SPATCH_DEFINES += $(SPATCH_TEST_FLAGS) -GIT-SPATCH-DEFINES: FORCE - @FLAGS='$(TRACK_SPATCH_DEFINES)'; \ - if test x"$$FLAGS" != x"`cat GIT-SPATCH-DEFINES 2>/dev/null`" ; then \ - echo >&2 " * new spatch flags"; \ - echo "$$FLAGS" >GIT-SPATCH-DEFINES; \ - fi - -include config.mak.uname --include config.mak.autogen --include config.mak - -ifdef DEVELOPER -include config.mak.dev -endif - GIT-VERSION-FILE: FORCE @OLD=$$(cat $@ 2>/dev/null || :) && \ $(call version_gen,"$(shell pwd)",GIT-VERSION-FILE.in,$@) && \ -- cgit v1.3-6-g1900 From e30c081c6af4963418184dbcd5df37322032f9dc Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 2 Oct 2025 09:29:28 +0200 Subject: Makefile: introduce infrastructure to build internal Rust library Introduce infrastructure to build the internal Rust library. This mirrors the infrastructure we have added to Meson in the preceding commit. Developers can enable the infrastructure by passing the new `WITH_RUST` build toggle. Inspired-by: Ezekiel Newren Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- .gitignore | 2 ++ Makefile | 37 +++++++++++++++++++++++++++++++++++++ shared.mak | 1 + 3 files changed, 40 insertions(+) (limited to 'Makefile') diff --git a/.gitignore b/.gitignore index 1803023427..0833453cf6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /fuzz_corpora +/target/ +/Cargo.lock /GIT-BUILD-DIR /GIT-BUILD-OPTIONS /GIT-CFLAGS diff --git a/Makefile b/Makefile index 7e52625d75..31e79342e1 100644 --- a/Makefile +++ b/Makefile @@ -483,6 +483,14 @@ 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 if you 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 always be enabled. +# +# Building Rust code requires Cargo. +# # == SHA-1 and SHA-256 defines == # # === SHA-1 backend === @@ -683,6 +691,7 @@ OBJECTS = OTHER_PROGRAMS = PROGRAM_OBJS = PROGRAMS = +RUST_SOURCES = EXCLUDED_PROGRAMS = SCRIPT_PERL = SCRIPT_PYTHON = @@ -918,6 +927,11 @@ TEST_SHELL_PATH = $(SHELL_PATH) LIB_FILE = libgit.a XDIFF_LIB = xdiff/lib.a REFTABLE_LIB = reftable/libreftable.a +ifdef DEBUG +RUST_LIB = target/debug/libgitcore.a +else +RUST_LIB = target/release/libgitcore.a +endif # 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) @@ -943,6 +957,15 @@ BASIC_LDFLAGS = ARFLAGS = rcs PTHREAD_CFLAGS = +# Rust flags +CARGO_ARGS = +ifndef V +CARGO_ARGS += --quiet +endif +ifndef DEBUG +CARGO_ARGS += --release +endif + # For the 'sparse' target SPARSE_FLAGS ?= -std=gnu99 -D__STDC_NO_VLA__ SP_EXTRA_FLAGS = @@ -1475,6 +1498,8 @@ CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o +RUST_SOURCES += src/lib.rs + GIT-VERSION-FILE: FORCE @OLD=$$(cat $@ 2>/dev/null || :) && \ $(call version_gen,"$(shell pwd)",GIT-VERSION-FILE.in,$@) && \ @@ -1504,6 +1529,11 @@ endif ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_APPEND) ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND) +ifdef WITH_RUST +BASIC_CFLAGS += -DWITH_RUST +GITLIBS += $(RUST_LIB) +endif + ifdef SANITIZE SANITIZERS := $(foreach flag,$(subst $(comma),$(space),$(SANITIZE)),$(flag)) BASIC_CFLAGS += -fsanitize=$(SANITIZE) -fno-sanitize-recover=$(SANITIZE) @@ -2918,6 +2948,12 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS) $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ +$(RUST_LIB): Cargo.toml $(RUST_SOURCES) + $(QUIET_CARGO)cargo build $(CARGO_ARGS) + +.PHONY: rust +rust: $(RUST_LIB) + $(XDIFF_LIB): $(XDIFF_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ @@ -3768,6 +3804,7 @@ clean: profile-clean coverage-clean cocciclean $(RM) $(FUZZ_PROGRAMS) $(RM) $(SP_OBJ) $(RM) $(HCC) + $(RM) -r Cargo.lock target/ $(RM) version-def.h $(RM) -r $(dep_dirs) $(compdb_dir) compile_commands.json $(RM) $(test_bindir_programs) diff --git a/shared.mak b/shared.mak index 5c7bc94785..0e7492076e 100644 --- a/shared.mak +++ b/shared.mak @@ -56,6 +56,7 @@ ifndef V QUIET_MKDIR_P_PARENT = @echo ' ' MKDIR -p $(@D); ## Used in "Makefile" + QUIET_CARGO = @echo ' ' CARGO $@; QUIET_CC = @echo ' ' CC $@; QUIET_AR = @echo ' ' AR $@; QUIET_LINK = @echo ' ' LINK $@; -- cgit v1.3-6-g1900 From 8832e728d362992a38eef89613b44d24f18e6c2a Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 2 Oct 2025 09:29:31 +0200 Subject: varint: reimplement as test balloon for Rust 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". Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 3 ++ meson.build | 5 +++- src/lib.rs | 1 + src/meson.build | 1 + src/varint.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/varint.rs (limited to 'Makefile') diff --git a/Makefile b/Makefile index 31e79342e1..2a7fc5cb1f 100644 --- a/Makefile +++ b/Makefile @@ -1307,7 +1307,9 @@ LIB_OBJS += urlmatch.o LIB_OBJS += usage.o LIB_OBJS += userdiff.o LIB_OBJS += utf8.o +ifndef WITH_RUST LIB_OBJS += varint.o +endif LIB_OBJS += version.o LIB_OBJS += versioncmp.o LIB_OBJS += walker.o @@ -1499,6 +1501,7 @@ CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o RUST_SOURCES += src/lib.rs +RUST_SOURCES += src/varint.rs GIT-VERSION-FILE: FORCE @OLD=$$(cat $@ 2>/dev/null || :) && \ diff --git a/meson.build b/meson.build index 234a9e9d6f..37dfa28601 100644 --- a/meson.build +++ b/meson.build @@ -522,7 +522,6 @@ libgit_sources = [ 'usage.c', 'userdiff.c', 'utf8.c', - 'varint.c', 'version.c', 'versioncmp.c', 'walker.c', @@ -1707,6 +1706,10 @@ rust_option = get_option('rust').disable_auto_if(not cargo.found()) if rust_option.allowed() subdir('src') libgit_c_args += '-DWITH_RUST' +else + libgit_sources += [ + 'varint.c', + ] endif libgit = declare_dependency( diff --git a/src/lib.rs b/src/lib.rs index e69de29bb2..9da70d8b57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod varint; diff --git a/src/meson.build b/src/meson.build index c8d874b210..25b9ad5a14 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,5 +1,6 @@ libgit_rs_sources = [ 'lib.rs', + 'varint.rs', ] # Unfortunately we must use a wrapper command to move the output file into the diff --git a/src/varint.rs b/src/varint.rs new file mode 100644 index 0000000000..6e610bdd8e --- /dev/null +++ b/src/varint.rs @@ -0,0 +1,92 @@ +#[no_mangle] +pub unsafe extern "C" fn decode_varint(bufp: *mut *const u8) -> u64 { + let mut buf = *bufp; + let mut c = *buf; + let mut val = u64::from(c & 127); + + buf = buf.add(1); + + while (c & 128) != 0 { + val = val.wrapping_add(1); + if val == 0 || val.leading_zeros() < 7 { + return 0; // overflow + } + + c = *buf; + buf = buf.add(1); + + val = (val << 7) + u64::from(c & 127); + } + + *bufp = buf; + val +} + +#[no_mangle] +pub unsafe extern "C" fn encode_varint(value: u64, buf: *mut u8) -> u8 { + let mut varint: [u8; 16] = [0; 16]; + let mut pos = varint.len() - 1; + + varint[pos] = (value & 127) as u8; + + let mut value = value >> 7; + while value != 0 { + pos -= 1; + value -= 1; + varint[pos] = 128 | (value & 127) as u8; + value >>= 7; + } + + if !buf.is_null() { + std::ptr::copy_nonoverlapping(varint.as_ptr().add(pos), buf, varint.len() - pos); + } + + (varint.len() - pos) as u8 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_decode_varint() { + unsafe { + assert_eq!(decode_varint(&mut [0x00].as_slice().as_ptr()), 0); + assert_eq!(decode_varint(&mut [0x01].as_slice().as_ptr()), 1); + assert_eq!(decode_varint(&mut [0x7f].as_slice().as_ptr()), 127); + assert_eq!(decode_varint(&mut [0x80, 0x00].as_slice().as_ptr()), 128); + assert_eq!(decode_varint(&mut [0x80, 0x01].as_slice().as_ptr()), 129); + assert_eq!(decode_varint(&mut [0x80, 0x7f].as_slice().as_ptr()), 255); + + // Overflows are expected to return 0. + assert_eq!(decode_varint(&mut [0x88; 16].as_slice().as_ptr()), 0); + } + } + + #[test] + fn test_encode_varint() { + unsafe { + let mut varint: [u8; 16] = [0; 16]; + + assert_eq!(encode_varint(0, std::ptr::null_mut()), 1); + + assert_eq!(encode_varint(0, varint.as_mut_slice().as_mut_ptr()), 1); + assert_eq!(varint, [0; 16]); + + assert_eq!(encode_varint(10, varint.as_mut_slice().as_mut_ptr()), 1); + assert_eq!(varint, [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + assert_eq!(encode_varint(127, varint.as_mut_slice().as_mut_ptr()), 1); + assert_eq!(varint, [127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + assert_eq!(encode_varint(128, varint.as_mut_slice().as_mut_ptr()), 2); + assert_eq!(varint, [128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + assert_eq!(encode_varint(129, varint.as_mut_slice().as_mut_ptr()), 2); + assert_eq!(varint, [128, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + assert_eq!(encode_varint(255, varint.as_mut_slice().as_mut_ptr()), 2); + assert_eq!(varint, [128, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + } + } +} -- cgit v1.3-6-g1900