1#   -*-makefile-*-
2#   application.make
3#
4#   Instance Makefile rules to build GNUstep-based applications.
5#
6#   Copyright (C) 1997 - 2010 Free Software Foundation, Inc.
7#
8#   Author:  Nicola Pero <nicola.pero@meta-innovation.com>
9#   Author:  Ovidiu Predescu <ovidiu@net-community.com>
10#   Based on the original version by Scott Christley.
11#
12#   This file is part of the GNUstep Makefile Package.
13#
14#   This library is free software; you can redistribute it and/or
15#   modify it under the terms of the GNU General Public License
16#   as published by the Free Software Foundation; either version 3
17#   of the License, or (at your option) any later version.
18#
19#   You should have received a copy of the GNU General Public
20#   License along with this library; see the file COPYING.
21#   If not, write to the Free Software Foundation,
22#   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
24# Applications usually link against a gui library (if available).
25ifeq ($(NEEDS_GUI),)
26  NEEDS_GUI = yes
27endif
28
29#
30# Include in the common makefile rules
31#
32ifeq ($(RULES_MAKE_LOADED),)
33  include $(GNUSTEP_MAKEFILES)/rules.make
34endif
35
36#
37# The name of the application is in the APP_NAME variable.
38# The list of application resource directories is in xxx_RESOURCE_DIRS
39# The list of application resource files is in xxx_RESOURCE_FILES
40# The list of localized resource files is in xxx_LOCALIZED_RESOURCE_FILES
41# The list of supported languages is in xxx_LANGUAGES
42# The name of the application icon (if any) is in xxx_APPLICATION_ICON
43# The name of the app class is xxx_PRINCIPAL_CLASS (defaults to NSApplication).
44#
45# If you want to insert your own entries into Info.plist (or
46# Info-gnustep.plist) you should create a xxxInfo.plist file (where
47# xxx is the application name) and gnustep-make will automatically
48# read it and merge it into Info-gnustep.plist.
49#
50
51.PHONY: internal-app-all_ \
52        internal-app-install_ \
53        internal-app-uninstall_ \
54        internal-app-copy_into_dir \
55        internal-application-build-template \
56        internal-app-run-compile-submake \
57        internal-app-compile
58
59#
60# Determine where to install.  By default, install into GNUSTEP_APPS.
61#
62ifneq ($($(GNUSTEP_INSTANCE)_INSTALL_DIR),)
63  APP_INSTALL_DIR = $($(GNUSTEP_INSTANCE)_INSTALL_DIR)
64endif
65
66ifeq ($(APP_INSTALL_DIR),)
67  APP_INSTALL_DIR = $(GNUSTEP_APPS)
68endif
69
70APP_DIR_NAME = $(GNUSTEP_INSTANCE:=.$(APP_EXTENSION))
71APP_DIR = $(GNUSTEP_BUILD_DIR)/$(APP_DIR_NAME)
72
73#
74# Now include the standard resource-bundle routines from Shared/bundle.make
75#
76
77ifneq ($(FOUNDATION_LIB), apple)
78  # GNUstep bundle
79  GNUSTEP_SHARED_BUNDLE_RESOURCE_PATH = $(APP_DIR)/Resources
80  APP_INFO_PLIST_FILE = $(APP_DIR)/Resources/Info-gnustep.plist
81else
82  # OSX bundle
83  GNUSTEP_SHARED_BUNDLE_RESOURCE_PATH = $(APP_DIR)/Contents/Resources
84  APP_INFO_PLIST_FILE = $(APP_DIR)/Contents/Info.plist
85endif
86GNUSTEP_SHARED_BUNDLE_INSTALL_NAME = $(APP_DIR_NAME)
87GNUSTEP_SHARED_BUNDLE_INSTALL_LOCAL_PATH = .
88GNUSTEP_SHARED_BUNDLE_INSTALL_PATH = $(APP_INSTALL_DIR)
89include $(GNUSTEP_MAKEFILES)/Instance/Shared/bundle.make
90
91ifneq ($(FOUNDATION_LIB), apple)
92APP_FILE_NAME = $(APP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR)/$(GNUSTEP_INSTANCE)$(EXEEXT)
93else
94APP_FILE_NAME = $(APP_DIR_NAME)/Contents/MacOS/$(GNUSTEP_INSTANCE)$(EXEEXT)
95endif
96
97APP_FILE = $(GNUSTEP_BUILD_DIR)/$(APP_FILE_NAME)
98
99
100#
101# Internal targets
102#
103
104# If building on Windows, also generate an import library which can be
105# used by loadable bundles to resolve symbols in the application.  If
106# a loadable bundle/palette needs to use symbols in the application,
107# it just needs to link against this APP_NAME/APP_NAME.exe.a library.
108# We add .exe to the application name to account for Gorm which is
109# using the same name for the library (libGorm.dll.a) and for the
110# application (Gorm.exe).  Using this terminology, just add
111# Gorm.app/Gorm.exe.a to the list of objects you link and you get it
112# working.  TODO: Move this into target.make
113ifeq ($(BUILD_DLL), yes)
114  ALL_LDFLAGS += -Wl,--export-all-symbols -Wl,--out-implib,$(GNUSTEP_BUILD_DIR)/$(APP_DIR_NAME)/$(GNUSTEP_TARGET_LDIR)/$(GNUSTEP_INSTANCE).exe$(LIBEXT)
115endif
116
117# If building on MinGW, also mark the application as a 'GUI'
118# application.  This prevents an ugly terminal window from being
119# automatically opened when you start your application directly by
120# double-clicking on the .exe icon in the Windows file manager.  TODO:
121# Move this into target.make, but somehow make sure it is only used
122# when linking applications.
123ifeq ($(findstring mingw32, $(GNUSTEP_TARGET_OS)), mingw32)
124  ALL_LDFLAGS += -Wl,-subsystem,windows
125else ifeq ($(findstring mingw64, $(GNUSTEP_TARGET_OS)), mingw32)
126  ALL_LDFLAGS += -Wl,-subsystem,windows
127endif
128
129$(APP_FILE): $(OBJ_FILES_TO_LINK)
130ifeq ($(OBJ_FILES_TO_LINK),)
131	$(WARNING_EMPTY_LINKING)
132endif
133	$(ECHO_LINKING)$(LD) $(ALL_LDFLAGS) $(CC_LDFLAGS) -o $(LDOUT)$@ \
134	$(OBJ_FILES_TO_LINK) $(ALL_LIB_DIRS) $(ALL_LIBS)$(END_ECHO)
135
136#
137# Compilation targets
138#
139ifeq ($(GNUSTEP_MAKE_PARALLEL_BUILDING), no)
140# Standard building
141internal-app-run-compile-submake: $(APP_FILE)
142else
143# Parallel building.  The actual compilation is delegated to a
144# sub-make invocation where _GNUSTEP_MAKE_PARALLEL is set to yet.
145# That sub-make invocation will compile files in parallel.
146internal-app-run-compile-submake:
147	$(ECHO_NOTHING_RECURSIVE_MAKE)$(MAKE) -f $(MAKEFILE_NAME) --no-print-directory --no-keep-going \
148	internal-app-compile \
149	GNUSTEP_TYPE=$(GNUSTEP_TYPE) \
150	GNUSTEP_INSTANCE=$(GNUSTEP_INSTANCE) \
151	GNUSTEP_OPERATION=compile \
152	GNUSTEP_BUILD_DIR="$(GNUSTEP_BUILD_DIR)" \
153	_GNUSTEP_MAKE_PARALLEL=yes$(END_ECHO_RECURSIVE_MAKE)
154
155internal-app-compile: $(APP_FILE)
156endif
157
158ifeq ($(FOUNDATION_LIB), apple)
159internal-app-all_:: $(GNUSTEP_OBJ_INSTANCE_DIR) \
160                    $(OBJ_DIRS_TO_CREATE) \
161                    $(APP_DIR)/Contents/MacOS \
162                    internal-app-run-compile-submake \
163                    shared-instance-bundle-all \
164                    $(APP_INFO_PLIST_FILE)
165# If they specified Info.plist in the xxx_RESOURCE_FILES, print a
166# warning. They are supposed to provide a xxxInfo.plist which gets
167# merged with the automatically generated entries to generate
168# Info.plist.
169ifneq ($(filter Info.plist,$($(GNUSTEP_INSTANCE)_RESOURCE_FILES)),)
170	$(WARNING_INFO_PLIST)
171endif
172
173$(APP_DIR)/Contents/MacOS:
174	$(ECHO_CREATING)$(MKDIRS) $@$(END_ECHO)
175
176else
177
178internal-app-all_:: $(GNUSTEP_OBJ_INSTANCE_DIR) \
179                    $(OBJ_DIRS_TO_CREATE) \
180                    $(APP_DIR)/$(GNUSTEP_TARGET_LDIR) \
181                    internal-app-run-compile-submake \
182                    internal-application-build-template \
183                    $(APP_DIR)/Resources \
184                    $(APP_INFO_PLIST_FILE) \
185                    $(APP_DIR)/Resources/$(GNUSTEP_INSTANCE).desktop \
186                    shared-instance-bundle-all
187# If they specified Info-gnustep.plist in the xxx_RESOURCE_FILES,
188# print a warning. They are supposed to provide a xxxInfo.plist which
189# gets merged with the automatically generated entries to generate
190# Info-gnustep.plist.
191ifneq ($(filter Info-gnustep.plist,$($(GNUSTEP_INSTANCE)_RESOURCE_FILES)),)
192	$(WARNING_INFO_GNUSTEP_PLIST)
193endif
194
195$(APP_DIR)/$(GNUSTEP_TARGET_LDIR):
196	$(ECHO_CREATING)$(MKDIRS) $@$(END_ECHO)
197
198ifeq ($(GNUSTEP_IS_FLATTENED), no)
199internal-application-build-template: $(APP_DIR)/$(GNUSTEP_INSTANCE)
200
201$(APP_DIR)/$(GNUSTEP_INSTANCE):
202	$(ECHO_NOTHING)cp $(GNUSTEP_MAKEFILES)/executable.template \
203	   $(APP_DIR)/$(GNUSTEP_INSTANCE); \
204	chmod a+x $(APP_DIR)/$(GNUSTEP_INSTANCE)$(END_ECHO)
205ifneq ($(CHOWN_TO),)
206	$(ECHO_CHOWNING)$(CHOWN) $(CHOWN_TO) $(APP_DIR)/$(GNUSTEP_INSTANCE)$(END_ECHO)
207endif
208else
209internal-application-build-template:
210
211endif
212endif
213
214PRINCIPAL_CLASS = $(strip $($(GNUSTEP_INSTANCE)_PRINCIPAL_CLASS))
215
216ifeq ($(PRINCIPAL_CLASS),)
217  PRINCIPAL_CLASS = NSApplication
218endif
219
220APPLICATION_ICON = $($(GNUSTEP_INSTANCE)_APPLICATION_ICON)
221
222MAIN_MODEL_FILE = $(strip $(subst .gmodel,,$(subst .gorm,,$(subst .nib,,$($(GNUSTEP_INSTANCE)_MAIN_MODEL_FILE)))))
223
224MAIN_MARKUP_FILE = $(strip $(subst .gsmarkup,,$($(GNUSTEP_INSTANCE)_MAIN_MARKUP_FILE)))
225
226# We must recreate Info.plist if PRINCIPAL_CLASS and/or
227# APPLICATION_ICON and/or MAIN_MODEL_FILE and/or MAIN_MARKUP_FILE has
228# changed since last time we built Info.plist.  We use
229# stamp-string.make, which will store the variables in a stamp file
230# inside GNUSTEP_STAMP_DIR, and rebuild Info.plist if
231# GNUSTEP_STAMP_STRING changes.  We will also depend on xxxInfo.plist
232# if any.
233GNUSTEP_STAMP_STRING = $(PRINCIPAL_CLASS)-$(APPLICATION_ICON)-$(MAIN_MODEL_FILE)-$(MAIN_MARKUP_FILE)
234
235ifneq ($(FOUNDATION_LIB),apple)
236GNUSTEP_STAMP_DIR = $(APP_DIR)
237
238# Only for efficiency
239$(GNUSTEP_STAMP_DIR): $(APP_DIR)/$(GNUSTEP_TARGET_LDIR)
240else
241# Everything goes in $(APP_DIR)/Contents on Apple
242GNUSTEP_STAMP_DIR = $(APP_DIR)/Contents
243endif
244
245include $(GNUSTEP_MAKEFILES)/Instance/Shared/stamp-string.make
246
247# On Apple we assume that xxxInfo.plist has a '{' (and nothing else)
248# on the first line, and the rest of the file is a plain property list
249# dictionary.  You must make sure your xxxInfo.plist is in this format
250# to use it on Apple.
251
252# The problem is, we need to add the automatically generated entries
253# to this custom dictionary on Apple - to do that, we generate '{'
254# followed by the custom entries, followed by xxxInfo.plist (with the
255# first line removed), or by '}'.  NB: "sed '1d' filename" prints out
256# filename, except the first line.
257
258# On GNUstep we use plmerge which is much slower, but should probably
259# be safer, because as soon as xxxInfo.plist is in plist format, it
260# should always work (even if the first line is not just a '{' and
261# nothing else).
262
263ifeq ($(FOUNDATION_LIB), apple)
264$(APP_INFO_PLIST_FILE): $(GNUSTEP_STAMP_DEPEND) $(GNUSTEP_PLIST_DEPEND)
265	$(ECHO_CREATING)(echo "{"; echo '  NOTE = "Automatically generated, do not edit!";'; \
266	  echo "  NSExecutable = \"$(GNUSTEP_INSTANCE)\";"; \
267	  echo "  NSMainNibFile = \"$(MAIN_MODEL_FILE)\";"; \
268	  echo "  GSMainMarkupFile = \"$(MAIN_MARKUP_FILE)\";"; \
269	  if [ "$(APPLICATION_ICON)" != "" ]; then \
270	    echo "  CFBundleIconFile = \"$(APPLICATION_ICON)\";"; \
271	  fi; \
272	  echo "  NSPrincipalClass = \"$(PRINCIPAL_CLASS)\";"; \
273	  if [ -r "$(GNUSTEP_PLIST_DEPEND)" ]; then \
274	    sed '1d' "$(GNUSTEP_PLIST_DEPEND)"; \
275	  else \
276	    echo "}"; \
277	  fi) > $@$(END_ECHO)
278else
279
280$(APP_INFO_PLIST_FILE): $(GNUSTEP_STAMP_DEPEND) $(GNUSTEP_PLIST_DEPEND)
281	$(ECHO_CREATING)(echo "{"; echo '  NOTE = "Automatically generated, do not edit!";'; \
282	  echo "  NSExecutable = \"$(GNUSTEP_INSTANCE)\";"; \
283	  echo "  NSMainNibFile = \"$(MAIN_MODEL_FILE)\";"; \
284	  echo "  GSMainMarkupFile = \"$(MAIN_MARKUP_FILE)\";"; \
285	  if [ "$(APPLICATION_ICON)" != "" ]; then \
286	    echo "  NSIcon = \"$(APPLICATION_ICON)\";"; \
287	  fi; \
288	  echo "  NSPrincipalClass = \"$(PRINCIPAL_CLASS)\";"; \
289	  echo "}") >$@$(END_ECHO)
290	 -$(ECHO_NOTHING)if [ -r "$(GNUSTEP_PLIST_DEPEND)" ]; then \
291	   plmerge $@ "$(GNUSTEP_PLIST_DEPEND)"; \
292	  fi$(END_ECHO)
293
294$(APP_DIR)/Resources/$(GNUSTEP_INSTANCE).desktop: $(APP_INFO_PLIST_FILE)
295	$(ECHO_CREATING)pl2link $^ $(APP_DIR)/Resources/$(GNUSTEP_INSTANCE).desktop; \
296	                 chmod a+x $(APP_DIR)/Resources/$(GNUSTEP_INSTANCE).desktop$(END_ECHO)
297
298endif
299
300internal-app-copy_into_dir:: shared-instance-bundle-copy_into_dir
301
302#
303# install/uninstall targets
304#
305$(APP_INSTALL_DIR):
306	$(ECHO_CREATING)$(MKINSTALLDIRS) $@$(END_ECHO)
307
308internal-app-install_:: shared-instance-bundle-install internal-install-app-wrapper
309ifeq ($(strip),yes)
310	$(ECHO_STRIPPING)$(STRIP) $(APP_INSTALL_DIR)/$(APP_FILE_NAME)$(END_ECHO)
311endif
312
313internal-app-uninstall_:: shared-instance-bundle-uninstall internal-uninstall-app-wrapper
314
315#
316# Normally, to start up an application from the command-line you would
317# need to use something like 'openapp Gorm.app'.  To make this easier
318# for end-users, we create a 'Gorm' executable inside GNUSTEP_TOOLS
319# that does just that.  Your environment needs to be setup (PATH and
320# library path properly setup) to use this executable.  But that's OK;
321# if your environment is not setup, then GNUSTEP_TOOLS wouldn't be
322# in your PATH and so typing 'openapp' or 'Gorm' at the command-line
323# would do nothing anyway because they wouldn't be found! ;-)
324#
325# If your environment is difficult (and you can't fix it), then you
326# should stick with 'openapp', and you may need to specify the whole
327# PATH to openapp so that it is found.  Eg,
328# /usr/GNUstep/System/Tools/openapp Gorm.app.  That will do a full
329# GNUstep environment setup and should work no matter what.
330#
331# If we have symlinks, we simply create a symlink from
332# GNUSTEP_TOOLS/GNUSTEP_TARGET_LDIR to APP_INSTALL_DIR/APP_FILE_NAME.
333# This is the fastest way to start up your application; it just jumps
334# to the executable file.  In fact, it is much faster than openapp.
335#
336# If we don't have symlinks, we install an app-wrapper consisting of a
337# one-liner shell script that will start openapp.  This will be
338# slower.
339#
340# These are the rules to create/delete this 'wrapper'.
341#
342$(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR):
343	$(ECHO_CREATING)$(MKINSTALLDIRS) $@$(END_ECHO)
344
345ifeq ($(HAS_LN_S), yes)
346# We generate a relative symlink.  This makes it easier to use DESTDIR
347# and other packaging relocation tricks.
348internal-install-app-wrapper: $(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR)
349	$(ECHO_NOTHING)\
350	  cd $(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR); \
351	  $(RM_LN_S) $(GNUSTEP_INSTANCE); \
352	  $(LN_S_RECURSIVE) `$(REL_PATH_SCRIPT) $(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR) $(APP_INSTALL_DIR)/$(APP_FILE_NAME) short` \
353	          $(GNUSTEP_INSTANCE)$(END_ECHO)
354else
355# Not sure that we can use relative paths with 'exec' in a portable
356# way.  We want the stuff to work with DESTDIR, so in this case we use
357# openapp in the app wrapper.  Much slower, but should work fine.
358internal-install-app-wrapper: $(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR)
359	$(ECHO_NOTHING)cat $(GNUSTEP_MAKEFILES)/app-wrapper.template \
360	                 | sed -e "s@GNUSTEP_INSTANCE@$(GNUSTEP_INSTANCE)@" > $(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR)/$(GNUSTEP_INSTANCE); \
361	               chmod a+x $(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR)/$(GNUSTEP_INSTANCE)$(END_ECHO)
362ifneq ($(CHOWN_TO),)
363	$(ECHO_CHOWNING)$(CHOWN) $(CHOWN_TO) $(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR)/$(GNUSTEP_INSTANCE)$(END_ECHO)
364endif
365endif
366
367internal-uninstall-app-wrapper:
368	$(ECHO_NOTHING)$(RM) -f $(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR)/$(GNUSTEP_INSTANCE)$(END_ECHO)
369
370include $(GNUSTEP_MAKEFILES)/Instance/Shared/strings.make
371