Remove unnecessary bitcode from dylibs. Fixes #51352 (#1469)

This is a series of fixes to the dynamic libraries we build / create to remove
any unnecessary bloat (unused architectures, bitcode).

A brand new watchOS app with no changes goes from 35MB to 11MB with these
fixes (with incremental builds disabled, the app size is 10MB).

--------------------------------------------------------------------------------

* [runtime] Split list of architectures into simulator and device-specific lists.

* [runtime] Build separate dylibs for device and simulator.

Build separate dylibs for device and simulator, since we already install these
into different locations.

This makes both the simulator and device builds slightly faster (since the
respective dylibs are smaller, and less data to copy around).

For watchOS apps, this saves ~430kb.

* [runtime] Strip bitcode from dylibs. Fixes #51352.

We know that dylibs will never be shipped to the App Store, so we'll never
need them to have bitcode.

So just strip the bitcode from all our dylibs, since this makes apps with
fastdev significantly smaller (and thus much faster to upload to watch
devices).

For watchOS apps this is a very significant improvement: a branch new watchOS
app without any changes goes from 35MB to 17MB.

https://bugzilla.xamarin.com/show_bug.cgi?id=51352

* [mtouch] Fix dylib compilation to not embed full bitcode.

Facts
=====

a. The output from the AOT compiler is an assembly (.s) file.
b. Clang's assembler does not support -fembed-bitcode-marker (only -fembed-
   bitcode), so when we ask clang to -fembed-bitcode-marker, the assembler
   receives a -fembed-bitcode argument.
c. This means that the assembled object file does not contain the
   __LLVM/__bitcode and __LLVM/__cmdline sections (it does however contain an
   __LLVM/__asm section).
d. The native linker will create a bitcode assembly section if none of the
   object files passed to the linker contain a __LLVM/__bitcode section and
   there's an __LLVM/__asm section present.
e. The end result is that when we build to a dylib, we end up (unexpectedly,
   because we ask Clang to -fembed-bitcode-marker) including both armv7k and
   bitcode in the dylib, thus bloating the dylib size significantly.

Solution
========

We manually add the __LLVM/__bitcode and __LLVM/__cmdline sections to the .s
file Mono's AOT compiler generated. This way the .o file will have the magic
sections, and the linker will not include bitcode (only the bitcode marker) in
the final library.

An empty watchOS extension with incremental builds is now 6MB smaller (down
to 11MB from 17MB).
This commit is contained in:
Rolf Bjarne Kvinge 2017-01-16 12:32:06 +01:00 коммит произвёл GitHub
Родитель 5f26772e1b
Коммит 0a07b6ba8e
4 изменённых файлов: 72 добавлений и 43 удалений

Просмотреть файл

@ -1626,22 +1626,22 @@ $(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/usr/lib/libmonosgen-2.0.a: $(WATCHOS_TARGET
$(Q) $(WATCHOS_BIN_PATH)/lipo $(WATCHOS_TARGET_LIBMONOSGEN) -create -output $@
$(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/usr/lib/libmonosgen-2.0.dylib: $(WATCHOS_TARGET_SHAREDMONOSGEN) | $(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/usr/lib
$(Q) $(WATCHOS_BIN_PATH)/lipo $(WATCHOS_TARGET_SHAREDMONOSGEN) -create -output $@
$(Q_STRIP) $(WATCHOS_BIN_PATH)/bitcode_strip $(WATCHOS_TARGET_SHAREDMONOSGEN) -m -o $@
$(Q) $(WATCHOS_BIN_PATH)/install_name_tool -id @executable_path/libmonosgen-2.0.dylib $@
$(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/usr/lib/libmono-profiler-log.a: $(WATCHOS_TARGET_LIBLOGPROFILER) | $(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/usr/lib
$(Q) $(WATCHOS_BIN_PATH)/lipo $(WATCHOS_TARGET_LIBLOGPROFILER) -create -output $@
$(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/usr/lib/libmono-profiler-log.dylib: $(WATCHOS_TARGET_SHAREDLIBLOGPROFILER) | $(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/usr/lib
$(Q) lipo $(WATCHOS_TARGET_SHAREDLIBLOGPROFILER) -create -output $@
$(Q) $(WATCHOS_BIN_PATH)/bitcode_strip $(WATCHOS_TARGET_SHAREDLIBLOGPROFILER) -m -o $@
$(Q) $(WATCHOS_BIN_PATH)/install_name_tool -id @executable_path/libmono-profiler-log.dylib -change $(BUILD_DESTDIR)/targetwatch/lib/libmonosgen-2.0.1.dylib @executable_path/libmonosgen-2.0.dylib $@
$(WATCHOS_DIRECTORIES):
$(Q) mkdir -p $@
$(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/Frameworks/Mono.framework/Mono: $(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/usr/lib/libmonosgen-2.0.dylib | $(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/Frameworks/Mono.framework
$(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/Frameworks/Mono.framework/Mono: $(WATCHOS_TARGET_SHAREDLIBLOGPROFILER) | $(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/Frameworks/Mono.framework
$(Q) cp $< $@
$(Q) $(WATCHOS_BIN_PATH)/install_name_tool -id @rpath/Mono.framework/Mono $@
$(Q) $(WATCHOS_BIN_PATH)/install_name_tool -id @rpath/Mono.framework/Mono -change $(BUILD_DESTDIR)/targetwatch/lib/libmonosgen-2.0.1.dylib @executable_path/libmonosgen-2.0.dylib $@
$(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/Frameworks/Mono.framework/Info.plist: Mono.framework-watchos.Info.plist | $(IOS_DESTDIR)$(XAMARIN_WATCHOS_SDK)/Frameworks/Mono.framework
$(Q) cp $< $@

Просмотреть файл

@ -91,53 +91,61 @@ $(2)_SOURCE_STEMS = $(MONOTOUCH_SOURCE_STEMS)
$(2)_X86_64_SOURCE_STEMS = $(MONOTOUCH_X86_64_SOURCE_STEMS)
$(2)_I386_SOURCE_STEMS = $(MONOTOUCH_I386_SOURCE_STEMS)
$(2)_LIBRARIES = $(MONOTOUCH_LIBS)
$(2)_ARCHITECTURES = $(3)
ifdef INCLUDE_DEVICE
$(2)_DEVICE_ARCHITECTURES = $(3)
endif
$(2)_SIM_ARCHITECTURES = $(4)
$(2)_ARCHITECTURES = $$($(2)_DEVICE_ARCHITECTURES) $$($(2)_SIM_ARCHITECTURES)
RUNTIME_$(2)_TARGETS_DIRS += \
$(IOS_DESTDIR)$$(XAMARIN_$(4)SIMULATOR_SDK)/usr/lib \
$(IOS_DESTDIR)$$(XAMARIN_$(4)SIMULATOR_SDK)/usr/include/xamarin \
$(IOS_DESTDIR)$$(XAMARIN_$(5)OS_SDK)/usr/lib \
$(IOS_DESTDIR)$$(XAMARIN_$(5)OS_SDK)/usr/include/xamarin \
$(IOS_DESTDIR)$$(XAMARIN_$(5)SIMULATOR_SDK)/usr/lib \
$(IOS_DESTDIR)$$(XAMARIN_$(5)SIMULATOR_SDK)/usr/include/xamarin \
$(IOS_DESTDIR)$$(XAMARIN_$(6)OS_SDK)/usr/lib \
$(IOS_DESTDIR)$$(XAMARIN_$(6)OS_SDK)/usr/include/xamarin \
RUNTIME_$(2)_TARGETS += \
$$(foreach file,$$($(2)_LIBRARIES),$(IOS_DESTDIR)$$(XAMARIN_$(4)SIMULATOR_SDK)/usr/lib/$$(file)) \
$(foreach file,$(SHIPPED_HEADERS),$(IOS_DESTDIR)$$(XAMARIN_$(4)SIMULATOR_SDK)/usr/include/$(file)) \
$$(foreach file,$$($(2)_LIBRARIES),$(IOS_DESTDIR)$$(XAMARIN_$(5)SIMULATOR_SDK)/usr/lib/$$(file)) \
$(foreach file,$(SHIPPED_HEADERS),$(IOS_DESTDIR)$$(XAMARIN_$(5)SIMULATOR_SDK)/usr/include/$(file)) \
ifdef INCLUDE_DEVICE
RUNTIME_$(2)_TARGETS += \
$$(foreach file,$$($(2)_LIBRARIES),$(IOS_DESTDIR)$$(XAMARIN_$(5)OS_SDK)/usr/lib/$$(file)) \
$(foreach file,$(SHIPPED_HEADERS),$(IOS_DESTDIR)$$(XAMARIN_$(5)OS_SDK)/usr/include/$(file)) \
$$(foreach file,$$($(2)_LIBRARIES),$(IOS_DESTDIR)$$(XAMARIN_$(6)OS_SDK)/usr/lib/$$(file)) \
$(foreach file,$(SHIPPED_HEADERS),$(IOS_DESTDIR)$$(XAMARIN_$(6)OS_SDK)/usr/include/$(file)) \
endif
$(IOS_DESTDIR)$$(XAMARIN_$(4)SIMULATOR_SDK)/usr/lib/%.a: .libs/$(1)/%.a | $(IOS_DESTDIR)$$(XAMARIN_$(4)SIMULATOR_SDK)/usr/lib
$(IOS_DESTDIR)$$(XAMARIN_$(5)SIMULATOR_SDK)/usr/lib/%.a: .libs/$(1)/%.a | $(IOS_DESTDIR)$$(XAMARIN_$(5)SIMULATOR_SDK)/usr/lib
$(Q) install -m 0644 $$< $$@
ifdef INCLUDE_DEVICE
$(IOS_DESTDIR)$$(XAMARIN_$(5)OS_SDK)/usr/lib/%.a: .libs/$(1)/%.a | $(IOS_DESTDIR)$$(XAMARIN_$(5)OS_SDK)/usr/lib
$(IOS_DESTDIR)$$(XAMARIN_$(6)OS_SDK)/usr/lib/%.a: .libs/$(1)/%.a | $(IOS_DESTDIR)$$(XAMARIN_$(6)OS_SDK)/usr/lib
$(Q) install -m 0644 $$< $$@
endif
$(IOS_DESTDIR)$$(XAMARIN_$(4)SIMULATOR_SDK)/usr/lib/%.dylib: .libs/$(1)/%.dylib | $(IOS_DESTDIR)$$(XAMARIN_$(4)SIMULATOR_SDK)/usr/lib
$(IOS_DESTDIR)$$(XAMARIN_$(5)SIMULATOR_SDK)/usr/lib/%.dylib: .libs/$(1)/%-sim.dylib | $(IOS_DESTDIR)$$(XAMARIN_$(5)SIMULATOR_SDK)/usr/lib
$(Q) install -m 0644 $$< $$@
ifdef INCLUDE_DEVICE
$(IOS_DESTDIR)$$(XAMARIN_$(5)OS_SDK)/usr/lib/%.dylib: .libs/$(1)/%.dylib | $(IOS_DESTDIR)$$(XAMARIN_$(5)OS_SDK)/usr/lib
$(IOS_DESTDIR)$$(XAMARIN_$(6)OS_SDK)/usr/lib/%.dylib: .libs/$(1)/%-dev.dylib | $(IOS_DESTDIR)$$(XAMARIN_$(6)OS_SDK)/usr/lib
ifeq (watchos,$(1))
$$(Q_STRIP) $(DEVICE_BIN_PATH)/bitcode_strip $$< -m -o $$@
else
$(Q) install -m 0644 $$< $$@
endif
endif
$(IOS_DESTDIR)$$(XAMARIN_$(4)SIMULATOR_SDK)/usr/include/%.h: %.h | $(IOS_DESTDIR)$$(XAMARIN_$(4)SIMULATOR_SDK)/usr/include/xamarin
$(IOS_DESTDIR)$$(XAMARIN_$(5)SIMULATOR_SDK)/usr/include/%.h: %.h | $(IOS_DESTDIR)$$(XAMARIN_$(5)SIMULATOR_SDK)/usr/include/xamarin
$(Q) install -m 0644 $$< $$@
ifdef INCLUDE_DEVICE
$(IOS_DESTDIR)$$(XAMARIN_$(5)OS_SDK)/usr/include/%.h: %.h | $(IOS_DESTDIR)$$(XAMARIN_$(5)OS_SDK)/usr/include/xamarin
$(IOS_DESTDIR)$$(XAMARIN_$(6)OS_SDK)/usr/include/%.h: %.h | $(IOS_DESTDIR)$$(XAMARIN_$(6)OS_SDK)/usr/include/xamarin
$(Q) install -m 0644 $$< $$@
endif
$$(RUNTIME_$(2)_TARGETS_DIRS):
$(Q) mkdir -p $$@
all-$(4): $$(RUNTIME_$(2)_TARGETS)
all-$(5): $$(RUNTIME_$(2)_TARGETS)
all-local:: $$(RUNTIME_$(2)_TARGETS)
install-local:: $$(RUNTIME_$(2)_TARGETS)
@ -145,31 +153,20 @@ endef
# 1: platform name
# 2: variable prefix
# 3: architectures
# 4: simulator variable name used in some places
# 5: device variable name used in some places
# 3: device architectures
# 4: sim architectures
# 5: simulator variable name used in some places
# 6: device variable name used in some places
ifdef INCLUDE_IOS
ifdef INCLUDE_DEVICE
$(eval $(call PlatformTemplate,ios,IOS,armv7 armv7s arm64 x86 x86_64,IOS,IPHONE))
else
$(eval $(call PlatformTemplate,ios,IOS, x86 x86_64,IOS,IPHONE))
endif
$(eval $(call PlatformTemplate,ios,IOS,armv7 armv7s arm64,x86 x86_64,IOS,IPHONE))
endif
ifdef INCLUDE_WATCH
ifdef INCLUDE_DEVICE
$(eval $(call PlatformTemplate,watchos,WATCHOS,armv7k x86,WATCH,WATCH))
else
$(eval $(call PlatformTemplate,watchos,WATCHOS, x86,WATCH,WATCH))
endif
$(eval $(call PlatformTemplate,watchos,WATCHOS,armv7k,x86,WATCH,WATCH))
endif
ifdef INCLUDE_TVOS
ifdef INCLUDE_DEVICE
$(eval $(call PlatformTemplate,tvos,TVOS,arm64 x86_64,TV,TV))
else
$(eval $(call PlatformTemplate,tvos,TVOS, x86_64,TV,TV))
endif
$(eval $(call PlatformTemplate,tvos,TVOS,arm64,x86_64,TV,TV))
endif
#
@ -217,16 +214,36 @@ $$(foreach arch,$$($(2)_ARCHITECTURES),.libs/$(1)/tvextension-main.$$(arch).o):
$(Q) rm -f $$@
$$(call Q_2,LIPO, [$1]) $(DEVICE_BIN_PATH)/lipo $$^ -create -output $$@
.libs/$(1)/libxamarin.dylib: $$(foreach arch,$$($(2)_ARCHITECTURES),.libs/$(1)/libxamarin.$$(arch).dylib)
.libs/$(1)/libxamarin-sim.dylib: $$(foreach arch,$$($(2)_SIM_ARCHITECTURES),.libs/$(1)/libxamarin.$$(arch).dylib)
$(Q) rm -f $$@
$$(call Q_2,LIPO, [$1]) $(DEVICE_BIN_PATH)/lipo $$^ -create -output $$@
$(Q) install_name_tool -id @executable_path/$$(notdir $$@) $$@
$(Q) install_name_tool -id @executable_path/libxamarin.dylib $$@
$(Q) install_name_tool -change @executable_path/ @executable_path/libmonosgen-2.0.dylib $$@
.libs/$(1)/libxamarin-debug.dylib: $$(foreach arch,$$($(2)_ARCHITECTURES),.libs/$(1)/libxamarin-debug.$$(arch).dylib)
.libs/$(1)/libxamarin-debug-sim.dylib: $$(foreach arch,$$($(2)_SIM_ARCHITECTURES),.libs/$(1)/libxamarin-debug.$$(arch).dylib)
$(Q) rm -f $$@
$$(call Q_2,LIPO, [$1]) $(DEVICE_BIN_PATH)/lipo $$^ -create -output $$@
$(Q) install_name_tool -id @executable_path/$$(notdir $$@) $$@
$(Q) install_name_tool -id @executable_path/libxamarin-debug.dylib $$@
$(Q) install_name_tool -change @executable_path/ @executable_path/libmonosgen-2.0.dylib $$@
.libs/$(1)/libxamarin-dev.dylib: $$(foreach arch,$$($(2)_DEVICE_ARCHITECTURES),.libs/$(1)/libxamarin.$$(arch).dylib)
$(Q) rm -f $$@
ifeq (1,$$(words $$($(2)_DEVICE_ARCHITECTURES)))
$(Q) cp $$^ $$@
else
$$(call Q_2,LIPO, [$1]) $(DEVICE_BIN_PATH)/lipo $$^ -create -output $$@
endif
$(Q) install_name_tool -id @executable_path/libxamarin.dylib $$@
$(Q) install_name_tool -change @executable_path/ @executable_path/libmonosgen-2.0.dylib $$@
.libs/$(1)/libxamarin-debug-dev.dylib: $$(foreach arch,$$($(2)_DEVICE_ARCHITECTURES),.libs/$(1)/libxamarin-debug.$$(arch).dylib)
$(Q) rm -f $$@
ifeq (1,$$(words $$($(2)_DEVICE_ARCHITECTURES)))
$(Q) cp $$^ $$@
else
$$(call Q_2,LIPO, [$1]) $(DEVICE_BIN_PATH)/lipo $$^ -create -output $$@
endif
$(Q) install_name_tool -id @executable_path/libxamarin-debug.dylib $$@
$(Q) install_name_tool -change @executable_path/ @executable_path/libmonosgen-2.0.dylib $$@
.SECONDARY: $$(foreach arch,$$($(2)_ARCHITECTURES),.libs/$(1)/app-main.$$(arch).o)

Просмотреть файл

@ -1855,14 +1855,24 @@ namespace Xamarin.Bundler {
public class AOTTask : ProcessTask {
public string AssemblyName;
public bool AddBitcodeMarkerSection;
public string AssemblyPath; // path to the .s file.
// executed with Parallel.ForEach
protected override void Build ()
{
var exit_code = base.Start ();
if (exit_code == 0)
if (exit_code == 0) {
if (AddBitcodeMarkerSection)
File.AppendAllText (AssemblyPath, @"
.section __LLVM, __bitcode
.byte 0
.section __LLVM, __cmdline
.byte 0
");
return;
}
Console.Error.WriteLine ("AOT Compilation exited with code {0}, command:\n{1}{2}", exit_code, Command, Output.Length > 0 ? ("\n" + Output.ToString ()) : string.Empty);
if (Output.Length > 0) {

Просмотреть файл

@ -268,6 +268,8 @@ namespace Xamarin.Bundler {
return new BuildTask [] { new AOTTask ()
{
AssemblyName = s,
AddBitcodeMarkerSection = App.FastDev && App.EnableMarkerOnlyBitCode,
AssemblyPath = asm,
ProcessStartInfo = Driver.CreateStartInfo (App, aotCompiler, aotArgs, Path.GetDirectoryName (s)),
NextTasks = nextTasks
}