#============================================================================== # Jam configuration and actions for MacOS/X # Copyright (C) 2003-2005 by Eric Sunshine # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published by # the Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public # License for more details. # # You should have received a copy of the GNU Library General Public License # along with this library; if not, write to the Free Software Foundation, # Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #============================================================================== SHELL ?= "/bin/sh" ; MACOSX_ENVIRONMENT = "export MACOSX_DEPLOYMENT_TARGET=10.2" ; PLUGIN.LFLAGS += "-bundle" ; # We use the ugly -Wl form, which does not contain embedded whitespace (unlike # "-framework AppKit"), to help external projects which use the result of # "cs-config --libs" in conjunction with GNU libtool, since libtool likes to # re-arrange arguments, not realizing that "-framwork" and "AppKit" need to # stay together. LINKLIBS += "-Wl,-framework,AppKit" "-Wl,-framework,Foundation" ; # Jambase in Jam 2.4 has a bug where it incorrectly defines RANLIB as "" for # MacOS/X, and this bogus value will override a RANLIB set via ?= in Jamconfig, # by a configure script, thus we must give RANLIB an appropriate value here if # we find that it has the bogus value. Jam 2.5 does not contain this bug. # Furthermore, MacOS/X Panther expects us to use the -s option with ranlib. if ! $(RANLIB) { RANLIB = "ranlib" ; } RANLIB += "-s" ; # Experience seems to indicate that library scanning misbehaves on MacOS/X with # Jam 2.4, consequently we disable it. NOARSCAN = true ; #------------------------------------------------------------------------------ # Public rules. #------------------------------------------------------------------------------ # ConstructApplicationTarget target : options # Constructs the application target name. rule ConstructApplicationTarget { return $(<) ; } # ConstructStaticLibraryTarget target : options # Constructs the static library target name. rule ConstructStaticLibraryTarget { return lib$(<)$(SUFLIB) ; } # ConstructSharedLibraryTarget target : options # Constructs the shared library target name. rule ConstructSharedLibraryTarget { return lib$(<).$(PACKAGE_VERSION).dylib ; } # ConstructSharedLibraryLinkLib target : options # Constructs the name of a shared library against which some other target # links. rule ConstructSharedLibraryLinkLib { return lib$(<).$(PACKAGE_VERSION).dylib ; } # ConstructPluginTarget target : options # Constructs the plugin target name. rule ConstructPluginTarget { return $(<).csbundle ; } # SystemLinkApplication target : objects : options # Apply appropriate rule to link the application based upon the options. rule SystemLinkApplication { local target = $($(<)_TARGET) ; Depends $(target) : $(>) ; if [ IsElem console : $(3) ] { LinkApplicationConsole $(target) : $(>) ; Clean clean : $(target) ; Clean $(<)clean : $(target) ; } else { CreateApplicationWrapper $(target) : $(>) ; CleanDir clean : [ Wrapper $(<) : app ] ; CleanDir $(<)clean : [ Wrapper $(<) : app ] ; } } # SystemInstallApplication target : subdirs : options # Apply appropriate rule to install the application based upon the options. rule SystemInstallApplication { if [ IsElem console : $(3) ] { Depends install_bin : [ DoInstall $(<) : $(bindir) $(2) : $(INSTALL_PROGRAM) ] ; } else { InstallApplicationGUI $(<) : $(bindir) $(2) ; } } # SystemInstallPlugin target : subdirs : options # Apply appropriate rule to install the plugin based upon the options. rule SystemInstallPlugin { Depends install_plugin : [ DoInstall $(<) : $(plugindir) $(2) : $(INSTALL_PROGRAM) ] ; } # SystemLinkPlugin target : objects : options # Link a plugin module and handle meta-data appropriately. rule SystemLinkPlugin { local target = $($(<)_TARGET) ; Depends $(target) : $(>) ; LinkPlugin $(target) : $(>) ; PluginMetaData $(<) : $($(<)_METAFILE) : $(3) ; Clean clean : $(target) ; Clean $(<)clean : $(target) ; } # LinkPlugin plugin : objects # Link a plugin module from a set of object files. actions LinkPlugin bind NEEDLIBS bind EXTRAOBJECTS { $(MACOSX_ENVIRONMENT) $(CMD.LINK) -bundle -o $(<) $(>) $(EXTRAOBJECTS) $(NEEDLIBS) $(LINKLIBS) } # LinkApplicationConsole exe : objects # Link a console (non-GUI) appliation from a set of object files. actions LinkApplicationConsole bind NEEDLIBS bind EXTRAOBJECTS { $(MACOSX_ENVIRONMENT) $(CMD.LINK) -o $(<) $(>) $(EXTRAOBJECTS) $(NEEDLIBS) $(LINKLIBS) } # CreateApplicationWrapper basename : objects # Create a complete, though minimal, application wrapper given a set of # object files. The rules ApplicationIconDefault and ApplicationIcon # control the icon associated with the application wrapper. rule CreateApplicationWrapper { WrapFile $(<) : $(<) : Contents MacOS : AppExe : $(>) ; WrapFile $(<) : PkgInfo : Contents : AppPkgInfo : $(>) ; WrapFile $(<) : version.plist : Contents : AppVersionPlist : $(>) ; WrapFile $(<) : Info.plist : Contents : AppInfoPlist : $(>) ; WrapFile $(<) : InfoPlist.strings : Contents Resources English.lproj : AppInfoPlistStrings : $(>) ; local icon = [ ApplicationIcon macosx : $(<) ] ; if ! $(icon) { local apptype = gui ; if [ IsElem console : $(>) ] { apptype = console ; } icon = [ ApplicationIconDefault macosx : $(apptype) ] ; } if $(icon) { $(<)_APPICON = $(icon) ; AppIcon $(<) : $(icon) ; } } # Wrapper basename : suffix [ : pathcomponents ] # Returns wrapper name in the directory specified by pathcomponents for # the given basename. If pathcomponents is omitted, LOCATE.TARGETS is # used. rule Wrapper { local dir ; if $(3) { dir = [ FDirName $(3) ] ; } else { dir = $(LOCATE.TARGETS) ; } return [ FDirName $(dir) $(1).$(2) ] ; } # WrapFile basename : file : pathcomponents : rule [ : objects : [ suffix ] ] # Generate a file within a wrapper. pathcomponents is a list of names # which compose the relative path within the wrapper where file should be # placed. pathcomponents may be the empty list if the file should reside # at the top-level of the wrapper. rule is rule/action which should be # invoked to generate file. rule is invoked with arguments # , , and . # objects is an optional list of files from which file should be built. It # may be omitted if file does not depend upon any other files. suffix is # the extension of the wrapper (not of file). If suffix is omitted, "app" # is assumed. # # Implementation note: If basename and file are the same, then we do not # grist file. (Obviously, we also do not want to set the file dependent # upon itself.) The reason we do not grist file in this case is that the # LinkWith, and LFlags rules associate the variables NEEDLIBS and # LINKLIBS with the ungristed name, therefore in order to get access to # these variables at AppExe action time, we must use the same (ungristed) # name. It is otherwise impossible to gain access to those variables. # This is an unfortunate hack which pollutes the otherwise general-purpose # WrapFile rule. rule WrapFile { local suffix ; if $(6) { suffix = $(6) ; } else { suffix = app ; } local target = $(2) ; if $(target) != $(1) { target = $(target:G=$(1)) ; Depends $(1) : $(target) ; } local dir = [ FDirName [ Wrapper $(1) : $(suffix) ] $(3) ] ; MakeLocate $(target) : $(dir) ; if $(5) { Depends $(target) : $(5) ; } BASENAME on $(target) = $(1) ; $(4) $(target) : $(5) : $(1) ; Clean clean : [ FDirName $(dir) $(target) ] ; Clean $(1)clean : [ FDirName $(dir) $(target) ] ; } # LinkApplication exe : objects actions AppExe bind NEEDLIBS bind EXTRAOBJECTS { $(MACOSX_ENVIRONMENT) $(CMD.LINK) -o $(<) $(>) $(EXTRAOBJECTS) $(NEEDLIBS) $(LINKLIBS) } # AppPkgInfo file actions AppPkgInfo { echo 'APPL????' > $(<) ; } # AppInfoPlistStrings file actions AppInfoPlistStrings { cat << EOT > $(<) CFBundleName = "$(BASENAME)"; CFBundleShortVersionString = "$(PACKAGE_VERSION)"; CFBundleGetInfoString = "$(BASENAME), $(PACKAGE_VERSION)"; EOT } # AppVersionPlist file actions AppVersionPlist { cat << EOT > $(<) CFBundleShortVersionString $(PACKAGE_VERSION) CFBundleVersion $(PACKAGE_VERSION) ProjectName $(BASENAME) EOT } # AppInfoPlist filename : placeholder : basename # Implementation Note: $(BASENAME)_APPICON might be empty in the actions of # this rule, if the client did not specify a default icon or a # target-specific icon, in which case we need to omit both the # CFBundleIconFile key and value. To accomplish this, the key and value # are placed on a single line with no intervening whitespace. When Jam # interpolates a variable, if the variable is empty, it removes all # adjacent text (the key and value, in this case) which is just what we # desire. actions AppInfoPlist { cat << EOT > $(<) CFBundleDevelopmentRegion English CFBundleName $(BASENAME) CFBundleExecutable $(BASENAME) CFBundleIconFile$($(BASENAME)_APPICON) CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleSignature ???? CFBundleVersion 0 CFBundleShortVersionString $(PACKAGE_VERSION) NSPrincipalClass NSApplication EOT } # AppIcon : # Copy an icon into the wrapper. It is assumed that some other agent has # already set SEARCH on the icon, if necessary. rule AppIcon { local icon = $(>:G=$(<)) ; Depends $(<) : $(icon) ; Depends $(icon) : $(>) ; MakeLocate $(icon) : [ FDirName [ Wrapper $(<) : app ] Contents Resources ] ; Copy $(icon) : $(>) ; Clean clean : $(icon) ; Clean $(<)clean : $(icon) ; } # InstallApplicationGUI app : installdirs # Install a GUI application. Unlike applications on other platforms which # exist as a single executable file, on MacOS/X, an application is wrapped # in a directory hierarchy, thus a deep copy is needed (i.e. the typical # Install rule does not work). rule InstallApplicationGUI { local wrapper = $(<).app ; Depends $(wrapper) : $(<) ; SEARCH on $(wrapper) = $(LOCATE.TARGETS) ; # Yuck! Internal knowledge of how DoInstall composes 'dir' and 'target'. local dir = [ ConcatDirs $(DESTDIR) $(2) ] ; local target = $(wrapper:BSR=$(dir):G=install) ; InstallApplicationWrapperPrepare $(target) ; Depends install_bin : [ DoInstall $(wrapper) : $(2) : "$(DEEPCOPY)" ] ; } actions InstallApplicationWrapperPrepare { $(DELTREE) $(<) ; }