From dc0a6e587c19fa7c4148832287c375fc24ba25c1 Mon Sep 17 00:00:00 2001 From: Sam Schweigel Date: Mon, 17 Nov 2025 14:17:09 -0800 Subject: [PATCH 1/3] Use -force_load, rather than -all_load, on ld64 (macOS) We have been using ld64's `-all_load` as the mac equivalent to `--whole-archive`, but `-force_load` does something closer to what we want. From the ld64 man page: ``` -all_load Loads all members of static archive libraries. -force_load path_to_archive Loads all members of the specified static archive library. Note: -all_load forces all members of all archives to be loaded. This option allows you to target a specific archive. ``` When we link `libjulia-internal.dylib` and `libjulia-codegen.dylib` with `-all_load`, we pull in more of the static LLVM support libraries than we need. Before: ``` 5.1M usr/lib/libjulia-internal.1.14.0.dylib 2.1M usr/lib/libjulia-codegen.1.14.0.dylib ``` After: ``` 3.8M usr/lib/libjulia-internal.1.14.0.dylib 2.1M usr/lib/libjulia-codegen.1.14.0.dylib ``` --- Make.inc | 4 +--- base/linking.jl | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Make.inc b/Make.inc index a246d9c3e781e..69fc0272a669f 100644 --- a/Make.inc +++ b/Make.inc @@ -1508,7 +1508,7 @@ RPATH_LIB := $(RPATH_ORIGIN) # --whole-archive ifeq ($(OS), Darwin) - WHOLE_ARCHIVE := -Xlinker -all_load + WHOLE_ARCHIVE := -Xlinker -force_load NO_WHOLE_ARCHIVE := else WHOLE_ARCHIVE := -Wl,--whole-archive @@ -1578,8 +1578,6 @@ endif ifeq ($(OS), Darwin) SHLIB_EXT := dylib OSLIBS += -framework CoreFoundation -WHOLE_ARCHIVE := -Xlinker -all_load -NO_WHOLE_ARCHIVE := HAVE_SSP := 1 JLIBLDFLAGS += -Wl,-compatibility_version,$(SOMAJOR) -Wl,-current_version,$(JULIA_MAJOR_VERSION).$(JULIA_MINOR_VERSION).$(JULIA_PATCH_VERSION) endif diff --git a/base/linking.jl b/base/linking.jl index edb70e8061119..e78efeada937d 100644 --- a/base/linking.jl +++ b/base/linking.jl @@ -107,7 +107,7 @@ function ld() end const WHOLE_ARCHIVE = if Sys.isapple() - "-all_load" + "-force_load" else "--whole-archive" end From a2a06b299433b30b28dd2e36167d562841ec5d61 Mon Sep 17 00:00:00 2001 From: Sam Schweigel Date: Tue, 18 Nov 2025 09:54:31 -0800 Subject: [PATCH 2/3] Make whole_archive a makefile function; add Base.Linking.whole_archive --- Make.inc | 11 ++++------- base/linking.jl | 15 +++++++++++++-- contrib/juliac/juliac.jl | 6 +++--- src/Makefile | 8 ++++---- sysimage.mk | 2 +- test/trimming/Makefile | 6 +++--- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Make.inc b/Make.inc index 69fc0272a669f..ea586fa0f9b9c 100644 --- a/Make.inc +++ b/Make.inc @@ -1508,11 +1508,9 @@ RPATH_LIB := $(RPATH_ORIGIN) # --whole-archive ifeq ($(OS), Darwin) - WHOLE_ARCHIVE := -Xlinker -force_load - NO_WHOLE_ARCHIVE := + whole_archive = -Xlinker -force_load $(1) else - WHOLE_ARCHIVE := -Wl,--whole-archive - NO_WHOLE_ARCHIVE := -Wl,--no-whole-archive + whole_archive = -Wl,--whole-archive $(1) -Wl,--no-whole-archive endif # Initialize these once, then add to them in OS-specific blocks @@ -1558,8 +1556,7 @@ ifeq (,$(findstring aarch64,$(ARCH))) OSLIBS += -lgcc_s endif -OSLIBS += -Wl,--export-dynamic -Wl,--version-script=$(BUILDROOT)/src/julia.expmap \ - $(NO_WHOLE_ARCHIVE) +OSLIBS += -Wl,--export-dynamic -Wl,--version-script=$(BUILDROOT)/src/julia.expmap -Wl,--no-whole-archive endif ifeq ($(OS), OpenBSD) @@ -1585,7 +1582,7 @@ endif ifeq ($(OS), WINNT) HAVE_SSP := 1 OSLIBS += -Wl,--export-all-symbols -Wl,--version-script=$(BUILDROOT)/src/julia.expmap \ - $(NO_WHOLE_ARCHIVE) -lpsapi -lkernel32 -lws2_32 -liphlpapi -lwinmm -ldbghelp -luserenv -lsecur32 -latomic -lole32 + -Wl,--no-whole-archive -lpsapi -lkernel32 -lws2_32 -liphlpapi -lwinmm -ldbghelp -luserenv -lsecur32 -latomic -lole32 # N.B.: Unlike in the sysimage, we cannot -Wl,--disable-auto-import -Wl,--disable-runtime-pseudo-reloc here, because libstdc++/LLVM are not fully correct under # enforced visibility at this point. JLDFLAGS += -Wl,--stack,8388608 diff --git a/base/linking.jl b/base/linking.jl index e78efeada937d..84b53c2134ede 100644 --- a/base/linking.jl +++ b/base/linking.jl @@ -107,7 +107,7 @@ function ld() end const WHOLE_ARCHIVE = if Sys.isapple() - "-force_load" + "-all_load" else "--whole-archive" end @@ -118,6 +118,17 @@ else "--no-whole-archive" end +# Prefer whole_archive to WHOLE_ARCHIVE +whole_archive(paths::String; is_cc=false) = whole_archive([paths]; is_cc) +function whole_archive(paths::Vector{String}; is_cc=false) + cc_arg(a) = is_cc ? "-Wl,$a" : a + if Sys.isapple() + Cmd(collect(Iterators.flatmap(p -> (cc_arg("-force_load"), p), paths))) + else + `$(cc_arg("--whole-archive")) $paths $(cc_arg("--no-whole-archive"))` + end +end + const SHARED = if Sys.isapple() "-dylib" else @@ -152,7 +163,7 @@ function link_image_cmd(path, out) end V = verbose_linking() ? "--verbose" : "" - `$(ld()) $V $SHARED -o $out $WHOLE_ARCHIVE $path $NO_WHOLE_ARCHIVE $PRIVATE_LIBDIR $SHLIBDIR $LIBS` + `$(ld()) $V $SHARED -o $out $(whole_archive(path)) $PRIVATE_LIBDIR $SHLIBDIR $LIBS` end function link_image(path, out, internal_stderr::IO=stderr, internal_stdout::IO=stdout) diff --git a/contrib/juliac/juliac.jl b/contrib/juliac/juliac.jl index 99d7e1c8b5c2c..b58722153878c 100644 --- a/contrib/juliac/juliac.jl +++ b/contrib/juliac/juliac.jl @@ -202,11 +202,11 @@ function link_products() julia_libs = Base.shell_split(Base.isdebugbuild() ? "-ljulia-debug -ljulia-internal-debug" : "-ljulia -ljulia-internal") try if output_type == "--output-lib" - cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` + cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -shared $(Base.Linking.whole_archive(img_path)) $(julia_libs)` elseif output_type == "--output-sysimage" - cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` + cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.whole_archive(img_path)) $(julia_libs)` else - cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` + cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -Wl,$(Base.Linking.whole_archive(img_path)) $(julia_libs)` end verbose && println("Running: $cmd2") run(cmd2) diff --git a/src/Makefile b/src/Makefile index 5726268041a5b..8cef80977d10a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -203,7 +203,7 @@ LIBJULIA_PATH_REL := libjulia endif COMMON_LIBPATHS := -L$(build_libdir) -L$(build_shlibdir) -RT_LIBS := $(WHOLE_ARCHIVE) $(LIBUV) $(WHOLE_ARCHIVE) $(LIBUTF8PROC) $(NO_WHOLE_ARCHIVE) $(LIBUNWIND) $(RT_LLVMLINK) $(OSLIBS) $(LIBTRACYCLIENT) $(LIBITTAPI) -lzstd +RT_LIBS := $(call whole_archive,$(LIBUV)) $(call whole_archive,$(LIBUTF8PROC)) $(LIBUNWIND) $(RT_LLVMLINK) $(OSLIBS) $(LIBTRACYCLIENT) $(LIBITTAPI) -lzstd # NB: CG needs uv_mutex_* symbols, but we expect to export them from libjulia-internal CG_LIBS := $(LIBUNWIND) $(CG_LLVMLINK) $(OSLIBS) $(LIBTRACYCLIENT) $(LIBITTAPI) @@ -212,9 +212,9 @@ RT_LIBS += $(MMTK_LIB) CG_LIBS += $(MMTK_LIB) endif -RT_DEBUG_LIBS := $(COMMON_LIBPATHS) $(WHOLE_ARCHIVE) $(BUILDDIR)/flisp/libflisp-debug.a $(WHOLE_ARCHIVE) $(BUILDDIR)/support/libsupport-debug.a -ljulia-debug $(RT_LIBS) +RT_DEBUG_LIBS := $(COMMON_LIBPATHS) $(call whole_archive,$(BUILDDIR)/flisp/libflisp-debug.a) $(call whole_archive,$(BUILDDIR)/support/libsupport-debug.a) -ljulia-debug $(RT_LIBS) CG_DEBUG_LIBS := $(COMMON_LIBPATHS) $(CG_LIBS) -ljulia-debug -ljulia-internal-debug -RT_RELEASE_LIBS := $(COMMON_LIBPATHS) $(WHOLE_ARCHIVE) $(BUILDDIR)/flisp/libflisp.a $(WHOLE_ARCHIVE) $(BUILDDIR)/support/libsupport.a -ljulia $(RT_LIBS) +RT_RELEASE_LIBS := $(COMMON_LIBPATHS) $(call whole_archive,$(BUILDDIR)/flisp/libflisp.a) $(call whole_archive,$(BUILDDIR)/support/libsupport.a) -ljulia $(RT_LIBS) CG_RELEASE_LIBS := $(COMMON_LIBPATHS) $(CG_LIBS) -ljulia -ljulia-internal OBJS := $(SRCS:%=$(BUILDDIR)/%.o) @@ -355,7 +355,7 @@ $(build_shlibdir)/libccalllazybar.$(SHLIB_EXT): $(SRCDIR)/ccalllazybar.c $(build @$(call PRINT_CC, $(CC) $(JCFLAGS) $(JCPPFLAGS) $(FLAGS_COMMON) -O3 $< $(fPIC) -shared -o $@ $(LDFLAGS) $(COMMON_LIBPATHS) $(call SONAME_FLAGS,libccalllazybar.$(SHLIB_EXT)) -lccalllazyfoo) $(build_shlibdir)/libllvmcalltest.$(SHLIB_EXT): $(SRCDIR)/llvmcalltest.cpp $(LLVM_CONFIG_ABSOLUTE) - @$(call PRINT_CC, $(CXX) $(JCXXFLAGS) $(LLVM_CXXFLAGS) $(FLAGS_COMMON) $(CPPFLAGS) $(CXXFLAGS) -O3 $< $(fPIC) -shared -o $@ $(LDFLAGS) $(COMMON_LIBPATHS) $(NO_WHOLE_ARCHIVE) $(CG_LLVMLINK)) -lpthread + @$(call PRINT_CC, $(CXX) $(JCXXFLAGS) $(LLVM_CXXFLAGS) $(FLAGS_COMMON) $(CPPFLAGS) $(CXXFLAGS) -O3 $< $(fPIC) -shared -o $@ $(LDFLAGS) $(COMMON_LIBPATHS) $(CG_LLVMLINK)) -lpthread .PHONY: julia_flisp.boot.inc.phony julia_flisp.boot.inc.phony: $(BUILDDIR)/julia_flisp.boot.inc diff --git a/sysimage.mk b/sysimage.mk index e7917875e0ef2..67464947eefdb 100644 --- a/sysimage.mk +++ b/sysimage.mk @@ -18,7 +18,7 @@ VERSDIR := v$(shell cut -d. -f1-2 < $(JULIAHOME)/VERSION) $(build_private_libdir)/%.$(SHLIB_EXT): $(build_private_libdir)/%-o.a @$(call PRINT_LINK, $(CXX) $(LDFLAGS) -shared $(fPIC) -L$(build_private_libdir) -L$(build_libdir) -L$(build_shlibdir) -o $@ \ - $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) \ + $(call whole_archive,$<) \ $(if $(findstring -debug,$(notdir $@)),-ljulia-internal-debug -ljulia-debug,-ljulia-internal -ljulia) \ $$([ $(OS) = WINNT ] && echo '' $(LIBM) -lssp -Wl,--disable-auto-import -Wl,--disable-runtime-pseudo-reloc)) @$(INSTALL_NAME_CMD)$(notdir $@) $@ diff --git a/test/trimming/Makefile b/test/trimming/Makefile index 3c1de9555e439..f0ee34dcc3703 100644 --- a/test/trimming/Makefile +++ b/test/trimming/Makefile @@ -52,13 +52,13 @@ $(BIN)/libsimple-o.a: $(SRCDIR)/libsimple.jl $(JULIAC_BUILDSCRIPT) $(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-lib true $(BIN)/bindinginfo_libsimple.json $(BIN)/hello$(EXE): $(BIN)/hello-o.a - $(CC) -o $@ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) + $(CC) -o $@ $(call whole_archive,$<) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) $(BIN)/trimmability$(EXE): $(BIN)/trimmability-o.a - $(CC) -o $@ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) + $(CC) -o $@ $(call whole_archive,$<) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) $(BIN)/basic_jll$(EXE): $(BIN)/basic_jll-o.a - $(CC) -o $@ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) + $(CC) -o $@ $(call whole_archive,$<) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) $(BIN)/capplication$(EXE): $(SRCDIR)/capplication.c $(SRCDIR)/libsimple.h $(BIN)/libsimple-o.a $(CC) -I$(BIN) -I$(SRCDIR) -I$(JULIA_LIBDIR) -o $@ $< -Wl,--whole-archive $(BIN)/libsimple-o.a -Wl,--no-whole-archive $(LDFLAGS_ADD) $(LDFLAGS) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) From c459ad86247588cc5106ca7361ea1854a4c0e90f Mon Sep 17 00:00:00 2001 From: Sam Schweigel Date: Tue, 18 Nov 2025 10:15:16 -0800 Subject: [PATCH 3/3] Fix use of Base.Linking.whole_archive in contrib/juliac script --- contrib/juliac/juliac.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/juliac/juliac.jl b/contrib/juliac/juliac.jl index b58722153878c..23eb1d93ffa82 100644 --- a/contrib/juliac/juliac.jl +++ b/contrib/juliac/juliac.jl @@ -202,11 +202,11 @@ function link_products() julia_libs = Base.shell_split(Base.isdebugbuild() ? "-ljulia-debug -ljulia-internal-debug" : "-ljulia -ljulia-internal") try if output_type == "--output-lib" - cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -shared $(Base.Linking.whole_archive(img_path)) $(julia_libs)` + cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -shared $(Base.Linking.whole_archive(img_path; is_cc=true)) $(julia_libs)` elseif output_type == "--output-sysimage" - cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.whole_archive(img_path)) $(julia_libs)` + cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.whole_archive(img_path; is_cc=true)) $(julia_libs)` else - cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -Wl,$(Base.Linking.whole_archive(img_path)) $(julia_libs)` + cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -Wl,$(Base.Linking.whole_archive(img_path; is_cc=true)) $(julia_libs)` end verbose && println("Running: $cmd2") run(cmd2)