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
-