* [PATCH] Makefile: link osxkeychain helper against Rust
@ 2026-05-05 17:26 Shardul Natu via GitGitGadget
2026-05-05 19:08 ` Kristoffer Haugsbakk
` (2 more replies)
0 siblings, 3 replies; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-05-05 17:26 UTC (permalink / raw)
To: git; +Cc: Shnatu
From: Shnatu <snatu@google.com>
When Rust is enabled, ensure that the git-credential-osxkeychain
helper is linked with the necessary Rust libraries.
Introduce the RUST_LIBS variable inside ifndef NO_RUST block
to hold the Rust library dependency, and use it in the helper's
build target. This cleanly handles cases where Rust is disabled,
making it a no-op and avoiding any build failures on systems
without Cargo.
This addresses reviewer feedback from internal CL 910223487
by simplifying the variables and avoiding confusing "LINK"
terminology.
Signed-off-by: Shnatu <snatu@google.com>
---
Makefile: link osxkeychain helper against Rust
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2288%2Fkiranani%2Fnext-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2288/kiranani/next-v1
Pull-Request: https://github.com/git/git/pull/2288
Makefile | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index f86173f93a..a17dca22b1 100644
--- a/Makefile
+++ b/Makefile
@@ -1593,6 +1593,7 @@ ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND)
ifndef NO_RUST
BASIC_CFLAGS += -DWITH_RUST
GITLIBS += $(RUST_LIB)
+RUST_LIBS = $(RUST_LIB)
ifeq ($(uname_S),Windows)
EXTLIBS += -luserenv
endif
@@ -4082,9 +4083,9 @@ $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
$(AR) $(ARFLAGS) $@ $^
-contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
+contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIBS) GIT-LDFLAGS
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
- $(filter %.o,$^) $(LIB_FILE) $(EXTLIBS) -framework Security -framework CoreFoundation
+ $(filter %.o,$^) $(LIB_FILE) $(RUST_LIBS) $(EXTLIBS) -framework Security -framework CoreFoundation
contrib/credential/osxkeychain/git-credential-osxkeychain.o: contrib/credential/osxkeychain/git-credential-osxkeychain.c GIT-CFLAGS
$(QUIET_LINK)$(CC) -o $@ -c $(dep_args) $(compdb_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
base-commit: 4f69b47b940100b02630f745a52f9d9850f122b2
--
gitgitgadget
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH] Makefile: link osxkeychain helper against Rust
2026-05-05 17:26 [PATCH] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
@ 2026-05-05 19:08 ` Kristoffer Haugsbakk
2026-05-07 0:39 ` Shnatu
2026-05-08 2:54 ` Junio C Hamano
2026-07-01 22:01 ` [PATCH v2] Makefile: link osxkeychain & support universal Rust Shardul Natu via GitGitGadget
2 siblings, 1 reply; 27+ messages in thread
From: Kristoffer Haugsbakk @ 2026-05-05 19:08 UTC (permalink / raw)
To: git, gitgitgadget; +Cc: Shnatu
On Tue, May 5, 2026, at 19:26, Shardul Natu via GitGitGadget wrote:
> From: Shnatu <snatu@google.com>
>
> When Rust is enabled, ensure that the git-credential-osxkeychain
> helper is linked with the necessary Rust libraries.
>
> Introduce the RUST_LIBS variable inside ifndef NO_RUST block
> to hold the Rust library dependency, and use it in the helper's
> build target. This cleanly handles cases where Rust is disabled,
> making it a no-op and avoiding any build failures on systems
> without Cargo.
>
> This addresses reviewer feedback from internal CL 910223487
> by simplifying the variables and avoiding confusing "LINK"
> terminology.
This pararagraph is meaningless to those outside internal.
>
> Signed-off-by: Shnatu <snatu@google.com>
> ---
>[snip]
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] Makefile: link osxkeychain helper against Rust
2026-05-05 19:08 ` Kristoffer Haugsbakk
@ 2026-05-07 0:39 ` Shnatu
0 siblings, 0 replies; 27+ messages in thread
From: Shnatu @ 2026-05-07 0:39 UTC (permalink / raw)
To: kristofferhaugsbakk; +Cc: git, gitgitgadget, snatu
I have remove the Google specific paragraph, in addition to updating the description
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] Makefile: link osxkeychain helper against Rust
2026-05-05 17:26 [PATCH] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2026-05-05 19:08 ` Kristoffer Haugsbakk
@ 2026-05-08 2:54 ` Junio C Hamano
2026-05-08 9:33 ` Koji Nakamaru
2026-07-01 22:01 ` [PATCH v2] Makefile: link osxkeychain & support universal Rust Shardul Natu via GitGitGadget
2 siblings, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2026-05-08 2:54 UTC (permalink / raw)
To: Shardul Natu via GitGitGadget
Cc: git, Shnatu, brian m. carlson, Koji Nakamaru
"Shardul Natu via GitGitGadget" <gitgitgadget@gmail.com> writes:
> From: Shnatu <snatu@google.com>
If your name is "Shardul Natu", we'd prefer (not 'require', but
'prefer') that the patches authored by you also identify with that
name, both on "From:" and "Signed-off-by:"..
> When Rust is enabled, ensure that the git-credential-osxkeychain
> helper is linked with the necessary Rust libraries.
>
> Introduce the RUST_LIBS variable inside ifndef NO_RUST block
> to hold the Rust library dependency, and use it in the helper's
> build target. This cleanly handles cases where Rust is disabled,
> making it a no-op and avoiding any build failures on systems
> without Cargo.
>
> This addresses reviewer feedback from internal CL 910223487
> by simplifying the variables and avoiding confusing "LINK"
> terminology.
>
> Signed-off-by: Shnatu <snatu@google.com>
> ---
> Makefile: link osxkeychain helper against Rust
Thanks. I've added to CC: a few folks who may be more clueful in
the affected area than I am. It somehow feels strange that we have
to have RUST_LIB and RUST_LIBS separately, and apparently with the
new definition the latter is expected to be a superset of the
former, and it is unclear what are the things that should be added
to the latter without getting added to the former.
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2288%2Fkiranani%2Fnext-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2288/kiranani/next-v1
> Pull-Request: https://github.com/git/git/pull/2288
>
> Makefile | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/Makefile b/Makefile
> index f86173f93a..a17dca22b1 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1593,6 +1593,7 @@ ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND)
> ifndef NO_RUST
> BASIC_CFLAGS += -DWITH_RUST
> GITLIBS += $(RUST_LIB)
> +RUST_LIBS = $(RUST_LIB)
> ifeq ($(uname_S),Windows)
> EXTLIBS += -luserenv
> endif
> @@ -4082,9 +4083,9 @@ $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
> contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
> $(AR) $(ARFLAGS) $@ $^
>
> -contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
> +contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIBS) GIT-LDFLAGS
> $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
> - $(filter %.o,$^) $(LIB_FILE) $(EXTLIBS) -framework Security -framework CoreFoundation
> + $(filter %.o,$^) $(LIB_FILE) $(RUST_LIBS) $(EXTLIBS) -framework Security -framework CoreFoundation
>
> contrib/credential/osxkeychain/git-credential-osxkeychain.o: contrib/credential/osxkeychain/git-credential-osxkeychain.c GIT-CFLAGS
> $(QUIET_LINK)$(CC) -o $@ -c $(dep_args) $(compdb_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
>
> base-commit: 4f69b47b940100b02630f745a52f9d9850f122b2
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] Makefile: link osxkeychain helper against Rust
2026-05-08 2:54 ` Junio C Hamano
@ 2026-05-08 9:33 ` Koji Nakamaru
2026-05-08 17:44 ` Shnatu
0 siblings, 1 reply; 27+ messages in thread
From: Koji Nakamaru @ 2026-05-08 9:33 UTC (permalink / raw)
To: Junio C Hamano
Cc: Shardul Natu via GitGitGadget, git, Shnatu, brian m. carlson
On Fri, May 8, 2026 at 11:54 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> "Shardul Natu via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > From: Shnatu <snatu@google.com>
>
> If your name is "Shardul Natu", we'd prefer (not 'require', but
> 'prefer') that the patches authored by you also identify with that
> name, both on "From:" and "Signed-off-by:"..
>
> > When Rust is enabled, ensure that the git-credential-osxkeychain
> > helper is linked with the necessary Rust libraries.
> >
> > Introduce the RUST_LIBS variable inside ifndef NO_RUST block
> > to hold the Rust library dependency, and use it in the helper's
> > build target. This cleanly handles cases where Rust is disabled,
> > making it a no-op and avoiding any build failures on systems
> > without Cargo.
> >
> > This addresses reviewer feedback from internal CL 910223487
> > by simplifying the variables and avoiding confusing "LINK"
> > terminology.
> >
> > Signed-off-by: Shnatu <snatu@google.com>
> > ---
> > Makefile: link osxkeychain helper against Rust
>
> Thanks. I've added to CC: a few folks who may be more clueful in
> the affected area than I am. It somehow feels strange that we have
> to have RUST_LIB and RUST_LIBS separately, and apparently with the
> new definition the latter is expected to be a superset of the
> former, and it is unclear what are the things that should be added
> to the latter without getting added to the former.
>
> > Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2288%2Fkiranani%2Fnext-v1
> > Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2288/kiranani/next-v1
> > Pull-Request: https://github.com/git/git/pull/2288
> >
> > Makefile | 5 +++--
> > 1 file changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/Makefile b/Makefile
> > index f86173f93a..a17dca22b1 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -1593,6 +1593,7 @@ ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND)
> > ifndef NO_RUST
> > BASIC_CFLAGS += -DWITH_RUST
> > GITLIBS += $(RUST_LIB)
> > +RUST_LIBS = $(RUST_LIB)
> > ifeq ($(uname_S),Windows)
> > EXTLIBS += -luserenv
> > endif
> > @@ -4082,9 +4083,9 @@ $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
> > contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
> > $(AR) $(ARFLAGS) $@ $^
> >
> > -contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
> > +contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIBS) GIT-LDFLAGS
> > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
> > - $(filter %.o,$^) $(LIB_FILE) $(EXTLIBS) -framework Security -framework CoreFoundation
> > + $(filter %.o,$^) $(LIB_FILE) $(RUST_LIBS) $(EXTLIBS) -framework Security -framework CoreFoundation
> >
> > contrib/credential/osxkeychain/git-credential-osxkeychain.o: contrib/credential/osxkeychain/git-credential-osxkeychain.c GIT-CFLAGS
> > $(QUIET_LINK)$(CC) -o $@ -c $(dep_args) $(compdb_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
> >
> > base-commit: 4f69b47b940100b02630f745a52f9d9850f122b2
How about simply wrapping the RUST_LIB-related sections in ifndef
NO_RUST, as shown below? This way, we can avoid defining
RUST_LIBS.
diff --git a/Makefile b/Makefile
index f86173f93a..daa1691950 100644
--- a/Makefile
+++ b/Makefile
@@ -947,11 +947,13 @@ else
RUST_TARGET_DIR = target/release
endif
+ifndef NO_RUST
ifeq ($(uname_S),Windows)
RUST_LIB = $(RUST_TARGET_DIR)/gitcore.lib
else
RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
endif
+endif
GITLIBS = common-main.o $(LIB_FILE)
EXTLIBS =
@@ -3027,11 +3029,13 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
+ifndef NO_RUST
$(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
$(QUIET_CARGO)cargo build $(CARGO_ARGS)
.PHONY: rust
rust: $(RUST_LIB)
+endif
export DEFAULT_EDITOR DEFAULT_PAGER
@@ -4082,9 +4086,9 @@ $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
$(AR) $(ARFLAGS) $@ $^
-contrib/credential/osxkeychain/git-credential-osxkeychain:
contrib/credential/osxkeychain/git-credential-osxkeychain.o
$(LIB_FILE) GIT-LDFLAGS
+contrib/credential/osxkeychain/git-credential-osxkeychain:
contrib/credential/osxkeychain/git-credential-osxkeychain.o
$(LIB_FILE) $(RUST_LIB) GIT-LDFLAGS
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
- $(filter %.o,$^) $(LIB_FILE) $(EXTLIBS) -framework
Security -framework CoreFoundation
+ $(filter %.o,$^) $(LIB_FILE) $(RUST_LIB) $(EXTLIBS)
-framework Security -framework CoreFoundation
contrib/credential/osxkeychain/git-credential-osxkeychain.o:
contrib/credential/osxkeychain/git-credential-osxkeychain.c GIT-CFLAGS
$(QUIET_LINK)$(CC) -o $@ -c $(dep_args) $(compdb_args)
$(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH] Makefile: link osxkeychain helper against Rust
2026-05-08 9:33 ` Koji Nakamaru
@ 2026-05-08 17:44 ` Shnatu
0 siblings, 0 replies; 27+ messages in thread
From: Shnatu @ 2026-05-08 17:44 UTC (permalink / raw)
To: koji.nakamaru; +Cc: git, gitgitgadget, gitster, sandals, snatu
Thank you for the suggestion! This is indeed a much cleaner approach.
By wrapping `RUST_LIB` and the rust targets in `ifndef NO_RUST`, we can link `git-credential-osxkeychain` directly against `$(RUST_LIB)` without needing to introduce an intermediate `RUST_LIBS` variable. When `NO_RUST` is defined, `$(RUST_LIB)` evaluates to empty, and Make naturally links it as a pure C binary without any Rust dependencies.
To integrate this with the universal build support (`RUST_TARGETS`/`lipo`) introduced in this PR, I have updated the changes to:
- Wrap the `RUST_LIB` definition block (which resolves target-specific paths for universal builds) in ifndef `NO_RUST`.
- Wrap the entire universal compilation and lipo combining block in ifndef `NO_RUST`.
- Remove the `RUST_LIBS` helper variable and use `$(RUST_LIB)` directly in `git-credential-osxkeychain`.
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v2] Makefile: link osxkeychain & support universal Rust
2026-05-05 17:26 [PATCH] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2026-05-05 19:08 ` Kristoffer Haugsbakk
2026-05-08 2:54 ` Junio C Hamano
@ 2026-07-01 22:01 ` Shardul Natu via GitGitGadget
2026-07-02 1:35 ` Junio C Hamano
` (2 more replies)
2 siblings, 3 replies; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-07-01 22:01 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Shnatu, Koji Nakamaru, Shnatu
From: Shnatu <snatu@google.com>
When Rust is enabled, ensure that the git-credential-osxkeychain
helper is linked with the necessary Rust libraries.
Also, introduce native support for macOS Universal Binaries
(multi-architecture builds) in the Git build system by allowing
the user to specify a list of target triples in the RUST_TARGETS
environment variable.
To implement this cleanly without complex shell scripting in recipes:
1. We introduce a declarative Make pattern rule (target/%/...) to
compile each target-specific library slice (e.g.,
target/aarch64-apple-darwin/...).
2. We update the $(RUST_LIB) recipe to depend on the list of
compiled target-specific member libraries ($(RUST_MEMBER_LIBS)).
3. On macOS, if multiple targets are specified, we use lipo to
combine them into a single Universal static library at
target/release/libgitcore.a.
4. If only one target is specified, we copy it to the standard
path.
5. We enforce that building for multiple targets requires macOS
(as lipo is only available there), raising a clear make error
on other platforms.
This is a highly elegant and native Makefile solution that avoids
complex shell scripting in recipes and fully supports macOS Universal
Binaries.
Signed-off-by: Shardul Natu <snatu@google.com>
---
Makefile: link osxkeychain helper against Rust
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2288%2Fkiranani%2Fnext-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2288/kiranani/next-v2
Pull-Request: https://github.com/git/git/pull/2288
Range-diff vs v1:
1: 57046d2f78 ! 1: 6a11aff909 Makefile: link osxkeychain helper against Rust
@@ Metadata
Author: Shnatu <snatu@google.com>
## Commit message ##
- Makefile: link osxkeychain helper against Rust
+ Makefile: link osxkeychain & support universal Rust
When Rust is enabled, ensure that the git-credential-osxkeychain
helper is linked with the necessary Rust libraries.
- Introduce the RUST_LIBS variable inside ifndef NO_RUST block
- to hold the Rust library dependency, and use it in the helper's
- build target. This cleanly handles cases where Rust is disabled,
- making it a no-op and avoiding any build failures on systems
- without Cargo.
+ Also, introduce native support for macOS Universal Binaries
+ (multi-architecture builds) in the Git build system by allowing
+ the user to specify a list of target triples in the RUST_TARGETS
+ environment variable.
- This addresses reviewer feedback from internal CL 910223487
- by simplifying the variables and avoiding confusing "LINK"
- terminology.
+ To implement this cleanly without complex shell scripting in recipes:
+ 1. We introduce a declarative Make pattern rule (target/%/...) to
+ compile each target-specific library slice (e.g.,
+ target/aarch64-apple-darwin/...).
+ 2. We update the $(RUST_LIB) recipe to depend on the list of
+ compiled target-specific member libraries ($(RUST_MEMBER_LIBS)).
+ 3. On macOS, if multiple targets are specified, we use lipo to
+ combine them into a single Universal static library at
+ target/release/libgitcore.a.
+ 4. If only one target is specified, we copy it to the standard
+ path.
+ 5. We enforce that building for multiple targets requires macOS
+ (as lipo is only available there), raising a clear make error
+ on other platforms.
- Signed-off-by: Shnatu <snatu@google.com>
+ This is a highly elegant and native Makefile solution that avoids
+ complex shell scripting in recipes and fully supports macOS Universal
+ Binaries.
+
+ Signed-off-by: Shardul Natu <snatu@google.com>
## Makefile ##
-@@ Makefile: ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND)
- ifndef NO_RUST
- BASIC_CFLAGS += -DWITH_RUST
- GITLIBS += $(RUST_LIB)
-+RUST_LIBS = $(RUST_LIB)
+@@ Makefile: include shared.mak
+ #
+ # Building Rust code requires Cargo.
+ #
++# Define RUST_TARGETS if you want to cross-compile. If left unspecified, it uses
++# the default rust target on the system.
++#
++# On macOS, this supports specifying multiple targets, separated by a space.
++# This will produce a Universal static library using `lipo`.
++#
++# Example: RUST_TARGETS="aarch64-apple-darwin x86_64-apple-darwin"
++#
+ # == SHA-1 and SHA-256 defines ==
+ #
+ # === SHA-1 backend ===
+@@ Makefile: TEST_SHELL_PATH = $(SHELL_PATH)
+
+ LIB_FILE = libgit.a
+
++ifndef NO_RUST
+ ifdef DEBUG
+-RUST_TARGET_DIR = target/debug
++RUST_BUILD_CONFIG = debug
+ else
+-RUST_TARGET_DIR = target/release
++RUST_BUILD_CONFIG = release
+ endif
+
ifeq ($(uname_S),Windows)
- EXTLIBS += -luserenv
+-RUST_LIB = $(RUST_TARGET_DIR)/gitcore.lib
++RUST_LIB_NAME = gitcore.lib
+ else
+-RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
++RUST_LIB_NAME = libgitcore.a
++endif
++RUST_LIB = target/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME)
endif
+
+ GITLIBS = common-main.o $(LIB_FILE)
+@@ Makefile: scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
+ $(LIB_FILE): $(LIB_OBJS)
+ $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
+
++ifndef NO_RUST
++ifeq ($(RUST_TARGETS),)
+ $(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
+ $(QUIET_CARGO)cargo build $(CARGO_ARGS)
++else
++ifneq ($(words $(RUST_TARGETS)),1)
++ifneq ($(uname_S),Darwin)
++$(error Building universal Rust libraries requires macOS (lipo is not available on $(uname_S)))
++endif
++endif
++
++RUST_MEMBER_LIBS = $(foreach target,$(RUST_TARGETS),target/$(target)/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME))
++$(RUST_MEMBER_LIBS): target/%/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
++ $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
++
++$(RUST_LIB): $(RUST_MEMBER_LIBS)
++ $(QUIET_GEN)\
++ if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
++ lipo -create $^ -output $@; \
++ else \
++ cp $< $@; \
++ fi
++endif
+
+ .PHONY: rust
+ rust: $(RUST_LIB)
++endif
+
+ export DEFAULT_EDITOR DEFAULT_PAGER
+
@@ Makefile: $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
$(AR) $(ARFLAGS) $@ $^
-contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
-+contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIBS) GIT-LDFLAGS
++# When Rust is enabled, git-credential-osxkeychain depends on Rust symbols in $(RUST_LIB)
++contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIB) GIT-LDFLAGS
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
-- $(filter %.o,$^) $(LIB_FILE) $(EXTLIBS) -framework Security -framework CoreFoundation
-+ $(filter %.o,$^) $(LIB_FILE) $(RUST_LIBS) $(EXTLIBS) -framework Security -framework CoreFoundation
+ $(filter %.o,$^) $(LIBS) -framework Security -framework CoreFoundation
- contrib/credential/osxkeychain/git-credential-osxkeychain.o: contrib/credential/osxkeychain/git-credential-osxkeychain.c GIT-CFLAGS
- $(QUIET_LINK)$(CC) -o $@ -c $(dep_args) $(compdb_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
Makefile | 44 +++++++++++++++++++++++++++++++++++++++-----
1 file changed, 39 insertions(+), 5 deletions(-)
diff --git a/Makefile b/Makefile
index 1f3f099f5c..8d49ecc897 100644
--- a/Makefile
+++ b/Makefile
@@ -500,6 +500,14 @@ include shared.mak
#
# Building Rust code requires Cargo.
#
+# Define RUST_TARGETS if you want to cross-compile. If left unspecified, it uses
+# the default rust target on the system.
+#
+# On macOS, this supports specifying multiple targets, separated by a space.
+# This will produce a Universal static library using `lipo`.
+#
+# Example: RUST_TARGETS="aarch64-apple-darwin x86_64-apple-darwin"
+#
# == SHA-1 and SHA-256 defines ==
#
# === SHA-1 backend ===
@@ -939,16 +947,19 @@ TEST_SHELL_PATH = $(SHELL_PATH)
LIB_FILE = libgit.a
+ifndef NO_RUST
ifdef DEBUG
-RUST_TARGET_DIR = target/debug
+RUST_BUILD_CONFIG = debug
else
-RUST_TARGET_DIR = target/release
+RUST_BUILD_CONFIG = release
endif
ifeq ($(uname_S),Windows)
-RUST_LIB = $(RUST_TARGET_DIR)/gitcore.lib
+RUST_LIB_NAME = gitcore.lib
else
-RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
+RUST_LIB_NAME = libgitcore.a
+endif
+RUST_LIB = target/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME)
endif
GITLIBS = common-main.o $(LIB_FILE)
@@ -3019,11 +3030,33 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
+ifndef NO_RUST
+ifeq ($(RUST_TARGETS),)
$(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
$(QUIET_CARGO)cargo build $(CARGO_ARGS)
+else
+ifneq ($(words $(RUST_TARGETS)),1)
+ifneq ($(uname_S),Darwin)
+$(error Building universal Rust libraries requires macOS (lipo is not available on $(uname_S)))
+endif
+endif
+
+RUST_MEMBER_LIBS = $(foreach target,$(RUST_TARGETS),target/$(target)/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME))
+$(RUST_MEMBER_LIBS): target/%/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
+ $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
+
+$(RUST_LIB): $(RUST_MEMBER_LIBS)
+ $(QUIET_GEN)\
+ if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
+ lipo -create $^ -output $@; \
+ else \
+ cp $< $@; \
+ fi
+endif
.PHONY: rust
rust: $(RUST_LIB)
+endif
export DEFAULT_EDITOR DEFAULT_PAGER
@@ -4074,7 +4107,8 @@ $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
$(AR) $(ARFLAGS) $@ $^
-contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
+# When Rust is enabled, git-credential-osxkeychain depends on Rust symbols in $(RUST_LIB)
+contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIB) GIT-LDFLAGS
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(LIBS) -framework Security -framework CoreFoundation
base-commit: 43192e7977f5f05138abcdb3212a3f87ab513bef
--
gitgitgadget
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v2] Makefile: link osxkeychain & support universal Rust
2026-07-01 22:01 ` [PATCH v2] Makefile: link osxkeychain & support universal Rust Shardul Natu via GitGitGadget
@ 2026-07-02 1:35 ` Junio C Hamano
2026-07-02 11:50 ` Patrick Steinhardt
2026-07-02 22:22 ` [PATCH v3 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2026-07-02 1:35 UTC (permalink / raw)
To: Shardul Natu via GitGitGadget
Cc: git, Kristoffer Haugsbakk, Shnatu, Koji Nakamaru
"Shardul Natu via GitGitGadget" <gitgitgadget@gmail.com> writes:
> From: Shnatu <snatu@google.com>
> Signed-off-by: Shardul Natu <snatu@google.com>
You'd want to make sure these two match.
> To implement this cleanly without complex shell scripting in recipes:
> 1. We introduce a declarative Make pattern rule (target/%/...) to
> compile each target-specific library slice (e.g.,
> target/aarch64-apple-darwin/...).
> 2. We update the $(RUST_LIB) recipe to depend on the list of
> compiled target-specific member libraries ($(RUST_MEMBER_LIBS)).
> 3. On macOS, if multiple targets are specified, we use lipo to
> combine them into a single Universal static library at
> target/release/libgitcore.a.
> 4. If only one target is specified, we copy it to the standard
> path.
> 5. We enforce that building for multiple targets requires macOS
> (as lipo is only available there), raising a clear make error
> on other platforms.
>
> This is a highly elegant and native Makefile solution that avoids
> complex shell scripting in recipes and fully supports macOS Universal
> Binaries.
You're the second person on this list I saw who calls their own
creation "elegant" ;-).
> +$(RUST_LIB): $(RUST_MEMBER_LIBS)
> + $(QUIET_GEN)\
> + if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
> + lipo -create $^ -output $@; \
> + else \
> + cp $< $@; \
> + fi
> +endif
Do we know that leading directories to $(RUST_LIB) target has
already been created at this point? If not, we may want to have
$(RUST_LIB): $(RUST_MEMBER_LIBS)
+ $(call mkdir_p_parent_template)
$(QUIET_GEN)\
if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
lipo -create $^ -output $@; \
on top.
Thanks for making the build procedure better.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2] Makefile: link osxkeychain & support universal Rust
2026-07-01 22:01 ` [PATCH v2] Makefile: link osxkeychain & support universal Rust Shardul Natu via GitGitGadget
2026-07-02 1:35 ` Junio C Hamano
@ 2026-07-02 11:50 ` Patrick Steinhardt
2026-07-02 22:30 ` Shardul Natu
2026-07-03 12:02 ` lipo availability [was: [PATCH v2] Makefile: link osxkeychain & support universal Rust] Ben Knoble
2026-07-02 22:22 ` [PATCH v3 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2 siblings, 2 replies; 27+ messages in thread
From: Patrick Steinhardt @ 2026-07-02 11:50 UTC (permalink / raw)
To: Shardul Natu via GitGitGadget
Cc: git, Kristoffer Haugsbakk, Shnatu, Koji Nakamaru
On Wed, Jul 01, 2026 at 10:01:43PM +0000, Shardul Natu via GitGitGadget wrote:
> From: Shnatu <snatu@google.com>
>
> When Rust is enabled, ensure that the git-credential-osxkeychain
> helper is linked with the necessary Rust libraries.
>
> Also, introduce native support for macOS Universal Binaries
> (multi-architecture builds) in the Git build system by allowing
> the user to specify a list of target triples in the RUST_TARGETS
> environment variable.
These are fundamentally unrelated things, aren't they? So I'd argue they
should be split up into two commits.
I think we could also use an explanation here what the universal binary
buys us for those who are not deeply familiar with the macOS platform.
What are they, and why do we want/need to support them?
> To implement this cleanly without complex shell scripting in recipes:
> 1. We introduce a declarative Make pattern rule (target/%/...) to
> compile each target-specific library slice (e.g.,
> target/aarch64-apple-darwin/...).
> 2. We update the $(RUST_LIB) recipe to depend on the list of
> compiled target-specific member libraries ($(RUST_MEMBER_LIBS)).
> 3. On macOS, if multiple targets are specified, we use lipo to
> combine them into a single Universal static library at
> target/release/libgitcore.a.
> 4. If only one target is specified, we copy it to the standard
> path.
> 5. We enforce that building for multiple targets requires macOS
> (as lipo is only available there), raising a clear make error
> on other platforms.
>
> This is a highly elegant and native Makefile solution that avoids
> complex shell scripting in recipes and fully supports macOS Universal
> Binaries.
As Junio already pointed out this self-praise reads quite weird. I'm
just going to assume that this is AI-generated fluff.
> diff --git a/Makefile b/Makefile
> index 1f3f099f5c..8d49ecc897 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -3019,11 +3030,33 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
> $(LIB_FILE): $(LIB_OBJS)
> $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
>
> +ifndef NO_RUST
> +ifeq ($(RUST_TARGETS),)
> $(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
> $(QUIET_CARGO)cargo build $(CARGO_ARGS)
> +else
> +ifneq ($(words $(RUST_TARGETS)),1)
> +ifneq ($(uname_S),Darwin)
> +$(error Building universal Rust libraries requires macOS (lipo is not available on $(uname_S)))
> +endif
> +endif
> +
> +RUST_MEMBER_LIBS = $(foreach target,$(RUST_TARGETS),target/$(target)/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME))
> +$(RUST_MEMBER_LIBS): target/%/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
>
> + $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
> +
> +$(RUST_LIB): $(RUST_MEMBER_LIBS)
> + $(QUIET_GEN)\
> + if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
> + lipo -create $^ -output $@; \
Can we assume lipo to be generally available on macOS? Also, is it
sufficient to just do this for the library? I would have expected that
binaries would also need some treatment there.
In other words: what does it help us to have the Rust treated this way
if the rest isn't?
Thanks!
Patrick
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v3 0/2] Makefile: link osxkeychain helper against Rust
2026-07-01 22:01 ` [PATCH v2] Makefile: link osxkeychain & support universal Rust Shardul Natu via GitGitGadget
2026-07-02 1:35 ` Junio C Hamano
2026-07-02 11:50 ` Patrick Steinhardt
@ 2026-07-02 22:22 ` Shardul Natu via GitGitGadget
2026-07-02 22:22 ` [PATCH v3 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain Shardul Natu via GitGitGadget
` (2 more replies)
2 siblings, 3 replies; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-07-02 22:22 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Shnatu, Koji Nakamaru
Shardul Natu (2):
Makefile: add $(RUST_LIB) prerequisite to osxkeychain
Makefile: support universal macOS builds via RUST_TARGETS
Makefile | 45 ++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 40 insertions(+), 5 deletions(-)
base-commit: 602f6c329a7d99df269d382df353b4e1bbbbd8aa
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2288%2Fkiranani%2Fnext-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2288/kiranani/next-v3
Pull-Request: https://github.com/git/git/pull/2288
Range-diff vs v2:
-: ---------- > 1: 41de7d391a Makefile: add $(RUST_LIB) prerequisite to osxkeychain
1: 6a11aff909 ! 2: 257f5ef42f Makefile: link osxkeychain & support universal Rust
@@
## Metadata ##
-Author: Shnatu <snatu@google.com>
+Author: Shardul Natu <snatu@google.com>
## Commit message ##
- Makefile: link osxkeychain & support universal Rust
+ Makefile: support universal macOS builds via RUST_TARGETS
- When Rust is enabled, ensure that the git-credential-osxkeychain
- helper is linked with the necessary Rust libraries.
+ On macOS, Universal Binaries contain native executable code for
+ multiple architectures (such as Intel x86_64 and Apple Silicon arm64)
+ bundled into a single file. This is standard practice for macOS
+ distribution and CI packaging (such as internal distribution packages
+ or tooling like Burrito/Homebrew), allowing a single build artifact
+ to run natively across all Macs without Rosetta emulation or
+ maintaining separate packages.
- Also, introduce native support for macOS Universal Binaries
- (multi-architecture builds) in the Git build system by allowing
- the user to specify a list of target triples in the RUST_TARGETS
- environment variable.
+ When building Git C code for multiple architectures on macOS, the
+ Apple toolchain (clang) natively supports universal builds via
+ CFLAGS/LDFLAGS. When "-arch x86_64 -arch arm64" is passed, clang
+ automatically compiles and links universal binaries for all C object
+ files and executables out of the box.
- To implement this cleanly without complex shell scripting in recipes:
- 1. We introduce a declarative Make pattern rule (target/%/...) to
- compile each target-specific library slice (e.g.,
- target/aarch64-apple-darwin/...).
- 2. We update the $(RUST_LIB) recipe to depend on the list of
- compiled target-specific member libraries ($(RUST_MEMBER_LIBS)).
- 3. On macOS, if multiple targets are specified, we use lipo to
- combine them into a single Universal static library at
- target/release/libgitcore.a.
- 4. If only one target is specified, we copy it to the standard
- path.
- 5. We enforce that building for multiple targets requires macOS
- (as lipo is only available there), raising a clear make error
- on other platforms.
+ Cargo and rustc, however, do not support multiple "-arch" flags or
+ emitting universal binaries in a single invocation. Instead, Cargo
+ requires invoking each target triple independently (e.g., passing
+ "--target x86_64-apple-darwin" and "--target aarch64-apple-darwin").
- This is a highly elegant and native Makefile solution that avoids
- complex shell scripting in recipes and fully supports macOS Universal
- Binaries.
+ To bridge this gap when Rust is enabled:
+ 1. Allow specifying space-separated target triples in RUST_TARGETS.
+ 2. Introduce declarative pattern rules (target/%/...) to compile
+ each target-specific library slice via Cargo.
+ 3. On macOS, if multiple targets are specified, use "lipo" (part of
+ the mandatory Xcode Command Line Tools) to combine the resulting
+ static libraries into target/release/libgitcore.a.
+ 4. Ensure target directory creation before invoking lipo via
+ mkdir_p_parent_template.
+
+ Once $(RUST_LIB) is compiled into a universal static archive, the
+ standard C linker seamlessly links it with the C object files to
+ produce universal Git executables.
Signed-off-by: Shardul Natu <snatu@google.com>
@@ Makefile: include shared.mak
# == SHA-1 and SHA-256 defines ==
#
# === SHA-1 backend ===
-@@ Makefile: TEST_SHELL_PATH = $(SHELL_PATH)
-
- LIB_FILE = libgit.a
+@@ Makefile: LIB_FILE = libgit.a
-+ifndef NO_RUST
+ ifndef NO_RUST
ifdef DEBUG
-RUST_TARGET_DIR = target/debug
+RUST_BUILD_CONFIG = debug
@@ Makefile: TEST_SHELL_PATH = $(SHELL_PATH)
else
-RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
+RUST_LIB_NAME = libgitcore.a
-+endif
+ endif
+RUST_LIB = target/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME)
endif
GITLIBS = common-main.o $(LIB_FILE)
-@@ Makefile: scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
- $(LIB_FILE): $(LIB_OBJS)
+@@ Makefile: $(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-+ifndef NO_RUST
+ ifndef NO_RUST
+ifeq ($(RUST_TARGETS),)
$(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
$(QUIET_CARGO)cargo build $(CARGO_ARGS)
@@ Makefile: scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
+ $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
+
+$(RUST_LIB): $(RUST_MEMBER_LIBS)
++ @$(call mkdir_p_parent_template)
+ $(QUIET_GEN)\
+ if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
+ lipo -create $^ -output $@; \
@@ Makefile: scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
.PHONY: rust
rust: $(RUST_LIB)
-+endif
-
- export DEFAULT_EDITOR DEFAULT_PAGER
-
-@@ Makefile: $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
- contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
- $(AR) $(ARFLAGS) $@ $^
-
--contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
-+# When Rust is enabled, git-credential-osxkeychain depends on Rust symbols in $(RUST_LIB)
-+contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIB) GIT-LDFLAGS
- $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
- $(filter %.o,$^) $(LIBS) -framework Security -framework CoreFoundation
-
--
gitgitgadget
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v3 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain
2026-07-02 22:22 ` [PATCH v3 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
@ 2026-07-02 22:22 ` Shardul Natu via GitGitGadget
2026-07-02 22:22 ` [PATCH v3 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
2026-07-04 18:05 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2 siblings, 0 replies; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-07-02 22:22 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Shnatu, Koji Nakamaru, Shardul Natu
From: Shardul Natu <snatu@google.com>
When Rust is enabled, the git-credential-osxkeychain helper depends on
Rust symbols compiled into $(RUST_LIB). While commit 522ea8ef7d
("osxkeychain: fix build with Rust") updated the linker command line to
use $(LIBS), it omitted $(RUST_LIB) from the target prerequisite list.
Without this prerequisite, running a parallel build ("make -j") from a
clean working tree can fail because Make does not know to invoke Cargo
to build libgitcore.a before linking git-credential-osxkeychain.
Add $(RUST_LIB) as a prerequisite dependency to the
git-credential-osxkeychain target.
Additionally, wrap the definitions of $(RUST_LIB) and the "rust" build
target in "ifndef NO_RUST". This ensures that when NO_RUST=1 is
specified, $(RUST_LIB) evaluates to empty, making the Rust dependency a
clean no-op without needing intermediate variables.
Signed-off-by: Shardul Natu <snatu@google.com>
---
Makefile | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 1f3f099f5c..7db38ecce9 100644
--- a/Makefile
+++ b/Makefile
@@ -939,6 +939,7 @@ TEST_SHELL_PATH = $(SHELL_PATH)
LIB_FILE = libgit.a
+ifndef NO_RUST
ifdef DEBUG
RUST_TARGET_DIR = target/debug
else
@@ -950,6 +951,7 @@ RUST_LIB = $(RUST_TARGET_DIR)/gitcore.lib
else
RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
endif
+endif
GITLIBS = common-main.o $(LIB_FILE)
EXTLIBS =
@@ -3019,11 +3021,13 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
+ifndef NO_RUST
$(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
$(QUIET_CARGO)cargo build $(CARGO_ARGS)
.PHONY: rust
rust: $(RUST_LIB)
+endif
export DEFAULT_EDITOR DEFAULT_PAGER
@@ -4074,7 +4078,8 @@ $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
$(AR) $(ARFLAGS) $@ $^
-contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
+# When Rust is enabled, git-credential-osxkeychain depends on Rust symbols in $(RUST_LIB)
+contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIB) GIT-LDFLAGS
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(LIBS) -framework Security -framework CoreFoundation
--
gitgitgadget
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH v3 2/2] Makefile: support universal macOS builds via RUST_TARGETS
2026-07-02 22:22 ` [PATCH v3 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2026-07-02 22:22 ` [PATCH v3 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain Shardul Natu via GitGitGadget
@ 2026-07-02 22:22 ` Shardul Natu via GitGitGadget
2026-07-03 5:36 ` Junio C Hamano
2026-07-04 18:05 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2 siblings, 1 reply; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-07-02 22:22 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Shnatu, Koji Nakamaru, Shardul Natu
From: Shardul Natu <snatu@google.com>
On macOS, Universal Binaries contain native executable code for
multiple architectures (such as Intel x86_64 and Apple Silicon arm64)
bundled into a single file. This is standard practice for macOS
distribution and CI packaging (such as internal distribution packages
or tooling like Burrito/Homebrew), allowing a single build artifact
to run natively across all Macs without Rosetta emulation or
maintaining separate packages.
When building Git C code for multiple architectures on macOS, the
Apple toolchain (clang) natively supports universal builds via
CFLAGS/LDFLAGS. When "-arch x86_64 -arch arm64" is passed, clang
automatically compiles and links universal binaries for all C object
files and executables out of the box.
Cargo and rustc, however, do not support multiple "-arch" flags or
emitting universal binaries in a single invocation. Instead, Cargo
requires invoking each target triple independently (e.g., passing
"--target x86_64-apple-darwin" and "--target aarch64-apple-darwin").
To bridge this gap when Rust is enabled:
1. Allow specifying space-separated target triples in RUST_TARGETS.
2. Introduce declarative pattern rules (target/%/...) to compile
each target-specific library slice via Cargo.
3. On macOS, if multiple targets are specified, use "lipo" (part of
the mandatory Xcode Command Line Tools) to combine the resulting
static libraries into target/release/libgitcore.a.
4. Ensure target directory creation before invoking lipo via
mkdir_p_parent_template.
Once $(RUST_LIB) is compiled into a universal static archive, the
standard C linker seamlessly links it with the C object files to
produce universal Git executables.
Signed-off-by: Shardul Natu <snatu@google.com>
---
Makefile | 38 ++++++++++++++++++++++++++++++++++----
1 file changed, 34 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
index 7db38ecce9..e01f989cd0 100644
--- a/Makefile
+++ b/Makefile
@@ -500,6 +500,14 @@ include shared.mak
#
# Building Rust code requires Cargo.
#
+# Define RUST_TARGETS if you want to cross-compile. If left unspecified, it uses
+# the default rust target on the system.
+#
+# On macOS, this supports specifying multiple targets, separated by a space.
+# This will produce a Universal static library using `lipo`.
+#
+# Example: RUST_TARGETS="aarch64-apple-darwin x86_64-apple-darwin"
+#
# == SHA-1 and SHA-256 defines ==
#
# === SHA-1 backend ===
@@ -941,16 +949,17 @@ LIB_FILE = libgit.a
ifndef NO_RUST
ifdef DEBUG
-RUST_TARGET_DIR = target/debug
+RUST_BUILD_CONFIG = debug
else
-RUST_TARGET_DIR = target/release
+RUST_BUILD_CONFIG = release
endif
ifeq ($(uname_S),Windows)
-RUST_LIB = $(RUST_TARGET_DIR)/gitcore.lib
+RUST_LIB_NAME = gitcore.lib
else
-RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
+RUST_LIB_NAME = libgitcore.a
endif
+RUST_LIB = target/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME)
endif
GITLIBS = common-main.o $(LIB_FILE)
@@ -3022,8 +3031,29 @@ $(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
ifndef NO_RUST
+ifeq ($(RUST_TARGETS),)
$(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
$(QUIET_CARGO)cargo build $(CARGO_ARGS)
+else
+ifneq ($(words $(RUST_TARGETS)),1)
+ifneq ($(uname_S),Darwin)
+$(error Building universal Rust libraries requires macOS (lipo is not available on $(uname_S)))
+endif
+endif
+
+RUST_MEMBER_LIBS = $(foreach target,$(RUST_TARGETS),target/$(target)/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME))
+$(RUST_MEMBER_LIBS): target/%/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
+ $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
+
+$(RUST_LIB): $(RUST_MEMBER_LIBS)
+ @$(call mkdir_p_parent_template)
+ $(QUIET_GEN)\
+ if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
+ lipo -create $^ -output $@; \
+ else \
+ cp $< $@; \
+ fi
+endif
.PHONY: rust
rust: $(RUST_LIB)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v2] Makefile: link osxkeychain & support universal Rust
2026-07-02 11:50 ` Patrick Steinhardt
@ 2026-07-02 22:30 ` Shardul Natu
2026-07-03 5:15 ` Patrick Steinhardt
2026-07-03 12:02 ` lipo availability [was: [PATCH v2] Makefile: link osxkeychain & support universal Rust] Ben Knoble
1 sibling, 1 reply; 27+ messages in thread
From: Shardul Natu @ 2026-07-02 22:30 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Shardul Natu via GitGitGadget, git, Kristoffer Haugsbakk, Shnatu,
Koji Nakamaru
> "Shardul Natu via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > From: Shnatu <snatu@google.com>
> > Signed-off-by: Shardul Natu <snatu@google.com>
>
> You'd want to make sure these two match.
Good catch. Done!
> > This is a highly elegant and native Makefile solution that avoids
> > complex shell scripting in recipes and fully supports macOS Universal
> > Binaries.
>
> You're the second person on this list I saw who calls their own
> creation "elegant" ;-).
Removed! It was AI generated description
> Do we know that leading directories to $(RUST_LIB) target has
> already been created at this point? If not, we may want to have
>
> $(RUST_LIB): $(RUST_MEMBER_LIBS)
> + $(call mkdir_p_parent_template)
> $(QUIET_GEN)\
> if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
> lipo -create $^ -output $@; \
>
> on top.
Added $(call mkdir_p_parent_template).
> > When Rust is enabled, ensure that the git-credential-osxkeychain
> > helper is linked with the necessary Rust libraries.
> >
> > Also, introduce native support for macOS Universal Binaries
> > (multi-architecture builds) in the Git build system by allowing
> > the user to specify a list of target triples in the RUST_TARGETS
> > environment variable.
>
> These are fundamentally unrelated things, aren't they? So I'd argue they
> should be split up into two commits.
You're right; these address two fundamentally different
problems. In v3, I have split this into a two commits:
1. Makefile: add $(RUST_LIB) prerequisite to osxkeychain
2. Makefile: support universal macOS builds via RUST_TARGETS
> I think we could also use an explanation here what the universal binary
> buys us for those who are not deeply familiar with the macOS platform.
> What are they, and why do we want/need to support them?
I have added this background to the relevant commit.
> Can we assume lipo to be generally available on macOS? Also, is it
> sufficient to just do this for the library? I would have expected that
> binaries would also need some treatment there.
>
> In other words: what does it help us to have the Rust treated this way
> if the rest isn't?
Yes, "lipo" is part of the Apple Xcode CLT, which
is already a hard prerequisite for invoking clang or make on macOS.
The reason only Rust needs special treatment in the Makefile is due to
how the respective toolchains handle multi-architecture builds:
1. Apple's C toolchain (clang) natively supports universal builds via
CFLAGS and LDFLAGS. When "-arch x86_64 -arch arm64" is passed, clang
automatically compiles and links universal binaries for all C object
files and executables out of the box.
2. Cargo and rustc, however, do not support multiple "-arch" flags or
emitting universal binaries in a single invocation. Instead, Cargo must
be invoked separately for each target triple ("--target x86_64-apple-darwin"
and "--target aarch64-apple-darwin").
By using "lipo" to combine those target-specific Rust static libraries
into a single universal archive at "target/release/libgitcore.a", we
bridge this gap. Once $(RUST_LIB) is a universal archive, the standard C
linker seamlessly links it with the C object files to produce the final
universal Git executables.
On Thu, Jul 2, 2026 at 4:57 AM Patrick Steinhardt <ps@pks.im> wrote:
>
> On Wed, Jul 01, 2026 at 10:01:43PM +0000, Shardul Natu via GitGitGadget wrote:
> > From: Shnatu <snatu@google.com>
> >
> > When Rust is enabled, ensure that the git-credential-osxkeychain
> > helper is linked with the necessary Rust libraries.
> >
> > Also, introduce native support for macOS Universal Binaries
> > (multi-architecture builds) in the Git build system by allowing
> > the user to specify a list of target triples in the RUST_TARGETS
> > environment variable.
>
> These are fundamentally unrelated things, aren't they? So I'd argue they
> should be split up into two commits.
>
> I think we could also use an explanation here what the universal binary
> buys us for those who are not deeply familiar with the macOS platform.
> What are they, and why do we want/need to support them?
>
> > To implement this cleanly without complex shell scripting in recipes:
> > 1. We introduce a declarative Make pattern rule (target/%/...) to
> > compile each target-specific library slice (e.g.,
> > target/aarch64-apple-darwin/...).
> > 2. We update the $(RUST_LIB) recipe to depend on the list of
> > compiled target-specific member libraries ($(RUST_MEMBER_LIBS)).
> > 3. On macOS, if multiple targets are specified, we use lipo to
> > combine them into a single Universal static library at
> > target/release/libgitcore.a.
> > 4. If only one target is specified, we copy it to the standard
> > path.
> > 5. We enforce that building for multiple targets requires macOS
> > (as lipo is only available there), raising a clear make error
> > on other platforms.
> >
> > This is a highly elegant and native Makefile solution that avoids
> > complex shell scripting in recipes and fully supports macOS Universal
> > Binaries.
>
> As Junio already pointed out this self-praise reads quite weird. I'm
> just going to assume that this is AI-generated fluff.
>
> > diff --git a/Makefile b/Makefile
> > index 1f3f099f5c..8d49ecc897 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -3019,11 +3030,33 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
> > $(LIB_FILE): $(LIB_OBJS)
> > $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
> >
> > +ifndef NO_RUST
> > +ifeq ($(RUST_TARGETS),)
> > $(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
> > $(QUIET_CARGO)cargo build $(CARGO_ARGS)
> > +else
> > +ifneq ($(words $(RUST_TARGETS)),1)
> > +ifneq ($(uname_S),Darwin)
> > +$(error Building universal Rust libraries requires macOS (lipo is not available on $(uname_S)))
> > +endif
> > +endif
> > +
> > +RUST_MEMBER_LIBS = $(foreach target,$(RUST_TARGETS),target/$(target)/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME))
> > +$(RUST_MEMBER_LIBS): target/%/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
> >
> > + $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
> > +
> > +$(RUST_LIB): $(RUST_MEMBER_LIBS)
> > + $(QUIET_GEN)\
> > + if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
> > + lipo -create $^ -output $@; \
>
> Can we assume lipo to be generally available on macOS? Also, is it
> sufficient to just do this for the library? I would have expected that
> binaries would also need some treatment there.
>
> In other words: what does it help us to have the Rust treated this way
> if the rest isn't?
>
> Thanks!
>
> Patrick
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2] Makefile: link osxkeychain & support universal Rust
2026-07-02 22:30 ` Shardul Natu
@ 2026-07-03 5:15 ` Patrick Steinhardt
0 siblings, 0 replies; 27+ messages in thread
From: Patrick Steinhardt @ 2026-07-03 5:15 UTC (permalink / raw)
To: Shardul Natu
Cc: Shardul Natu via GitGitGadget, git, Kristoffer Haugsbakk, Shnatu,
Koji Nakamaru
On Thu, Jul 02, 2026 at 03:30:15PM -0700, Shardul Natu wrote:
> > Can we assume lipo to be generally available on macOS? Also, is it
> > sufficient to just do this for the library? I would have expected that
> > binaries would also need some treatment there.
> >
> > In other words: what does it help us to have the Rust treated this way
> > if the rest isn't?
>
> Yes, "lipo" is part of the Apple Xcode CLT, which
> is already a hard prerequisite for invoking clang or make on macOS.
> The reason only Rust needs special treatment in the Makefile is due to
> how the respective toolchains handle multi-architecture builds:
> 1. Apple's C toolchain (clang) natively supports universal builds via
> CFLAGS and LDFLAGS. When "-arch x86_64 -arch arm64" is passed, clang
> automatically compiles and links universal binaries for all C object
> files and executables out of the box.
> 2. Cargo and rustc, however, do not support multiple "-arch" flags or
> emitting universal binaries in a single invocation. Instead, Cargo must
> be invoked separately for each target triple ("--target x86_64-apple-darwin"
> and "--target aarch64-apple-darwin").
>
> By using "lipo" to combine those target-specific Rust static libraries
> into a single universal archive at "target/release/libgitcore.a", we
> bridge this gap. Once $(RUST_LIB) is a universal archive, the standard C
> linker seamlessly links it with the C object files to produce the final
> universal Git executables.
Okay, that makes sense. This information should definitely be part of
the commit message to give reviewers a bit more context.
Thanks!
Patrick
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v3 2/2] Makefile: support universal macOS builds via RUST_TARGETS
2026-07-02 22:22 ` [PATCH v3 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
@ 2026-07-03 5:36 ` Junio C Hamano
2026-07-03 17:37 ` Shardul Natu
0 siblings, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2026-07-03 5:36 UTC (permalink / raw)
To: Shardul Natu via GitGitGadget
Cc: git, Kristoffer Haugsbakk, Shnatu, Koji Nakamaru
"Shardul Natu via GitGitGadget" <gitgitgadget@gmail.com> writes:
> From: Shardul Natu <snatu@google.com>
>
> On macOS, Universal Binaries contain native executable code for
> multiple architectures (such as Intel x86_64 and Apple Silicon arm64)
> bundled into a single file. This is standard practice for macOS
> distribution and CI packaging (such as internal distribution packages
> or tooling like Burrito/Homebrew), allowing a single build artifact
> to run natively across all Macs without Rosetta emulation or
> maintaining separate packages.
>
> When building Git C code for multiple architectures on macOS, the
> Apple toolchain (clang) natively supports universal builds via
> CFLAGS/LDFLAGS. When "-arch x86_64 -arch arm64" is passed, clang
> automatically compiles and links universal binaries for all C object
> files and executables out of the box.
>
> Cargo and rustc, however, do not support multiple "-arch" flags or
> emitting universal binaries in a single invocation. Instead, Cargo
> requires invoking each target triple independently (e.g., passing
> "--target x86_64-apple-darwin" and "--target aarch64-apple-darwin").
This is much easier to understand for those of us unfamiliar with
the macOS ecosystem. Very much appreciated.
> +$(RUST_LIB): $(RUST_MEMBER_LIBS)
> + @$(call mkdir_p_parent_template)
The leading @ is a bit curious because among ~20 existing use of
this pattern, nobody adds it to squelch "mkdir -p". In fact, the
macro uses the standard pattern to define $(QUIET_MKDIR_P_PARENT)
that does the squelching when $(V) is unset.
> + $(QUIET_GEN)\
> + if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
Recipe parts in our Makefile that are written in bourne shell, the
CodingGuidelines apply.
$ git grep -n -e 'if \[' ':(glob)**/Makefile'
gives empty. Probably,
if test $(words $(RUST_TARGETS)) -gt 1; \
then \
would fit better.
> + lipo -create $^ -output $@; \
> + else \
> + cp $< $@; \
> + fi
> +endif
>
> .PHONY: rust
> rust: $(RUST_LIB)
Other than that, looking good.
Thanks.
^ permalink raw reply [flat|nested] 27+ messages in thread
* lipo availability [was: [PATCH v2] Makefile: link osxkeychain & support universal Rust]
2026-07-02 11:50 ` Patrick Steinhardt
2026-07-02 22:30 ` Shardul Natu
@ 2026-07-03 12:02 ` Ben Knoble
1 sibling, 0 replies; 27+ messages in thread
From: Ben Knoble @ 2026-07-03 12:02 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Shardul Natu via GitGitGadget, git, Kristoffer Haugsbakk, Shnatu,
Koji Nakamaru
> Le 2 juil. 2026 à 07:57, Patrick Steinhardt <ps@pks.im> a écrit :
>
> On Wed, Jul 01, 2026 at 10:01:43PM +0000, Shardul Natu via GitGitGadget wrote:
>> From: Shnatu <snatu@google.com>
>>
>> Also, introduce native support for macOS Universal Binaries
>> (multi-architecture builds) in the Git build system by allowing
>> the user to specify a list of target triples in the RUST_TARGETS
>> environment variable.
>
>> 3. On macOS, if multiple targets are specified, we use lipo to
>> combine them into a single Universal static library at
>> target/release/libgitcore.a.
>>
>
>> diff --git a/Makefile b/Makefile
>> index 1f3f099f5c..8d49ecc897 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -3019,11 +3030,33 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
>> $(LIB_FILE): $(LIB_OBJS)
>> $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
>>
>> +ifndef NO_RUST
>> +ifeq ($(RUST_TARGETS),)
>> $(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
>> $(QUIET_CARGO)cargo build $(CARGO_ARGS)
>> +else
>> +ifneq ($(words $(RUST_TARGETS)),1)
>> +ifneq ($(uname_S),Darwin)
>> +$(error Building universal Rust libraries requires macOS (lipo is not available on $(uname_S)))
>> +endif
>> +endif
>> +
>> +RUST_MEMBER_LIBS = $(foreach target,$(RUST_TARGETS),target/$(target)/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME))
>> +$(RUST_MEMBER_LIBS): target/%/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
>>
>> + $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
>> +
>> +$(RUST_LIB): $(RUST_MEMBER_LIBS)
>> + $(QUIET_GEN)\
>> + if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
>> + lipo -create $^ -output $@; \
>
> Can we assume lipo to be generally available on macOS?
From my digging, universal binaries to support the PowerPC transition to Intel have been available since Xcode 2.1 from 2005 (whose release notes, if they ever existed, have been impossible for me to find). Of course for modern (Universal Binary 2) formats, you will need newer Xcode: the format was announced in 2020, so I suspect Xcode 12 is a minimum but not necessarily sufficient version. I have not been able to find a release note specific to UB2, though in 12.2 there is mention of both universal binaries and the arm architecture. Apple’s announcement [1] supports the argument for v12.
[1]: https://www.apple.com/au/newsroom/2020/06/apple-announces-mac-transition-to-apple-silicon/
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v3 2/2] Makefile: support universal macOS builds via RUST_TARGETS
2026-07-03 5:36 ` Junio C Hamano
@ 2026-07-03 17:37 ` Shardul Natu
0 siblings, 0 replies; 27+ messages in thread
From: Shardul Natu @ 2026-07-03 17:37 UTC (permalink / raw)
To: Junio C Hamano
Cc: Shardul Natu via GitGitGadget, git, Kristoffer Haugsbakk,
Koji Nakamaru
> > +$(RUST_LIB): $(RUST_MEMBER_LIBS)
> > + @$(call mkdir_p_parent_template)
>
> The leading @ is a bit curious because among ~20 existing use of
> this pattern, nobody adds it to squelch "mkdir -p". In fact, the
> macro uses the standard pattern to define $(QUIET_MKDIR_P_PARENT)
> that does the squelching when $(V) is unset.
Done!
> Recipe parts in our Makefile that are written in bourne shell, the
> CodingGuidelines apply.
>
> $ git grep -n -e 'if \[' ':(glob)**/Makefile'
>
> gives empty. Probably,
>
> if test $(words $(RUST_TARGETS)) -gt 1; \
> then \
>
> would fit better.
Thank you for pointing out the CodingGuidelines rule for Bourne shell
snippets in Makefiles. I have updated the condition from "if [" to "if
test".
Thanks,
Shardul
On Thu, Jul 2, 2026 at 10:36 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> "Shardul Natu via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > From: Shardul Natu <snatu@google.com>
> >
> > On macOS, Universal Binaries contain native executable code for
> > multiple architectures (such as Intel x86_64 and Apple Silicon arm64)
> > bundled into a single file. This is standard practice for macOS
> > distribution and CI packaging (such as internal distribution packages
> > or tooling like Burrito/Homebrew), allowing a single build artifact
> > to run natively across all Macs without Rosetta emulation or
> > maintaining separate packages.
> >
> > When building Git C code for multiple architectures on macOS, the
> > Apple toolchain (clang) natively supports universal builds via
> > CFLAGS/LDFLAGS. When "-arch x86_64 -arch arm64" is passed, clang
> > automatically compiles and links universal binaries for all C object
> > files and executables out of the box.
> >
> > Cargo and rustc, however, do not support multiple "-arch" flags or
> > emitting universal binaries in a single invocation. Instead, Cargo
> > requires invoking each target triple independently (e.g., passing
> > "--target x86_64-apple-darwin" and "--target aarch64-apple-darwin").
>
> This is much easier to understand for those of us unfamiliar with
> the macOS ecosystem. Very much appreciated.
>
> > +$(RUST_LIB): $(RUST_MEMBER_LIBS)
> > + @$(call mkdir_p_parent_template)
>
> The leading @ is a bit curious because among ~20 existing use of
> this pattern, nobody adds it to squelch "mkdir -p". In fact, the
> macro uses the standard pattern to define $(QUIET_MKDIR_P_PARENT)
> that does the squelching when $(V) is unset.
>
> > + $(QUIET_GEN)\
> > + if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
>
> Recipe parts in our Makefile that are written in bourne shell, the
> CodingGuidelines apply.
>
> $ git grep -n -e 'if \[' ':(glob)**/Makefile'
>
> gives empty. Probably,
>
> if test $(words $(RUST_TARGETS)) -gt 1; \
> then \
>
> would fit better.
>
> > + lipo -create $^ -output $@; \
> > + else \
> > + cp $< $@; \
> > + fi
> > +endif
> >
> > .PHONY: rust
> > rust: $(RUST_LIB)
>
> Other than that, looking good.
>
> Thanks.
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust
2026-07-02 22:22 ` [PATCH v3 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2026-07-02 22:22 ` [PATCH v3 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain Shardul Natu via GitGitGadget
2026-07-02 22:22 ` [PATCH v3 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
@ 2026-07-04 18:05 ` Shardul Natu via GitGitGadget
2026-07-04 18:05 ` [PATCH v4 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain Shardul Natu via GitGitGadget
` (3 more replies)
2 siblings, 4 replies; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-07-04 18:05 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Shardul Natu, Koji Nakamaru
This series improves macOS build reliability and distribution support when
Rust is enabled in the Git build system. It addresses two distinct
challenges: a parallel build race condition in git-credential-osxkeychain
and support for macOS Universal Binaries (multi-architecture distribution).
Why This Series is Needed
=========================
1. Parallel Build Race Condition ("make -j"): While commit 522ea8ef7d
("osxkeychain: fix build with Rust") updated the link command for
git-credential-osxkeychain to pass $(LIBS), it omitted $(RUST_LIB) from
the target prerequisite list. When running a parallel build ("make -j")
from a clean working tree, Make can attempt to link
git-credential-osxkeychain before Cargo has finished compiling
libgitcore.a, causing linker failures.
2. macOS Universal Binary (lipo) Support: On macOS, Universal Binaries
bundle native executable code for multiple architectures (Intel x86_64
and Apple Silicon arm64) into a single file. This is standard practice
for macOS distribution and CI packaging (such as Burrito, Homebrew, and
Git's macOS CI runners), allowing a single artifact to run natively
across all Macs without Rosetta translation.
While Apple's C compiler (clang) natively supports universal builds by
passing "-arch x86_64 -arch arm64" in CFLAGS and LDFLAGS, Cargo and rustc do
not support multiple "-arch" flags in a single invocation. Instead, Cargo
must be invoked separately for each target triple ("--target
x86_64-apple-darwin" and "--target aarch64-apple-darwin"). This series
bridges that gap.
Overview of Patches
===================
* Patch 1: Makefile: add $(RUST_LIB) prerequisite to osxkeychain Adds
$(RUST_LIB) as a prerequisite dependency to the osxkeychain target,
eliminating the parallel build race condition. Additionally, wraps the
definitions of $(RUST_LIB) and the "rust" build target in "ifndef
NO_RUST" so that disabling Rust cleanly makes the dependency a no-op.
* Patch 2: Makefile: support universal macOS builds via RUST_TARGETS Allows
users to specify space-separated target triples in RUST_TARGETS.
Introduces declarative pattern rules (target/%/...) to compile each
target slice via Cargo, and uses "lipo" (part of the mandatory Xcode
Command Line Tools) to combine the resulting static archives into a
universal library at target/release/libgitcore.a. Uses
mkdir_p_parent_template to guarantee directory creation before lipo.
Changes since v2:
* Split the original combined commit into a two-patch series to separate
prerequisite bug fixes from Universal Binary features.
* Added $(call mkdir_p_parent_template) prior to invoking lipo to guarantee
that parent target directories exist.
*
Shardul Natu (2):
Makefile: add $(RUST_LIB) prerequisite to osxkeychain
Makefile: support universal macOS builds via RUST_TARGETS
Makefile | 46 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 41 insertions(+), 5 deletions(-)
base-commit: 602f6c329a7d99df269d382df353b4e1bbbbd8aa
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2288%2Fkiranani%2Fnext-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2288/kiranani/next-v4
Pull-Request: https://github.com/git/git/pull/2288
Range-diff vs v3:
1: 41de7d391a = 1: 41de7d391a Makefile: add $(RUST_LIB) prerequisite to osxkeychain
2: 257f5ef42f ! 2: 88fc2e0bd8 Makefile: support universal macOS builds via RUST_TARGETS
@@ Makefile: $(LIB_FILE): $(LIB_OBJS)
+ $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
+
+$(RUST_LIB): $(RUST_MEMBER_LIBS)
-+ @$(call mkdir_p_parent_template)
++ $(call mkdir_p_parent_template)
+ $(QUIET_GEN)\
-+ if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
++ if test $(words $(RUST_TARGETS)) -gt 1; \
++ then \
+ lipo -create $^ -output $@; \
+ else \
+ cp $< $@; \
--
gitgitgadget
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v4 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain
2026-07-04 18:05 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
@ 2026-07-04 18:05 ` Shardul Natu via GitGitGadget
2026-07-06 10:49 ` Patrick Steinhardt
2026-07-04 18:05 ` [PATCH v4 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
` (2 subsequent siblings)
3 siblings, 1 reply; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-07-04 18:05 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Shardul Natu, Koji Nakamaru, Shardul Natu
From: Shardul Natu <snatu@google.com>
When Rust is enabled, the git-credential-osxkeychain helper depends on
Rust symbols compiled into $(RUST_LIB). While commit 522ea8ef7d
("osxkeychain: fix build with Rust") updated the linker command line to
use $(LIBS), it omitted $(RUST_LIB) from the target prerequisite list.
Without this prerequisite, running a parallel build ("make -j") from a
clean working tree can fail because Make does not know to invoke Cargo
to build libgitcore.a before linking git-credential-osxkeychain.
Add $(RUST_LIB) as a prerequisite dependency to the
git-credential-osxkeychain target.
Additionally, wrap the definitions of $(RUST_LIB) and the "rust" build
target in "ifndef NO_RUST". This ensures that when NO_RUST=1 is
specified, $(RUST_LIB) evaluates to empty, making the Rust dependency a
clean no-op without needing intermediate variables.
Signed-off-by: Shardul Natu <snatu@google.com>
---
Makefile | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 1f3f099f5c..7db38ecce9 100644
--- a/Makefile
+++ b/Makefile
@@ -939,6 +939,7 @@ TEST_SHELL_PATH = $(SHELL_PATH)
LIB_FILE = libgit.a
+ifndef NO_RUST
ifdef DEBUG
RUST_TARGET_DIR = target/debug
else
@@ -950,6 +951,7 @@ RUST_LIB = $(RUST_TARGET_DIR)/gitcore.lib
else
RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
endif
+endif
GITLIBS = common-main.o $(LIB_FILE)
EXTLIBS =
@@ -3019,11 +3021,13 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
+ifndef NO_RUST
$(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
$(QUIET_CARGO)cargo build $(CARGO_ARGS)
.PHONY: rust
rust: $(RUST_LIB)
+endif
export DEFAULT_EDITOR DEFAULT_PAGER
@@ -4074,7 +4078,8 @@ $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
$(AR) $(ARFLAGS) $@ $^
-contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
+# When Rust is enabled, git-credential-osxkeychain depends on Rust symbols in $(RUST_LIB)
+contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIB) GIT-LDFLAGS
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(LIBS) -framework Security -framework CoreFoundation
--
gitgitgadget
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH v4 2/2] Makefile: support universal macOS builds via RUST_TARGETS
2026-07-04 18:05 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2026-07-04 18:05 ` [PATCH v4 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain Shardul Natu via GitGitGadget
@ 2026-07-04 18:05 ` Shardul Natu via GitGitGadget
2026-07-06 10:49 ` Patrick Steinhardt
2026-07-05 4:08 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Junio C Hamano
2026-07-06 17:14 ` [PATCH v5 " Shardul Natu via GitGitGadget
3 siblings, 1 reply; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-07-04 18:05 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Shardul Natu, Koji Nakamaru, Shardul Natu
From: Shardul Natu <snatu@google.com>
On macOS, Universal Binaries contain native executable code for
multiple architectures (such as Intel x86_64 and Apple Silicon arm64)
bundled into a single file. This is standard practice for macOS
distribution and CI packaging (such as internal distribution packages
or tooling like Burrito/Homebrew), allowing a single build artifact
to run natively across all Macs without Rosetta emulation or
maintaining separate packages.
When building Git C code for multiple architectures on macOS, the
Apple toolchain (clang) natively supports universal builds via
CFLAGS/LDFLAGS. When "-arch x86_64 -arch arm64" is passed, clang
automatically compiles and links universal binaries for all C object
files and executables out of the box.
Cargo and rustc, however, do not support multiple "-arch" flags or
emitting universal binaries in a single invocation. Instead, Cargo
requires invoking each target triple independently (e.g., passing
"--target x86_64-apple-darwin" and "--target aarch64-apple-darwin").
To bridge this gap when Rust is enabled:
1. Allow specifying space-separated target triples in RUST_TARGETS.
2. Introduce declarative pattern rules (target/%/...) to compile
each target-specific library slice via Cargo.
3. On macOS, if multiple targets are specified, use "lipo" (part of
the mandatory Xcode Command Line Tools) to combine the resulting
static libraries into target/release/libgitcore.a.
4. Ensure target directory creation before invoking lipo via
mkdir_p_parent_template.
Once $(RUST_LIB) is compiled into a universal static archive, the
standard C linker seamlessly links it with the C object files to
produce universal Git executables.
Signed-off-by: Shardul Natu <snatu@google.com>
---
Makefile | 39 +++++++++++++++++++++++++++++++++++----
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
index 7db38ecce9..ecada0acb4 100644
--- a/Makefile
+++ b/Makefile
@@ -500,6 +500,14 @@ include shared.mak
#
# Building Rust code requires Cargo.
#
+# Define RUST_TARGETS if you want to cross-compile. If left unspecified, it uses
+# the default rust target on the system.
+#
+# On macOS, this supports specifying multiple targets, separated by a space.
+# This will produce a Universal static library using `lipo`.
+#
+# Example: RUST_TARGETS="aarch64-apple-darwin x86_64-apple-darwin"
+#
# == SHA-1 and SHA-256 defines ==
#
# === SHA-1 backend ===
@@ -941,16 +949,17 @@ LIB_FILE = libgit.a
ifndef NO_RUST
ifdef DEBUG
-RUST_TARGET_DIR = target/debug
+RUST_BUILD_CONFIG = debug
else
-RUST_TARGET_DIR = target/release
+RUST_BUILD_CONFIG = release
endif
ifeq ($(uname_S),Windows)
-RUST_LIB = $(RUST_TARGET_DIR)/gitcore.lib
+RUST_LIB_NAME = gitcore.lib
else
-RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
+RUST_LIB_NAME = libgitcore.a
endif
+RUST_LIB = target/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME)
endif
GITLIBS = common-main.o $(LIB_FILE)
@@ -3022,8 +3031,30 @@ $(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
ifndef NO_RUST
+ifeq ($(RUST_TARGETS),)
$(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
$(QUIET_CARGO)cargo build $(CARGO_ARGS)
+else
+ifneq ($(words $(RUST_TARGETS)),1)
+ifneq ($(uname_S),Darwin)
+$(error Building universal Rust libraries requires macOS (lipo is not available on $(uname_S)))
+endif
+endif
+
+RUST_MEMBER_LIBS = $(foreach target,$(RUST_TARGETS),target/$(target)/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME))
+$(RUST_MEMBER_LIBS): target/%/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
+ $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
+
+$(RUST_LIB): $(RUST_MEMBER_LIBS)
+ $(call mkdir_p_parent_template)
+ $(QUIET_GEN)\
+ if test $(words $(RUST_TARGETS)) -gt 1; \
+ then \
+ lipo -create $^ -output $@; \
+ else \
+ cp $< $@; \
+ fi
+endif
.PHONY: rust
rust: $(RUST_LIB)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust
2026-07-04 18:05 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2026-07-04 18:05 ` [PATCH v4 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain Shardul Natu via GitGitGadget
2026-07-04 18:05 ` [PATCH v4 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
@ 2026-07-05 4:08 ` Junio C Hamano
2026-07-05 17:38 ` Shardul Natu
2026-07-06 17:14 ` [PATCH v5 " Shardul Natu via GitGitGadget
3 siblings, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2026-07-05 4:08 UTC (permalink / raw)
To: Shardul Natu via GitGitGadget
Cc: git, Kristoffer Haugsbakk, Shardul Natu, Koji Nakamaru
"Shardul Natu via GitGitGadget" <gitgitgadget@gmail.com> writes:
> Changes since v2:
>
> * Split the original combined commit into a two-patch series to separate
> prerequisite bug fixes from Universal Binary features.
This was addressing Patrick's comment, which was already done in v3;
hopefully that is now settled?
> * Added $(call mkdir_p_parent_template) prior to invoking lipo to guarantee
> that parent target directories exist.
Obviously correct ;-).
> *
>
It is a mystery what the third bullet point was ;-)
The changes relative to v3 (which I looked at) look good now.
Thanks.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust
2026-07-05 4:08 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Junio C Hamano
@ 2026-07-05 17:38 ` Shardul Natu
0 siblings, 0 replies; 27+ messages in thread
From: Shardul Natu @ 2026-07-05 17:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: Shardul Natu via GitGitGadget, git, Kristoffer Haugsbakk,
Koji Nakamaru
> This was addressing Patrick's comment, which was already done in v3;
> hopefully that is now settled?
Sorry, updated the description of the PR!
> It is a mystery what the third bullet point was ;-)
Remnant of thoughts! Removed!!
Thank you,
Shardul
On Sat, Jul 4, 2026 at 9:08 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> "Shardul Natu via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > Changes since v2:
> >
> > * Split the original combined commit into a two-patch series to separate
> > prerequisite bug fixes from Universal Binary features.
>
> This was addressing Patrick's comment, which was already done in v3;
> hopefully that is now settled?
>
> > * Added $(call mkdir_p_parent_template) prior to invoking lipo to guarantee
> > that parent target directories exist.
>
> Obviously correct ;-).
>
> > *
> >
>
> It is a mystery what the third bullet point was ;-)
>
> The changes relative to v3 (which I looked at) look good now.
>
> Thanks.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v4 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain
2026-07-04 18:05 ` [PATCH v4 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain Shardul Natu via GitGitGadget
@ 2026-07-06 10:49 ` Patrick Steinhardt
0 siblings, 0 replies; 27+ messages in thread
From: Patrick Steinhardt @ 2026-07-06 10:49 UTC (permalink / raw)
To: Shardul Natu via GitGitGadget
Cc: git, Kristoffer Haugsbakk, Shardul Natu, Koji Nakamaru
On Sat, Jul 04, 2026 at 06:05:54PM +0000, Shardul Natu via GitGitGadget wrote:
> From: Shardul Natu <snatu@google.com>
> diff --git a/Makefile b/Makefile
> index 1f3f099f5c..7db38ecce9 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -4074,7 +4078,8 @@ $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
> contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
> $(AR) $(ARFLAGS) $@ $^
>
> -contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
> +# When Rust is enabled, git-credential-osxkeychain depends on Rust symbols in $(RUST_LIB)
> +contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIB) GIT-LDFLAGS
> $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
> $(filter %.o,$^) $(LIBS) -framework Security -framework CoreFoundation
I was wondering why no other target declares an explicit dependency on
RUST_LIB. As it turns out, all the other targets that link "$(LIBS)" all
already depend on "$(GITLIBS)", which includes both "$(LIB_FILE)" and
"$(RUST_LIB)". So shouldn't we also depend depend on "$(GITLIBS)" here
instead of on either of the other two variables?
Patrick
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v4 2/2] Makefile: support universal macOS builds via RUST_TARGETS
2026-07-04 18:05 ` [PATCH v4 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
@ 2026-07-06 10:49 ` Patrick Steinhardt
0 siblings, 0 replies; 27+ messages in thread
From: Patrick Steinhardt @ 2026-07-06 10:49 UTC (permalink / raw)
To: Shardul Natu via GitGitGadget
Cc: git, Kristoffer Haugsbakk, Shardul Natu, Koji Nakamaru
On Sat, Jul 04, 2026 at 06:05:55PM +0000, Shardul Natu via GitGitGadget wrote:
> From: Shardul Natu <snatu@google.com>
>
> On macOS, Universal Binaries contain native executable code for
> multiple architectures (such as Intel x86_64 and Apple Silicon arm64)
> bundled into a single file. This is standard practice for macOS
> distribution and CI packaging (such as internal distribution packages
> or tooling like Burrito/Homebrew), allowing a single build artifact
> to run natively across all Macs without Rosetta emulation or
> maintaining separate packages.
>
> When building Git C code for multiple architectures on macOS, the
> Apple toolchain (clang) natively supports universal builds via
> CFLAGS/LDFLAGS. When "-arch x86_64 -arch arm64" is passed, clang
> automatically compiles and links universal binaries for all C object
> files and executables out of the box.
>
> Cargo and rustc, however, do not support multiple "-arch" flags or
> emitting universal binaries in a single invocation. Instead, Cargo
> requires invoking each target triple independently (e.g., passing
> "--target x86_64-apple-darwin" and "--target aarch64-apple-darwin").
>
> To bridge this gap when Rust is enabled:
> 1. Allow specifying space-separated target triples in RUST_TARGETS.
> 2. Introduce declarative pattern rules (target/%/...) to compile
> each target-specific library slice via Cargo.
> 3. On macOS, if multiple targets are specified, use "lipo" (part of
> the mandatory Xcode Command Line Tools) to combine the resulting
> static libraries into target/release/libgitcore.a.
> 4. Ensure target directory creation before invoking lipo via
> mkdir_p_parent_template.
Nit: The last item really is quite uninteresting in the bigger scheme of
things.
> Once $(RUST_LIB) is compiled into a universal static archive, the
> standard C linker seamlessly links it with the C object files to
> produce universal Git executables.
Okay, this overall reads a lot better now.
> diff --git a/Makefile b/Makefile
> index 7db38ecce9..ecada0acb4 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -500,6 +500,14 @@ include shared.mak
> #
> # Building Rust code requires Cargo.
> #
> +# Define RUST_TARGETS if you want to cross-compile. If left unspecified, it uses
> +# the default rust target on the system.
s/rust/Rust/
> @@ -3022,8 +3031,30 @@ $(LIB_FILE): $(LIB_OBJS)
> $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
>
> ifndef NO_RUST
> +ifeq ($(RUST_TARGETS),)
> $(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
> $(QUIET_CARGO)cargo build $(CARGO_ARGS)
> +else
> +ifneq ($(words $(RUST_TARGETS)),1)
> +ifneq ($(uname_S),Darwin)
> +$(error Building universal Rust libraries requires macOS (lipo is not available on $(uname_S)))
> +endif
> +endif
> +
> +RUST_MEMBER_LIBS = $(foreach target,$(RUST_TARGETS),target/$(target)/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME))
> +$(RUST_MEMBER_LIBS): target/%/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
> + $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
With this we now have both:
- target/$ARCH/$BUILD_CONFIG/
- target/$BUILD_CONFIG/
Is there any reason why we have to have those two different layouts
instead of swapping the order in the first item so that all artifacts
are in "target/$BUILD_CONFIG/"? Essentially, what I'm proposing instead
is:
- "target/$BUILD_CONFIG/" for the final universal executable.
- "target/$BUILD_CONFIG/$ARCH" for the per-arch artifacts.
Patrick
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v5 0/2] Makefile: link osxkeychain helper against Rust
2026-07-04 18:05 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
` (2 preceding siblings ...)
2026-07-05 4:08 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Junio C Hamano
@ 2026-07-06 17:14 ` Shardul Natu via GitGitGadget
2026-07-06 17:14 ` [PATCH v5 1/2] Makefile: add $(GITLIBS) prerequisite to osxkeychain Shardul Natu via GitGitGadget
2026-07-06 17:14 ` [PATCH v5 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
3 siblings, 2 replies; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-07-06 17:14 UTC (permalink / raw)
To: git
Cc: Kristoffer Haugsbakk, Shardul Natu, Koji Nakamaru,
Patrick Steinhardt, Shardul Natu, Ben Knoble
This series improves macOS build reliability and distribution support when
Rust is enabled in the Git build system. It addresses two distinct
challenges: a parallel build race condition in git-credential-osxkeychain
and support for macOS Universal Binaries (multi-architecture distribution).
Why This Series is Needed
=========================
1. Parallel Build Race Condition (make -j): While commit 522ea8ef7d
("osxkeychain: fix build with Rust") updated the link command for
git-credential-osxkeychain to pass $(LIBS), it omitted $(RUST_LIB) from
the target prerequisite list. When running a parallel build (make -j)
from a clean working tree, Make can attempt to link
git-credential-osxkeychain before Cargo has finished compiling
libgitcore.a, causing linker failures.
2. macOS Universal Binary (lipo) Support: On macOS, Universal Binaries
bundle native executable code for multiple architectures (Intel x86_64
and Apple Silicon arm64) into a single file. This is standard practice
for macOS distribution and CI packaging (such as Burrito, Homebrew, and
Git's macOS CI runners), allowing a single artifact to run natively
across all Macs without Rosetta translation.
While Apple's C compiler (clang) natively supports universal builds by
passing -arch x86_64 -arch arm64 in CFLAGS and LDFLAGS, Cargo and rustc do
not support multiple -arch flags in a single invocation. Instead, Cargo must
be invoked separately for each target triple (--target x86_64-apple-darwin
and --target aarch64-apple-darwin). This series bridges that gap.
Overview of Patches
===================
* Patch 1: Makefile: add $(RUST_LIB) prerequisite to osxkeychain Adds
$(RUST_LIB) as a prerequisite dependency to the osxkeychain target,
eliminating the parallel build race condition. Additionally, wraps the
definitions of $(RUST_LIB) and the rust build target in ifndef NO_RUST so
that disabling Rust cleanly makes the dependency a no-op.
* Patch 2: Makefile: support universal macOS builds via RUST_TARGETS Allows
users to specify space-separated target triples in RUST_TARGETS.
Introduces declarative pattern rules (target/%/...) to compile each
target slice via Cargo, and uses lipo (part of the mandatory Xcode
Command Line Tools) to combine the resulting static archives into a
universal library at target/release/libgitcore.a. Uses
mkdir_p_parent_template to guarantee directory creation before lipo.
Changes since v4:
* Changed the osxkeychain prerequisite dependency from $(LIB_FILE)
$(RUST_LIB) to $(GITLIBS) to match the canonical prerequisite pattern
used by all other core Git targets linking $(LIBS).
Changes since v3:
* Removed leading @ from $(call mkdir_p_parent_template) so it relies on
the built-in $(QUIET_MKDIR_P_PARENT) behavior, matching existing Makefile
conventions.
* Replaced if [ with if test in Bourne shell recipe snippets to strictly
adhere to the project's CodingGuidelines.
Changes since v2:
* Split the original combined commit into a two-patch series to separate
prerequisite bug fixes from Universal Binary features.
* Added $(call mkdir_p_parent_template) prior to invoking lipo to guarantee
that parent target directories exist.
Shardul Natu (2):
Makefile: add $(GITLIBS) prerequisite to osxkeychain
Makefile: support universal macOS builds via RUST_TARGETS
Makefile | 46 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 41 insertions(+), 5 deletions(-)
base-commit: 602f6c329a7d99df269d382df353b4e1bbbbd8aa
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2288%2Fkiranani%2Fnext-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2288/kiranani/next-v5
Pull-Request: https://github.com/git/git/pull/2288
Range-diff vs v4:
1: 41de7d391a ! 1: e0bb18ff01 Makefile: add $(RUST_LIB) prerequisite to osxkeychain
@@ Metadata
Author: Shardul Natu <snatu@google.com>
## Commit message ##
- Makefile: add $(RUST_LIB) prerequisite to osxkeychain
+ Makefile: add $(GITLIBS) prerequisite to osxkeychain
When Rust is enabled, the git-credential-osxkeychain helper depends on
Rust symbols compiled into $(RUST_LIB). While commit 522ea8ef7d
@@ Commit message
clean working tree can fail because Make does not know to invoke Cargo
to build libgitcore.a before linking git-credential-osxkeychain.
- Add $(RUST_LIB) as a prerequisite dependency to the
- git-credential-osxkeychain target.
+ All other core Git targets that link $(LIBS) already depend on
+ $(GITLIBS), which bundles common-main.o, $(LIB_FILE), and $(RUST_LIB)
+ when Rust is enabled. Add $(GITLIBS) as a prerequisite dependency to the
+ git-credential-osxkeychain target to make it consistent with the rest of
+ the codebase.
Additionally, wrap the definitions of $(RUST_LIB) and the "rust" build
target in "ifndef NO_RUST". This ensures that when NO_RUST=1 is
@@ Makefile: $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
-contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
+# When Rust is enabled, git-credential-osxkeychain depends on Rust symbols in $(RUST_LIB)
-+contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) $(RUST_LIB) GIT-LDFLAGS
++contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(GITLIBS) GIT-LDFLAGS
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(LIBS) -framework Security -framework CoreFoundation
2: 88fc2e0bd8 ! 2: 66f71fb0d7 Makefile: support universal macOS builds via RUST_TARGETS
@@ Commit message
3. On macOS, if multiple targets are specified, use "lipo" (part of
the mandatory Xcode Command Line Tools) to combine the resulting
static libraries into target/release/libgitcore.a.
- 4. Ensure target directory creation before invoking lipo via
- mkdir_p_parent_template.
Once $(RUST_LIB) is compiled into a universal static archive, the
standard C linker seamlessly links it with the C object files to
@@ Makefile: include shared.mak
# Building Rust code requires Cargo.
#
+# Define RUST_TARGETS if you want to cross-compile. If left unspecified, it uses
-+# the default rust target on the system.
++# the default Rust target on the system.
+#
+# On macOS, this supports specifying multiple targets, separated by a space.
+# This will produce a Universal static library using `lipo`.
--
gitgitgadget
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v5 1/2] Makefile: add $(GITLIBS) prerequisite to osxkeychain
2026-07-06 17:14 ` [PATCH v5 " Shardul Natu via GitGitGadget
@ 2026-07-06 17:14 ` Shardul Natu via GitGitGadget
2026-07-06 17:14 ` [PATCH v5 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
1 sibling, 0 replies; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-07-06 17:14 UTC (permalink / raw)
To: git
Cc: Kristoffer Haugsbakk, Shardul Natu, Koji Nakamaru,
Patrick Steinhardt, Shardul Natu, Ben Knoble, Shardul Natu
From: Shardul Natu <snatu@google.com>
When Rust is enabled, the git-credential-osxkeychain helper depends on
Rust symbols compiled into $(RUST_LIB). While commit 522ea8ef7d
("osxkeychain: fix build with Rust") updated the linker command line to
use $(LIBS), it omitted $(RUST_LIB) from the target prerequisite list.
Without this prerequisite, running a parallel build ("make -j") from a
clean working tree can fail because Make does not know to invoke Cargo
to build libgitcore.a before linking git-credential-osxkeychain.
All other core Git targets that link $(LIBS) already depend on
$(GITLIBS), which bundles common-main.o, $(LIB_FILE), and $(RUST_LIB)
when Rust is enabled. Add $(GITLIBS) as a prerequisite dependency to the
git-credential-osxkeychain target to make it consistent with the rest of
the codebase.
Additionally, wrap the definitions of $(RUST_LIB) and the "rust" build
target in "ifndef NO_RUST". This ensures that when NO_RUST=1 is
specified, $(RUST_LIB) evaluates to empty, making the Rust dependency a
clean no-op without needing intermediate variables.
Signed-off-by: Shardul Natu <snatu@google.com>
---
Makefile | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 1f3f099f5c..7f4be97b90 100644
--- a/Makefile
+++ b/Makefile
@@ -939,6 +939,7 @@ TEST_SHELL_PATH = $(SHELL_PATH)
LIB_FILE = libgit.a
+ifndef NO_RUST
ifdef DEBUG
RUST_TARGET_DIR = target/debug
else
@@ -950,6 +951,7 @@ RUST_LIB = $(RUST_TARGET_DIR)/gitcore.lib
else
RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
endif
+endif
GITLIBS = common-main.o $(LIB_FILE)
EXTLIBS =
@@ -3019,11 +3021,13 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
+ifndef NO_RUST
$(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
$(QUIET_CARGO)cargo build $(CARGO_ARGS)
.PHONY: rust
rust: $(RUST_LIB)
+endif
export DEFAULT_EDITOR DEFAULT_PAGER
@@ -4074,7 +4078,8 @@ $(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
$(AR) $(ARFLAGS) $@ $^
-contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(LIB_FILE) GIT-LDFLAGS
+# When Rust is enabled, git-credential-osxkeychain depends on Rust symbols in $(RUST_LIB)
+contrib/credential/osxkeychain/git-credential-osxkeychain: contrib/credential/osxkeychain/git-credential-osxkeychain.o $(GITLIBS) GIT-LDFLAGS
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(LIBS) -framework Security -framework CoreFoundation
--
gitgitgadget
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH v5 2/2] Makefile: support universal macOS builds via RUST_TARGETS
2026-07-06 17:14 ` [PATCH v5 " Shardul Natu via GitGitGadget
2026-07-06 17:14 ` [PATCH v5 1/2] Makefile: add $(GITLIBS) prerequisite to osxkeychain Shardul Natu via GitGitGadget
@ 2026-07-06 17:14 ` Shardul Natu via GitGitGadget
1 sibling, 0 replies; 27+ messages in thread
From: Shardul Natu via GitGitGadget @ 2026-07-06 17:14 UTC (permalink / raw)
To: git
Cc: Kristoffer Haugsbakk, Shardul Natu, Koji Nakamaru,
Patrick Steinhardt, Shardul Natu, Ben Knoble, Shardul Natu
From: Shardul Natu <snatu@google.com>
On macOS, Universal Binaries contain native executable code for
multiple architectures (such as Intel x86_64 and Apple Silicon arm64)
bundled into a single file. This is standard practice for macOS
distribution and CI packaging (such as internal distribution packages
or tooling like Burrito/Homebrew), allowing a single build artifact
to run natively across all Macs without Rosetta emulation or
maintaining separate packages.
When building Git C code for multiple architectures on macOS, the
Apple toolchain (clang) natively supports universal builds via
CFLAGS/LDFLAGS. When "-arch x86_64 -arch arm64" is passed, clang
automatically compiles and links universal binaries for all C object
files and executables out of the box.
Cargo and rustc, however, do not support multiple "-arch" flags or
emitting universal binaries in a single invocation. Instead, Cargo
requires invoking each target triple independently (e.g., passing
"--target x86_64-apple-darwin" and "--target aarch64-apple-darwin").
To bridge this gap when Rust is enabled:
1. Allow specifying space-separated target triples in RUST_TARGETS.
2. Introduce declarative pattern rules (target/%/...) to compile
each target-specific library slice via Cargo.
3. On macOS, if multiple targets are specified, use "lipo" (part of
the mandatory Xcode Command Line Tools) to combine the resulting
static libraries into target/release/libgitcore.a.
Once $(RUST_LIB) is compiled into a universal static archive, the
standard C linker seamlessly links it with the C object files to
produce universal Git executables.
Signed-off-by: Shardul Natu <snatu@google.com>
---
Makefile | 39 +++++++++++++++++++++++++++++++++++----
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
index 7f4be97b90..335fd056fa 100644
--- a/Makefile
+++ b/Makefile
@@ -500,6 +500,14 @@ include shared.mak
#
# Building Rust code requires Cargo.
#
+# Define RUST_TARGETS if you want to cross-compile. If left unspecified, it uses
+# the default Rust target on the system.
+#
+# On macOS, this supports specifying multiple targets, separated by a space.
+# This will produce a Universal static library using `lipo`.
+#
+# Example: RUST_TARGETS="aarch64-apple-darwin x86_64-apple-darwin"
+#
# == SHA-1 and SHA-256 defines ==
#
# === SHA-1 backend ===
@@ -941,16 +949,17 @@ LIB_FILE = libgit.a
ifndef NO_RUST
ifdef DEBUG
-RUST_TARGET_DIR = target/debug
+RUST_BUILD_CONFIG = debug
else
-RUST_TARGET_DIR = target/release
+RUST_BUILD_CONFIG = release
endif
ifeq ($(uname_S),Windows)
-RUST_LIB = $(RUST_TARGET_DIR)/gitcore.lib
+RUST_LIB_NAME = gitcore.lib
else
-RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
+RUST_LIB_NAME = libgitcore.a
endif
+RUST_LIB = target/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME)
endif
GITLIBS = common-main.o $(LIB_FILE)
@@ -3022,8 +3031,30 @@ $(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
ifndef NO_RUST
+ifeq ($(RUST_TARGETS),)
$(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
$(QUIET_CARGO)cargo build $(CARGO_ARGS)
+else
+ifneq ($(words $(RUST_TARGETS)),1)
+ifneq ($(uname_S),Darwin)
+$(error Building universal Rust libraries requires macOS (lipo is not available on $(uname_S)))
+endif
+endif
+
+RUST_MEMBER_LIBS = $(foreach target,$(RUST_TARGETS),target/$(target)/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME))
+$(RUST_MEMBER_LIBS): target/%/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
+ $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
+
+$(RUST_LIB): $(RUST_MEMBER_LIBS)
+ $(call mkdir_p_parent_template)
+ $(QUIET_GEN)\
+ if test $(words $(RUST_TARGETS)) -gt 1; \
+ then \
+ lipo -create $^ -output $@; \
+ else \
+ cp $< $@; \
+ fi
+endif
.PHONY: rust
rust: $(RUST_LIB)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 27+ messages in thread
end of thread, other threads:[~2026-07-06 17:15 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-05 17:26 [PATCH] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2026-05-05 19:08 ` Kristoffer Haugsbakk
2026-05-07 0:39 ` Shnatu
2026-05-08 2:54 ` Junio C Hamano
2026-05-08 9:33 ` Koji Nakamaru
2026-05-08 17:44 ` Shnatu
2026-07-01 22:01 ` [PATCH v2] Makefile: link osxkeychain & support universal Rust Shardul Natu via GitGitGadget
2026-07-02 1:35 ` Junio C Hamano
2026-07-02 11:50 ` Patrick Steinhardt
2026-07-02 22:30 ` Shardul Natu
2026-07-03 5:15 ` Patrick Steinhardt
2026-07-03 12:02 ` lipo availability [was: [PATCH v2] Makefile: link osxkeychain & support universal Rust] Ben Knoble
2026-07-02 22:22 ` [PATCH v3 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2026-07-02 22:22 ` [PATCH v3 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain Shardul Natu via GitGitGadget
2026-07-02 22:22 ` [PATCH v3 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
2026-07-03 5:36 ` Junio C Hamano
2026-07-03 17:37 ` Shardul Natu
2026-07-04 18:05 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Shardul Natu via GitGitGadget
2026-07-04 18:05 ` [PATCH v4 1/2] Makefile: add $(RUST_LIB) prerequisite to osxkeychain Shardul Natu via GitGitGadget
2026-07-06 10:49 ` Patrick Steinhardt
2026-07-04 18:05 ` [PATCH v4 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
2026-07-06 10:49 ` Patrick Steinhardt
2026-07-05 4:08 ` [PATCH v4 0/2] Makefile: link osxkeychain helper against Rust Junio C Hamano
2026-07-05 17:38 ` Shardul Natu
2026-07-06 17:14 ` [PATCH v5 " Shardul Natu via GitGitGadget
2026-07-06 17:14 ` [PATCH v5 1/2] Makefile: add $(GITLIBS) prerequisite to osxkeychain Shardul Natu via GitGitGadget
2026-07-06 17:14 ` [PATCH v5 2/2] Makefile: support universal macOS builds via RUST_TARGETS Shardul Natu via GitGitGadget
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.