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.
This commit is contained in:
Patrick Walton 2016-05-25 15:18:48 -07:00
parent 18a84988fd
commit 5f1e8fa601
13 changed files with 77 additions and 18 deletions

View File

@ -46,9 +46,14 @@ export DESTDIR
# other important variables # other important variables
export OBJDIR export OBJDIR
export OUTDIR export OUTDIR
export STATIC
ifneq (,$(STATIC))
STATICLIB = STATICLIB=1
endif
libui: libui:
@$(MAKE) -f build/GNUmakefile.libui inlibuibuild=1 @$(MAKE) -f build/GNUmakefile.libui inlibuibuild=1 $(STATICLIB)
clean: clean:
rm -rf $(OBJDIR) $(OUTDIR) rm -rf $(OBJDIR) $(OUTDIR)

View File

@ -50,12 +50,7 @@ else
reallinker = $(CXX) reallinker = $(CXX)
endif endif
$(OUT): $(OFILES) | $(OUTDIR) include $(OS)/GNUosspecificlink.mk
@$(reallinker) -o $(OUT) $(OFILES) $(LDFLAGS)
ifeq ($(USESSONAME),1)
@ln -sf $(NAME)$(SUFFIX) $(OUTNOSONAME)
endif
@echo ====== Linked $(OUT)
.SECONDEXPANSION: .SECONDEXPANSION:

View File

@ -69,7 +69,11 @@ OUT = $(OUTDIR)/$(NAME)$(SUFFIX)
# TODO use $(CC), $(CXX), $(LD), and s$(RC) # TODO use $(CC), $(CXX), $(LD), and s$(RC)
$(OUT): $(OFILES) | $(OUTDIR) $(OUT): $(OFILES) | $(OUTDIR)
ifeq (,$(STATICLIB))
@link -out:$(OUT) $(OFILES) $(LDFLAGS) @link -out:$(OUT) $(OFILES) $(LDFLAGS)
else
@lib -out:$(OUT) $(OFILES)
endif
@echo ====== Linked $(OUT) @echo ====== Linked $(OUT)
.SECONDEXPANSION: .SECONDEXPANSION:

View File

@ -30,7 +30,11 @@ SUFFIX = $(EXESUFFIX)
# TODO merge with the one in build/GNUmakefile.test # TODO merge with the one in build/GNUmakefile.test
ifeq ($(TOOLCHAIN),gcc) ifeq ($(TOOLCHAIN),gcc)
ifeq (,$(STATIC))
LDFLAGS += -L$(OUTDIR) -lui LDFLAGS += -L$(OUTDIR) -lui
else
LDFLAGS += -L$(OUTDIR) -lui $(NATIVE_UI_LDFLAGS)
endif
# see build/GNUmakefile.test # see build/GNUmakefile.test
ifeq ($(OS),darwin) ifeq ($(OS),darwin)
LDFLAGS += -Wl,-rpath,@executable_path/ LDFLAGS += -Wl,-rpath,@executable_path/

View File

@ -17,10 +17,14 @@ HFILES += \
ui_$(OS)$(OSHSUFFIX) ui_$(OS)$(OSHSUFFIX)
NAME = libui NAME = libui
ifeq (,$(STATIC))
SUFFIX = $(LIBSUFFIX) SUFFIX = $(LIBSUFFIX)
ifeq ($(USESSONAME),1) ifeq ($(USESSONAME),1)
SUFFIX = $(SONAMEEXT) SUFFIX = $(SONAMEEXT)
endif endif
else
SUFFIX = $(STATICLIBSUFFIX)
endif
ifeq ($(TOOLCHAIN),gcc) ifeq ($(TOOLCHAIN),gcc)
# make every symbol hidden by default except _UI_EXTERN ones # make every symbol hidden by default except _UI_EXTERN ones

View File

@ -42,10 +42,7 @@ HFILES += \
# LONGTERM split into a separate file or put in GNUmakefile.libui somehow? # LONGTERM split into a separate file or put in GNUmakefile.libui somehow?
# flags for Cocoa # flags for Cocoa
LDFLAGS += \ LDFLAGS += $(NATIVE_UI_LDFLAGS)
-lobjc \
-framework Foundation \
-framework AppKit
# flags for OS X versioning # flags for OS X versioning
CFLAGS += \ CFLAGS += \
@ -57,9 +54,11 @@ CXXFLAGS += \
LDFLAGS += \ LDFLAGS += \
-mmacosx-version-min=10.8 -mmacosx-version-min=10.8
ifeq (,$(STATIC))
# flags for building a shared library # flags for building a shared library
LDFLAGS += \ LDFLAGS += \
-dynamiclib -dynamiclib
endif
# on warning about undefined symbols: # on warning about undefined symbols:
# the gcc flags don't work with Apple's linker # the gcc flags don't work with Apple's linker

View File

@ -3,6 +3,7 @@
EXESUFFIX = EXESUFFIX =
LIBSUFFIX = .dylib LIBSUFFIX = .dylib
OSHSUFFIX = .h OSHSUFFIX = .h
STATICLIBSUFFIX = .a
TOOLCHAIN = gcc TOOLCHAIN = gcc
USESSONAME = 1 USESSONAME = 1
@ -11,3 +12,9 @@ SONAMEEXT = .$(SOVERSION)$(LIBSUFFIX)
# note the explicit need for @rpath # note the explicit need for @rpath
# LONGTERM -current_version, -compatibility_version # LONGTERM -current_version, -compatibility_version
SONAMEFLAG = -Wl,-install_name,@rpath/ SONAMEFLAG = -Wl,-install_name,@rpath/
NATIVE_UI_LDFLAGS += \
-lobjc \
-framework Foundation \
-framework AppKit

View File

@ -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)

View File

@ -43,17 +43,16 @@ HFILES += \
# LONGTERM split into a separate file or put in GNUmakefile.libui somehow? # LONGTERM split into a separate file or put in GNUmakefile.libui somehow?
# flags for GTK+ # flags for GTK+
CFLAGS += \ CFLAGS += $(NATIVE_UI_CFLAGS)
`pkg-config --cflags gtk+-3.0` CXXFLAGS += $(NATIVE_UI_CXXFLAGS)
CXXFLAGS += \ LDFLAGS += $(NATIVE_UI_LDFLAGS)
`pkg-config --cflags gtk+-3.0`
LDFLAGS += \
`pkg-config --libs gtk+-3.0` -lm -ldl
# flags for building a shared library # 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 # 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 += \ LDFLAGS += \
-shared -shared
endif
# flags for warning on undefined symbols # flags for warning on undefined symbols
# this is not gcc-global because OS X doesn't support these flags # this is not gcc-global because OS X doesn't support these flags

View File

@ -3,6 +3,7 @@
EXESUFFIX = EXESUFFIX =
LIBSUFFIX = .so LIBSUFFIX = .so
OSHSUFFIX = .h OSHSUFFIX = .h
STATICLIBSUFFIX = .a
TOOLCHAIN = gcc TOOLCHAIN = gcc
# LONGTERM clean up all the NAMEs and SUFFIXs and NOSOSUFFIXs or whatever it was # LONGTERM clean up all the NAMEs and SUFFIXs and NOSOSUFFIXs or whatever it was
@ -11,3 +12,11 @@ SOVERSION = $(SOVERSION0)
SONAMEEXT = $(LIBSUFFIX).$(SOVERSION) SONAMEEXT = $(LIBSUFFIX).$(SOVERSION)
# this is not gcc-global because OS X uses a different filename format # this is not gcc-global because OS X uses a different filename format
SONAMEFLAG = -Wl,-soname, 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

15
unix/GNUosspecificlink.mk Normal file
View File

@ -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)

View File

@ -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 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 # flags for building a shared library
ifeq (,$(STATIC))
LDFLAGS += \ LDFLAGS += \
-dll -dll
endif
# TODO flags for warning on undefined symbols # TODO flags for warning on undefined symbols

View File

@ -3,6 +3,7 @@
EXESUFFIX = .exe EXESUFFIX = .exe
LIBSUFFIX = .dll LIBSUFFIX = .dll
OSHSUFFIX = .h OSHSUFFIX = .h
STATICLIBSUFFIX = .lib
TOOLCHAIN = msvc TOOLCHAIN = msvc
USESSONAME = 0 USESSONAME = 0