From 5f1e8fa6019ce36744cb59577779009cba3d4471 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 25 May 2016 15:18:48 -0700 Subject: [PATCH] Add support for static linking. Use `make STATIC=1` to build a static library. Some language ecosystems, like those of Rust, have a convention of static linking in order to make binaries easier to distribute. In those environments, this feature helps libui fit in more easily. In order to prevent internal symbols from linking, we first create an intermediate object file with `ld -r` and strip private symbols from it before using `ar` to create the library. --- GNUmakefile | 7 ++++++- build/GNUbasegcc.mk | 7 +------ build/GNUbasemsvc.mk | 4 ++++ build/GNUmakefile.example | 6 +++++- build/GNUmakefile.libui | 4 ++++ darwin/GNUfiles.mk | 7 +++---- darwin/GNUosspecific.mk | 7 +++++++ darwin/GNUosspecificlink.mk | 15 +++++++++++++++ unix/GNUfiles.mk | 11 +++++------ unix/GNUosspecific.mk | 9 +++++++++ unix/GNUosspecificlink.mk | 15 +++++++++++++++ windows/GNUfiles.mk | 2 ++ windows/GNUosspecific.mk | 1 + 13 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 darwin/GNUosspecificlink.mk create mode 100644 unix/GNUosspecificlink.mk diff --git a/GNUmakefile b/GNUmakefile index 39b91cea..631495a4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -46,9 +46,14 @@ export DESTDIR # other important variables export OBJDIR export OUTDIR +export STATIC + +ifneq (,$(STATIC)) +STATICLIB = STATICLIB=1 +endif libui: - @$(MAKE) -f build/GNUmakefile.libui inlibuibuild=1 + @$(MAKE) -f build/GNUmakefile.libui inlibuibuild=1 $(STATICLIB) clean: rm -rf $(OBJDIR) $(OUTDIR) diff --git a/build/GNUbasegcc.mk b/build/GNUbasegcc.mk index 757d8fd7..b6741d1d 100644 --- a/build/GNUbasegcc.mk +++ b/build/GNUbasegcc.mk @@ -50,12 +50,7 @@ else reallinker = $(CXX) endif -$(OUT): $(OFILES) | $(OUTDIR) - @$(reallinker) -o $(OUT) $(OFILES) $(LDFLAGS) -ifeq ($(USESSONAME),1) - @ln -sf $(NAME)$(SUFFIX) $(OUTNOSONAME) -endif - @echo ====== Linked $(OUT) +include $(OS)/GNUosspecificlink.mk .SECONDEXPANSION: diff --git a/build/GNUbasemsvc.mk b/build/GNUbasemsvc.mk index 7e1bb6bf..46703b87 100644 --- a/build/GNUbasemsvc.mk +++ b/build/GNUbasemsvc.mk @@ -69,7 +69,11 @@ OUT = $(OUTDIR)/$(NAME)$(SUFFIX) # TODO use $(CC), $(CXX), $(LD), and s$(RC) $(OUT): $(OFILES) | $(OUTDIR) +ifeq (,$(STATICLIB)) @link -out:$(OUT) $(OFILES) $(LDFLAGS) +else + @lib -out:$(OUT) $(OFILES) +endif @echo ====== Linked $(OUT) .SECONDEXPANSION: diff --git a/build/GNUmakefile.example b/build/GNUmakefile.example index 1219ac74..2b9d4cbd 100644 --- a/build/GNUmakefile.example +++ b/build/GNUmakefile.example @@ -30,7 +30,11 @@ SUFFIX = $(EXESUFFIX) # TODO merge with the one in build/GNUmakefile.test ifeq ($(TOOLCHAIN),gcc) - LDFLAGS += -L$(OUTDIR) -lui + ifeq (,$(STATIC)) + LDFLAGS += -L$(OUTDIR) -lui + else + LDFLAGS += -L$(OUTDIR) -lui $(NATIVE_UI_LDFLAGS) + endif # see build/GNUmakefile.test ifeq ($(OS),darwin) LDFLAGS += -Wl,-rpath,@executable_path/ diff --git a/build/GNUmakefile.libui b/build/GNUmakefile.libui index 41b106ae..96f11c28 100644 --- a/build/GNUmakefile.libui +++ b/build/GNUmakefile.libui @@ -17,10 +17,14 @@ HFILES += \ ui_$(OS)$(OSHSUFFIX) NAME = libui +ifeq (,$(STATIC)) SUFFIX = $(LIBSUFFIX) ifeq ($(USESSONAME),1) SUFFIX = $(SONAMEEXT) endif +else +SUFFIX = $(STATICLIBSUFFIX) +endif ifeq ($(TOOLCHAIN),gcc) # make every symbol hidden by default except _UI_EXTERN ones diff --git a/darwin/GNUfiles.mk b/darwin/GNUfiles.mk index ed145a9d..9b9ed693 100644 --- a/darwin/GNUfiles.mk +++ b/darwin/GNUfiles.mk @@ -42,10 +42,7 @@ HFILES += \ # LONGTERM split into a separate file or put in GNUmakefile.libui somehow? # flags for Cocoa -LDFLAGS += \ - -lobjc \ - -framework Foundation \ - -framework AppKit +LDFLAGS += $(NATIVE_UI_LDFLAGS) # flags for OS X versioning CFLAGS += \ @@ -57,9 +54,11 @@ CXXFLAGS += \ LDFLAGS += \ -mmacosx-version-min=10.8 +ifeq (,$(STATIC)) # flags for building a shared library LDFLAGS += \ -dynamiclib +endif # on warning about undefined symbols: # the gcc flags don't work with Apple's linker diff --git a/darwin/GNUosspecific.mk b/darwin/GNUosspecific.mk index cc13d1b1..9f948e73 100644 --- a/darwin/GNUosspecific.mk +++ b/darwin/GNUosspecific.mk @@ -3,6 +3,7 @@ EXESUFFIX = LIBSUFFIX = .dylib OSHSUFFIX = .h +STATICLIBSUFFIX = .a TOOLCHAIN = gcc USESSONAME = 1 @@ -11,3 +12,9 @@ SONAMEEXT = .$(SOVERSION)$(LIBSUFFIX) # note the explicit need for @rpath # LONGTERM -current_version, -compatibility_version SONAMEFLAG = -Wl,-install_name,@rpath/ + +NATIVE_UI_LDFLAGS += \ + -lobjc \ + -framework Foundation \ + -framework AppKit + diff --git a/darwin/GNUosspecificlink.mk b/darwin/GNUosspecificlink.mk new file mode 100644 index 00000000..0b9087e6 --- /dev/null +++ b/darwin/GNUosspecificlink.mk @@ -0,0 +1,15 @@ +# 28 may 2016 + +$(OUT): $(OFILES) | $(OUTDIR) +ifeq (,$(STATICLIB)) + @$(reallinker) -o $(OUT) $(OFILES) $(LDFLAGS) +ifeq ($(USESSONAME),1) + @ln -sf $(NAME)$(SUFFIX) $(OUTNOSONAME) +endif +else + nm -m $(OFILES) | sed -E -n 's/^[0-9a-f]* \([A-Z_]+,[a-z_]+\) external //p' > $(OBJDIR)/symbols + $(LD) -exported_symbols_list $(OBJDIR)/symbols -r $(OFILES) -o $(OUT:%.a=%.o) + $(AR) rcs $(OUT) $(OUT:%.a=%.o) +endif + @echo ====== Linked $(OUT) + diff --git a/unix/GNUfiles.mk b/unix/GNUfiles.mk index b4a1784c..adc345ec 100644 --- a/unix/GNUfiles.mk +++ b/unix/GNUfiles.mk @@ -43,17 +43,16 @@ HFILES += \ # LONGTERM split into a separate file or put in GNUmakefile.libui somehow? # flags for GTK+ -CFLAGS += \ - `pkg-config --cflags gtk+-3.0` -CXXFLAGS += \ - `pkg-config --cflags gtk+-3.0` -LDFLAGS += \ - `pkg-config --libs gtk+-3.0` -lm -ldl +CFLAGS += $(NATIVE_UI_CFLAGS) +CXXFLAGS += $(NATIVE_UI_CXXFLAGS) +LDFLAGS += $(NATIVE_UI_LDFLAGS) # flags for building a shared library # OS X does support -shared but it has a preferred name for this so let's use that there instead; hence this is not gcc-global +ifeq (,$(STATIC)) LDFLAGS += \ -shared +endif # flags for warning on undefined symbols # this is not gcc-global because OS X doesn't support these flags diff --git a/unix/GNUosspecific.mk b/unix/GNUosspecific.mk index 5f6fc938..77b91fbb 100644 --- a/unix/GNUosspecific.mk +++ b/unix/GNUosspecific.mk @@ -3,6 +3,7 @@ EXESUFFIX = LIBSUFFIX = .so OSHSUFFIX = .h +STATICLIBSUFFIX = .a TOOLCHAIN = gcc # LONGTERM clean up all the NAMEs and SUFFIXs and NOSOSUFFIXs or whatever it was @@ -11,3 +12,11 @@ SOVERSION = $(SOVERSION0) SONAMEEXT = $(LIBSUFFIX).$(SOVERSION) # this is not gcc-global because OS X uses a different filename format SONAMEFLAG = -Wl,-soname, + +NATIVE_UI_CFLAGS = \ + `pkg-config --cflags gtk+-3.0` +NATIVE_UI_CXXFLAGS = \ + `pkg-config --cflags gtk+-3.0` +NATIVE_UI_LDFLAGS = \ + `pkg-config --libs gtk+-3.0` -lm -ldl + diff --git a/unix/GNUosspecificlink.mk b/unix/GNUosspecificlink.mk new file mode 100644 index 00000000..573b289f --- /dev/null +++ b/unix/GNUosspecificlink.mk @@ -0,0 +1,15 @@ +# 28 may 2016 + +$(OUT): $(OFILES) | $(OUTDIR) +ifeq (,$(STATICLIB)) + @$(reallinker) -o $(OUT) $(OFILES) $(LDFLAGS) +ifeq ($(USESSONAME),1) + @ln -sf $(NAME)$(SUFFIX) $(OUTNOSONAME) +endif +else + $(LD) -r $(OFILES) -o $(OUT:%.a=%.o) + objcopy --localize-hidden $(OUT:%.a=%.o) + $(AR) rcs $(OUT) $(OUT:%.a=%.o) +endif + @echo ====== Linked $(OUT) + diff --git a/windows/GNUfiles.mk b/windows/GNUfiles.mk index 905d6597..d9e992d2 100644 --- a/windows/GNUfiles.mk +++ b/windows/GNUfiles.mk @@ -73,8 +73,10 @@ LDFLAGS += \ user32.lib kernel32.lib usp10.lib gdi32.lib comctl32.lib uxtheme.lib msimg32.lib comdlg32.lib d2d1.lib dwrite.lib ole32.lib oleaut32.lib oleacc.lib uuid.lib # flags for building a shared library +ifeq (,$(STATIC)) LDFLAGS += \ -dll +endif # TODO flags for warning on undefined symbols diff --git a/windows/GNUosspecific.mk b/windows/GNUosspecific.mk index a4da078f..c8335d66 100644 --- a/windows/GNUosspecific.mk +++ b/windows/GNUosspecific.mk @@ -3,6 +3,7 @@ EXESUFFIX = .exe LIBSUFFIX = .dll OSHSUFFIX = .h +STATICLIBSUFFIX = .lib TOOLCHAIN = msvc USESSONAME = 0