1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
| | Upstream-status: https://github.com/LIJI32/SameBoy/pull/662
diff --git a/Makefile b/Makefile
index a1bce3e..cea556e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,14 @@
# Make hacks
.INTERMEDIATE:
+# Library versioning, following libtool's 'version-info' scheme (see:
+# info '(libtool) Libtool versioning' or
+# https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html).
+LT_CURRENT := 0
+LT_REVISION := 0
+LT_AGE := 0
+LT_VERSION_INFO := $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
# Set target, configuration, version and destination folders
PLATFORM := $(shell uname -s)
@@ -33,11 +41,47 @@ else
DEFAULT := sdl
endif
+ifneq ($(LIBRARY),)
+DEFAULT += lib
+endif
+
+# Select whether libtool should build/link for static vs shared
+# libraries, or both.
+ifneq ($(LIBRARY),)
+ifeq ($(LIBRARY), shared)
+LT_MODE_ARG := -shared
+else ifeq ($(LIBRARY), static)
+LT_MODE_ARG := -static
+else
+# Build both static and shared libraries.
+LT_MODE_ARG :=
+endif
+endif
+
NULL := /dev/null
ifeq ($(PLATFORM),windows32)
NULL := NUL
endif
+# Strip a given prefix from a string.
+# arg1: The prefix to strip.
+# arg2: The text containing the prefix.
+# Return $text with $prefix stripped, else nothing.
+define strip_prefix =
+$(let stripped,$(subst $(1),,$(2)),$\
+ $(shell test "$(1)$(stripped)" = "$(2)" && echo $(stripped)))
+endef
+
+# Simplify a path for use with pkg-config, by replacing $prefix with '${prefix}'
+# arg1: prefix, e.g. an installation prefix, such as /usr/local.
+# arg2: pkgdir, e.g. a path such as $datadir, $bindir, etc.
+# arg3: pkg-config variable name, e.g. 'prefix' or 'exec_prefix'.
+# Defaults to 'prefix'.
+define simplify_pkgconf_dir =
+$(let stripped,$(call strip_prefix,$(1),$(2)),$\
+ $(if stripped,$${$(or $(3),prefix)}$(stripped),$(2)))
+endef
+
ifneq ($(shell which xdg-open 2> $(NULL))$(FREEDESKTOP),)
# Running on an FreeDesktop environment, configure for (optional) installation
DESTDIR ?=
@@ -46,6 +90,22 @@ DATA_DIR ?= $(PREFIX)/share/sameboy/
FREEDESKTOP ?= true
endif
+# Autoconf-style conventionally named variables.
+prefix ?= $(PREFIX)
+exec_prefix ?= $(prefix)
+includedir ?= $(prefix)/include
+bindir ?= $(exec_prefix)/bin
+libdir ?= $(exec_prefix)/lib
+datadir ?= $(prefix)/share
+
+# Prettified variants for use in the pkg-config file.
+override PKGCONF_EXEC_PREFIX = \
+ $(call simplify_pkgconf_dir,$(prefix),$(exec_prefix))
+override PKGCONF_INCLUDEDIR = \
+ $(call simplify_pkgconf_dir,$(prefix),$(includedir))
+override PKGCONF_LIBDIR = \
+ $(call simplify_pkgconf_dir,$(exec_prefix),$(libdir),exec_prefix)
+
default: $(DEFAULT)
ifeq ($(MAKECMDGOALS),)
@@ -101,6 +161,9 @@ BIN := build/bin
OBJ := build/obj
INC := build/include/sameboy
LIBDIR := build/lib
+PKGCONF_DIR := $(LIBDIR)/pkgconfig
+LIBTOOL_LIBRARY := $(LIBDIR)/libsameboy.la
+PKGCONF_FILE := $(PKGCONF_DIR)/sameboy.pc
BOOTROMS_DIR ?= $(BIN)/BootROMs
@@ -125,6 +188,26 @@ PKG_CONFIG := pkg-config
endif
endif
+# Libtool makes it easy to correctly build shared libraries with
+# version info on both MacOS and GNU/Linux; require it if building
+# libraries.
+ifneq ($(LIBRARY),)
+ifneq (, $(shell command -v libtool 2> $(NULL)))
+LIBTOOL := libtool
+LIBTOOL_CC := $(LIBTOOL) --tag=CC --mode=compile $(CC) -c
+LIBTOOL_LD := $(LIBTOOL) --tag=CC --mode=link $(CC) \
+ -version-info $(LT_VERSION_INFO) $(LT_MODE_ARG)
+else
+$(error "please install libtool")
+endif
+else
+# Not building libraries.
+LIBTOOL :=
+LIBTOOL_CC := $(CC)
+LIBTOOL_LD :=
+endif
+
+
ifeq ($(PLATFORM),windows32)
# To force use of the Unix version instead of the Windows version
MKDIR := $(shell which mkdir)
@@ -276,11 +359,6 @@ LDFLAGS += -Wl,/NODEFAULTLIB:libcmt.lib
endif
endif
-LIBFLAGS := -nostdlib -Wl,-r
-ifneq ($(PLATFORM),Darwin)
-LIBFLAGS += -no-pie
-endif
-
ifeq ($(CONF),debug)
CFLAGS += -g
else ifeq ($(CONF), release)
@@ -336,11 +414,14 @@ tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin $
_ios: $(BIN)/SameBoy-iOS.app $(OBJ)/installer
ios-ipa: $(BIN)/SameBoy-iOS.ipa
ios-deb: $(BIN)/SameBoy-iOS.deb
+
+# Libraries.
ifeq ($(PLATFORM),windows32)
lib: lib-unsupported
-else
-lib: $(LIBDIR)/libsameboy.o $(LIBDIR)/libsameboy.a
+else ifneq ($(LIBRARY),)
+lib: $(LIBTOOL_LIBRARY) $(PKGCONF_FILE)
endif
+
all: sdl tester libretro lib
ifeq ($(PLATFORM),Darwin)
all: cocoa ios-ipa ios-deb
@@ -361,6 +442,10 @@ CORE_SOURCES += $(shell ls Windows/*.c)
endif
CORE_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(CORE_SOURCES))
+# Libtool PIC objects are created along the .o variants, when building
+# a shared library.
+CORE_LOBJECTS := $(patsubst %,$(OBJ)/%.lo,$(CORE_SOURCES))
+$(CORE_LOBJECTS): $(CORE_OBJECTS)
PUBLIC_HEADERS := $(patsubst Core/%,$(INC)/%,$(CORE_HEADERS))
COCOA_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(COCOA_SOURCES))
IOS_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(IOS_SOURCES))
@@ -404,30 +489,30 @@ $(OBJ)/%.dep: %
$(OBJ)/Core/%.c.o: Core/%.c
-@$(MKDIR) -p $(dir $@)
- $(CC) $(CFLAGS) $(FAT_FLAGS) -DGB_INTERNAL -c $< -o $@
+ $(LIBTOOL_CC) $(CFLAGS) $(FAT_FLAGS) -DGB_INTERNAL -c $< -o $@
$(OBJ)/SDL/%.c.o: SDL/%.c
-@$(MKDIR) -p $(dir $@)
- $(CC) $(CFLAGS) $(FRONTEND_CFLAGS) $(FAT_FLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -c $< -o $@
+ $(LIBTOOL_CC) $(CFLAGS) $(FRONTEND_CFLAGS) $(FAT_FLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -c $< -o $@
$(OBJ)/OpenDialog/%.c.o: OpenDialog/%.c
-@$(MKDIR) -p $(dir $@)
- $(CC) $(CFLAGS) $(FRONTEND_CFLAGS) $(FAT_FLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -c $< -o $@
+ $(LIBTOOL_CC) $(CFLAGS) $(FRONTEND_CFLAGS) $(FAT_FLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -c $< -o $@
$(OBJ)/%.c.o: %.c
-@$(MKDIR) -p $(dir $@)
- $(CC) $(CFLAGS) $(FRONTEND_CFLAGS) $(FAT_FLAGS) -c $< -o $@
+ $(LIBTOOL_CC) $(CFLAGS) $(FRONTEND_CFLAGS) $(FAT_FLAGS) -c $< -o $@
# HexFiend requires more flags
$(OBJ)/HexFiend/%.m.o: HexFiend/%.m
-@$(MKDIR) -p $(dir $@)
- $(CC) $(CFLAGS) $(FRONTEND_CFLAGS) $(FAT_FLAGS) $(OCFLAGS) -c $< -o $@ -fno-objc-arc -include HexFiend/HexFiend_2_Framework_Prefix.pch
+ $(LIBTOOL_CC) $(CFLAGS) $(FRONTEND_CFLAGS) $(FAT_FLAGS) $(OCFLAGS) -c $< -o $@ -fno-objc-arc -include HexFiend/HexFiend_2_Framework_Prefix.pch
$(OBJ)/%.m.o: %.m
-@$(MKDIR) -p $(dir $@)
- $(CC) $(CFLAGS) $(FRONTEND_CFLAGS) $(FAT_FLAGS) $(OCFLAGS) -c $< -o $@
-
+ $(LIBTOOL_CC) $(CFLAGS) $(FRONTEND_CFLAGS) $(FAT_FLAGS) $(OCFLAGS) -c $< -o $@
+
# iOS Port
$(BIN)/SameBoy-iOS.app: $(BIN)/SameBoy-iOS.app/SameBoy \
@@ -653,15 +738,28 @@ libretro:
# Does not install mimetype icons because FreeDesktop is cursed abomination with no right to exist.
# If you somehow find a reasonable way to make associate an icon with an extension in this dumpster
# fire of a desktop environment, open an issue or a pull request
+# Install for Linux, and other FreeDesktop platforms.
+install_headers = install -Dm 644 -t $(DESTDIR)$(includedir)/sameboy $(INC)/*
+install_pkgconf_file = install -Dm 644 -t $(DESTDIR)$(libdir)/pkgconfig $(PKGCONF_FILE)
+
ifneq ($(FREEDESKTOP),)
ICON_NAMES := apps/sameboy mimetypes/x-gameboy-rom mimetypes/x-gameboy-color-rom
ICON_SIZES := 16x16 32x32 64x64 128x128 256x256 512x512
ICONS := $(foreach name,$(ICON_NAMES), $(foreach size,$(ICON_SIZES),$(DESTDIR)$(PREFIX)/share/icons/hicolor/$(size)/$(name).png))
+ifneq ($(LIBRARY),)
+install: lib pkgconf
+endif
+
install: sdl $(DESTDIR)$(PREFIX)/share/mime/packages/sameboy.xml $(ICONS) FreeDesktop/sameboy.desktop
-@$(MKDIR) -p $(dir $(DESTDIR)$(PREFIX))
mkdir -p $(DESTDIR)$(DATA_DIR)/ $(DESTDIR)$(PREFIX)/bin/
cp -rf $(BIN)/SDL/* $(DESTDIR)$(DATA_DIR)/
mv $(DESTDIR)$(DATA_DIR)/sameboy $(DESTDIR)$(PREFIX)/bin/sameboy
+ifneq ($(LIBRARY),)
+ $(install_headers)
+ $(install_pkgconf_file)
+ $(LIBTOOL) --mode=install install -D $(LIBTOOL_LIBRARY) $(libdir)/libsameboy.la
+endif
ifeq ($(DESTDIR),)
-update-mime-database -n $(PREFIX)/share/mime
-xdg-desktop-menu install --novendor --mode system FreeDesktop/sameboy.desktop
@@ -727,20 +825,23 @@ $(OBJ)/control.tar.gz: iOS/deb-postinst iOS/deb-prerm iOS/deb-control
$(OBJ)/debian-binary:
-@$(MKDIR) -p $(dir $@)
echo 2.0 > $@
-
-$(LIBDIR)/libsameboy.o: $(CORE_OBJECTS)
+
+# Link library objects with libtool.
+$(LIBTOOL_LIBRARY): $(CORE_LOBJECTS)
-@$(MKDIR) -p $(dir $@)
- @# This is a somewhat simple hack to force Clang and GCC to build a native object file out of one or many LTO objects
- echo "static const char __attribute__((used)) x=0;"| $(CC) $(filter-out -flto,$(CFLAGS)) -c -x c - -o $(OBJ)/lto_hack.o
- @# And this is a somewhat complicated hack to invoke the correct LTO-enabled LD command in a mostly cross-platform nature
- $(CC) $(FAT_FLAGS) $(CFLAGS) $(LIBFLAGS) $^ $(OBJ)/lto_hack.o -o $@
- -@rm $(OBJ)/lto_hack.o
-
-$(LIBDIR)/libsameboy.a: $(LIBDIR)/libsameboy.o
+ $(LIBTOOL_LD) -rpath $(libdir) $^ -o $@
+
+$(PKGCONF_FILE): sameboy.pc.in
-@$(MKDIR) -p $(dir $@)
-@rm -f $@
- ar -crs $@ $^
-
+ sed -e 's,@prefix@,$(prefix),' \
+ -e 's/@version@/$(VERSION)/' \
+ -e 's,@exec_prefix@,$(PKGCONF_EXEC_PREFIX),' \
+ -e 's,@includedir@,$(PKGCONF_INCLUDEDIR),' \
+ -e 's,@libdir@,$(PKGCONF_LIBDIR),' $< > $@
+
+pkgconf: $(PKGCONF_FILE)
+
$(INC)/%.h: Core/%.h
-@$(MKDIR) -p $(dir $@)
-@# CPPP doesn't like multibyte characters, so we replace the single quote character before processing so it doesn't complain
@@ -754,4 +855,4 @@ lib-unsupported:
clean:
rm -rf build
-.PHONY: libretro tester cocoa ios _ios ios-ipa ios-deb liblib-unsupported bootroms
+.PHONY: libretro tester cocoa ios _ios ios-ipa ios-deb lib lib-unsupported bootroms pkgconf
diff --git a/README.md b/README.md
index 9c5f8da..e23f2ca 100644
--- a/README.md
+++ b/README.md
@@ -53,12 +53,18 @@ On Windows, SameBoy also requires:
To compile, simply run `make`. The targets are:
* `cocoa` (Default for macOS)
* `sdl` (Default for everything else)
- * `lib` (Creates libsameboy.o and libsameboy.a for statically linking SameBoy, as well as a headers directory with corresponding headers; currently not supported on Windows due to linker limitations)
+ * `lib` (Creates libsameboy.o, libsameboy.a and libsameboy.so for linking SameBoy, as well as a headers directory with corresponding headers; currently not supported on Windows due to linker limitations)
* `ios` (Plain iOS .app bundle), `ios-ipa` (iOS IPA archive for side-loading), `ios-deb` (iOS deb package for jailbroken devices)
* `libretro`
* `bootroms`
* `tester`
+For convenience, when installing the static and shared libraries is
+desired, you can specify the LIBRARY=1 make variable to have the
+libraries built as part of the default target, as well as installed,
+along the headers. Alternatively, `LIBRARY=shared` will install just
+the shared library, while `LIBRARY=static` only the static one.
+
You may also specify `CONF=debug` (default), `CONF=release`, `CONF=native_release` or `CONF=fat_release` to control optimization, symbols and multi-architectures. `native_release` is faster than `release`, but is optimized to the host's CPU and therefore is not portable. `fat_release` is exclusive to macOS and builds x86-64 and ARM64 fat binaries; this requires using a recent enough `clang` and macOS SDK using `xcode-select`, or setting them explicitly with `CC=` and `SYSROOT=`, respectively. All other configurations will build to your host architecture, except for the iOS targets. You may set `BOOTROMS_DIR=...` to a directory containing precompiled boot ROM files, otherwise the build system will compile and use SameBoy's own boot ROMs.
The SDL port will look for resource files with a path relative to executable and inside the directory specified by the `DATA_DIR` variable. If you are packaging SameBoy, you may wish to override this by setting the `DATA_DIR` variable during compilation to the target path of the directory containing all files (apart from the executable, that's not necessary) from the `build/bin/SDL` directory in the source tree. Make sure the variable ends with a `/` character. On FreeDesktop environments, `DATA_DIR` will default to `/usr/local/share/sameboy/`. `PREFIX` and `DESTDIR` follow their standard usage and default to an empty string an `/usr/local`, respectively
diff --git a/sameboy.pc.in b/sameboy.pc.in
new file mode 100644
index 0000000..dc0ca0b
--- /dev/null
+++ b/sameboy.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+
+Name: sameboy
+Description: The SameBoy library
+Version: @version@
+Cflags: -I${includedir}/sameboy
+Libs: -L${libdir} -lsameboy
|