rule Copy { if $(2) { SEARCH on $(2) += $(SEARCH_SOURCE) ; Depends $(1) : <build>copyattr $(2) ; Copy1 $(1) : <build>copyattr $(2) ; } } actions Copy1 { $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) "$(2[1])" -d "$(2[2-])" "$(1)" } rule SymLink { # SymLink <target> : <source> : <makeDefaultDependencies> ; # Links <target> to <source>. # <source> is the exact link contents. No binding is done. # <makeDefaultDependencies> If true, <target> will be made a dependency # of the `all' pseudo target, i.e. it will be made by default, and removed # on `jam clean'. local target = $(1) ; local source = $(2) ; local makeDefaultDependencies = $(3) ; if ! $(makeDefaultDependencies) { makeDefaultDependencies = true ; } LINKCONTENTS on $(target) = $(source) ; SymLink1 $(target) ; if $(makeDefaultDependencies) = true { LocalDepends files : $(target) ; LocalClean clean : $(target) ; } } actions SymLink1 { $(RM) "$(1)" && $(LN) -s "$(LINKCONTENTS)" "$(1)" } rule RelSymLink { # RelSymLink <link> : <link target> : <makeDefaultDependencies> ; # Creates a relative symbolic link from <link> to <link target>. # <link> and <link target> can be usual targets. They may have a grist # and don't need to have any dirname. Their LOCATE variables are used to # find their locations. # <makeDefaultDependencies> If true (which is the default), <link> will be # made a dependency of the `files' pseudo target, i.e. it will be made by # default, and removed on `jam clean'. local target = $(1) ; local source = $(2) ; local makeDefaultDependencies = $(3) ; local targetDir = [ on $(target) FDirName $(LOCATE[1]) $(target:D) ] ; local sourceDir = [ on $(source) FDirName $(LOCATE[1]) $(source:D) ] ; local sourcePath = $(source:G=) ; sourcePath = $(sourcePath:D=$(sourceDir)) ; local targetDirComponents = [ FSplitPath $(targetDir) ] ; local sourceComponents = [ FSplitPath $(sourcePath) ] ; SymLink $(target) : [ FRelPath $(targetDirComponents) : $(sourceComponents) ] : $(makeDefaultDependencies) ; NOUPDATE $(target) ; Depends $(target) : $(source) ; } rule AbsSymLink { # AbsSymLink <link> : <link target> : <link dir> # : <makeDefaultDependencies> ; # Creates an absolute symbolic link from <link> to <link target>. # <link> and <link target> must be usual targets. If <link dir> is # given, then it is set as LOCATE directory on <link>. # <makeDefaultDependencies> If true (which is the default), <link> will be # made a dependency of the `files' pseudo target, i.e. it will be made by # default, and removed on `jam clean'. local makeDefaultDependencies = $(4) ; if ! $(makeDefaultDependencies) { makeDefaultDependencies = true ; } Depends $(1) : $(2) ; if $(3) { MakeLocate $(1) : $(3) ; } SEARCH on $(2) += $(SEARCH_SOURCE) ; if $(makeDefaultDependencies) = true { LocalDepends files : $(1) ; LocalClean clean : $(1) ; } } actions AbsSymLink { target="$(2)" case "$target" in /*) ;; *) target=`pwd`/"$target";; esac $(RM) "$(1)" && $(LN) -s "$target" "$(1)" } rule HaikuInstall installAndUninstall : dir : sources : installgrist : installRule : targets { # Usage: HaikuInstall <[ install [ and uninstall ] pseudotarget ]> # : <directory> : <sources to install> : [ <installgrist> ] # : [ <install rule> ] : [ <targets> ] ; local install = $(installAndUninstall[1]) ; install ?= install ; local uninstall = $(installAndUninstall[2]) ; uninstall ?= un$(install) ; installgrist ?= $(INSTALLGRIST) ; installRule ?= Install ; targets ?= $(sources) ; targets = $(targets:G=$(installgrist)) ; NotFile $(install) ; NotFile $(uninstall) ; Depends $(install) : $(targets) ; Clean $(uninstall) : $(targets) ; SEARCH on $(sources) += $(SEARCH_SOURCE) ; MakeLocate $(targets) : $(dir) ; local source ; for source in $(sources) { local target = $(targets[1]) ; targets = $(targets[2-]) ; Depends $(target) : $(source) ; $(installRule) $(target) : $(source) ; if [ on $(target) return $(MODE) ] { Chmod $(target) ; } if $(OWNER) && $(CHOWN) { Chown $(target) ; OWNER on $(target) = $(OWNER) ; } if $(GROUP) && $(CHGRP) { Chgrp $(target) ; GROUP on $(target) = $(GROUP) ; } } } rule InstallAbsSymLinkAdapter { # InstallAbsSymLinkAdapter <link> : <link target> if ! [ on $(2) return $(TARGET) ] { TARGET on $(2) = [ on $(2) return $(SEARCH) ] ; } AbsSymLink $(1) : $(2) : : false ; } rule HaikuInstallAbsSymLink { # Usage: HaikuInstallAbsSymLink <[ install [ and uninstall ] pseudotarget ]> # : <directory> : <sources to install> # : [ <installgrist> ] ; HaikuInstall $(1) : $(2) : $(3) : $(4) : InstallAbsSymLinkAdapter ; } rule InstallRelSymLinkAdapter { # InstallRelSymLinkAdapter <link> : <link target> if ! [ on $(2) return $(TARGET) ] { TARGET on $(2) = [ on $(2) return $(SEARCH) ] ; } RelSymLink $(1) : $(2) : false ; } rule HaikuInstallRelSymLink { # Usage: HaikuInstallRelSymLink <[ install [ and uninstall ] pseudotarget ]> # : <directory> : <sources to install> # : [ <installgrist> ] ; HaikuInstall $(1) : $(2) : $(3) : $(4) : InstallRelSymLinkAdapter ; } rule UnarchiveObjects { # UnarchiveObjects <target objects> : <static object> MakeLocateArch $(1) ; Depends $(1) : $(2) ; SEARCH on $(2) = $(SEARCH_SOURCE) ; } actions UnarchiveObjects { ( cd $(1[1]:D) && $(TARGET_AR_$(TARGET_PACKAGING_ARCH)) \ $(TARGET_UNARFLAGS_$(TARGET_PACKAGING_ARCH)) "$(2)" $(1:BS) ) } rule ExtractArchive directory : entries : archiveFile : grist { # ExtractArchive <directory> : <entries> : <archiveFile> [ : <grist> ] # # Extract the archive file target <archiveFile> to directory <directory>. # The rule can be called multiple times for different <entries> for the same # <directory> and <archiveFile> combo. # # <directory> - The directory into which to extract the archive file. The # directory is created by this rule and it is the target # that the extract action is associated with. # <entries> - The entries of the archive file one is interested in. The # rule always extracts the complete archive file, from the # given entries the rule creates targets (using <grist>) # representing the extracted entries. Those targets are # returned by the rule. # <archiveFile> - The archive file target to extract. # <grist> - The grist used to create targets from <entries>. Defaults to # "extracted". grist ?= extracted ; # Turn the entries into targets to build. local targets ; local entry ; for entry in $(entries) { local target = $(entry:G=$(grist)) ; targets += $(target) ; } LOCATE on $(targets) = $(directory:G=) ; Depends $(targets) : $(directory) $(archiveFile) ; NoUpdate $(targets) ; # one-time initialization for the main target (the directory) if ! [ on $(directory) return $(INITIALIZED) ] { # make sure the parent dir exists local parentDir = $(directory:PG=dir) ; Depends $(directory) : $(parentDir) ; MkDir $(parentDir) ; NoUpdate $(directory) ; Depends $(directory) : $(archiveFile) ; switch $(archiveFile:S) { case .zip : ExtractZipArchive1 $(directory) : $(archiveFile) ; case .tgz : ExtractTarArchive1 $(directory) : $(archiveFile) ; case .hpkg : Depends $(directory) : <build>package ; ExtractHPKGArchive1 $(directory) : <build>package $(archiveFile) ; case "" : Exit "ExtractArchive: No archive passed" ; case * : Exit "ExtractArchive: Unhandled archive extension:" "$(archiveFile:S)" ; } INITIALIZED on $(directory) = 1 ; } return $(targets) ; } actions ExtractZipArchive1 { mkdir -p $(1) unzip -q -u -o -d $(1) $(2) } actions ExtractTarArchive1 { mkdir -p $(1) tar -C $(1) -xf $(2) } actions ExtractHPKGArchive1 { mkdir -p "$(1)" $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) $(2[1]) extract -C "$(1)" "$(2[2])" } rule ObjectReference { # ObjectReference <reference object> : <source object> # Makes <reference object> refer to the same file as <source object>. # The filenames must of course be identical. # <source object> must have already been LOCATEd. local ref = $(1) ; local source = $(2) ; if $(ref) != $(source) { Depends $(ref) : $(source) ; LOCATE on $(ref) = [ on $(source) return $(LOCATE) ] ; } } rule ObjectReferences { # ObjectReferences <source objects> # Creates local references to <source objects>, i.e. identifiers with the # current grist referring to the same files. <source objects> must have # already been LOCATEd. local source ; for source in $(1) { ObjectReference [ FGristFiles $(source) ] : $(source) ; } } rule CopySetHaikuRevision target : source { # CopySetHaikuRevision <target> : <source> # # Copy <source> to <target>, writing the Git revision of the working # directory into the haiku revision section of <target>. # # <target> - Output file target. Gristed and located target. # <source> - ELF object to be copied. Gristed and located target. PropagateContainerUpdateTargetFlags $(target) : $(source) ; HAIKU_TARGET_IS_EXECUTABLE on $(target) = [ on $(source) return $(HAIKU_TARGET_IS_EXECUTABLE) ] ; local revisionFile = [ DetermineHaikuRevision ] ; Depends $(target) : <build>copyattr <build>set_haiku_revision $(source) $(revisionFile) ; CopySetHaikuRevision1 $(target) : <build>copyattr <build>set_haiku_revision $(source) $(revisionFile) ; } actions CopySetHaikuRevision1 { $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) $(2[1]) --data $(2[3]) $(1) || exit 1 revision=0 if [ -n "$(2[4]:E=)" ]; then revision="`cat $(2[4]:E=)`" fi $(2[2]) $(1) "$revision" } rule DetermineHaikuRevision { # If existing, make the target depend on the .git/index file in the # root directory, so it gets updated when the revision changes due to # commits or merges. local gitIndex = <haiku-rootdir-git>index ; local revisionFile = <haiku-rootdir>haiku-revision ; if ! [ on $(gitIndex) return $(HAIKU_GIT_REVISION_DETERMINED) ] { HAIKU_GIT_REVISION_DETERMINED on $(gitIndex) = 1 ; MakeLocate $(revisionFile) : $(HAIKU_BUILD_OUTPUT_DIR) ; LocalClean clean : $(revisionFile) ; if $(HAIKU_REVISION) { DetermineHaikuRevision2 $(revisionFile) ; } else if [ Glob [ FDirName $(HAIKU_TOP) .git ] : index ] { SEARCH on $(gitIndex) = [ FDirName $(HAIKU_TOP) .git ] ; Depends $(revisionFile) : $(gitIndex) ; DetermineHaikuRevision1 $(revisionFile) : $(gitIndex) ; } else { revisionFile = ; } } return $(revisionFile) ; } actions DetermineHaikuRevision1 { $(HAIKU_TOP)/build/scripts/determine_haiku_revision $(HAIKU_TOP) $(1) } actions DetermineHaikuRevision2 { echo $(HAIKU_REVISION) > $(1) } rule DetermineEffectiveHaikuRevision { local revisionFile = <haiku-rootdir>effective-haiku-revision ; if ! [ on $(revisionFile) return $(HAIKU_EFFECTIVE_REVISION_DETERMINED) ] { HAIKU_EFFECTIVE_REVISION_DETERMINED on $(revisionFile) = 1 ; MakeLocate $(revisionFile) : $(HAIKU_BUILD_OUTPUT_DIR) ; local rawRevision = [ DetermineHaikuRevision ] ; Depends $(revisionFile) : $(rawRevision) ; DetermineEffectiveHaikuRevision1 $(revisionFile) : $(rawRevision) ; LocalClean clean : $(revisionFile) ; } return $(revisionFile) ; } actions DetermineEffectiveHaikuRevision1 { revision=`sed -n 's,^\(hrev[0-9]*\).*,\1,p' "$(2:E=unknown-revision)"` if [ -z "$revision" ]; then echo "Error: unable to determine the effective Haiku revision." echo " If you are using a Haiku clone without tags, you can set" echo " the revision tag to use with e.g. HAIKU_REVISION=hrev43210" exit 1 fi echo "${revision:-0}" > "$(1)" } rule DataFileToSourceFile sourceFile : dataFile : dataVariable : sizeVariable { sourceFile = [ FGristFiles $(sourceFile) ] ; MakeLocateCommonPlatform $(sourceFile) ; sizeVariable ?= $(dataVariable)Size ; DATA_VARIABLE on $(sourceFile) = $(dataVariable) ; SIZE_VARIABLE on $(sourceFile) = $(sizeVariable) ; Depends $(sourceFile) : <build>data_to_source $(dataFile) ; DataFileToSourceFile1 $(sourceFile) : <build>data_to_source $(dataFile) ; LocalClean clean : $(sourceFile) ; } actions DataFileToSourceFile1 { $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) $(2[1]) $(DATA_VARIABLE) $(SIZE_VARIABLE) $(2[2]) $(1) } rule DownloadLocatedFile target : url : source { # DownloadLocatedFile <target> : <url> [ : <source> ] ; # # <source> is an optional target that <target> will be made dependent on. # Its resolved path can be used in <url> via '$source'. URL on $(target) = $(url) ; if $(source) { Depends $(target) : $(source) ; } DownloadLocatedFile1 $(target) : $(source) ; } actions DownloadLocatedFile1 { source="$(2)" if [ "$(HAIKU_NO_DOWNLOADS)" = 1 ]; then echo "ERROR: Would need to download $(URL), but HAIKU_NO_DOWNLOADS is set!" exit 1 fi wget --retry-connrefused --timeout 10 -O "$(1)" $(URL) || exit 1 touch "$(1)" } rule DownloadFile file : url : source { # DownloadFile <file> : <url> [ : <source> ] ; # # <source> is an optional target that the target will be made dependent on. # Its resolved path can be used in <url> via '$source'. file = $(file:G=download) ; # Request the download only once. if [ on $(file) return $(HAIKU_FILE_DOWNLOAD) ] { return $(file) ; } HAIKU_FILE_DOWNLOAD on $(file) = 1 ; MakeLocate $(file) : $(HAIKU_DOWNLOAD_DIR) ; DownloadLocatedFile $(file) : $(url) : $(source) ; return $(file) ; } actions ChecksumFileSHA256 { $(HOST_SHA256) $(2) \ | $(HOST_EXTENDED_REGEX_SED) 's,([^[:space:]]*).*,\1,' > $(1) # The sed part is only necessary for sha256sum, but it doesn't harm for # sha256 either. } rule Sed target : source : substitutions : targetMap { # Sed <target> : [ <source> ] : <substitutions> [ : <targetMap> ] ; # # Performs substitutions in a text file. If <source> is given, that is the # input, otherwise the substitutions are performed in place on <target>. The # caller is responsible for locating <target>, <source>, and any other used # target. # # <target> - The target file. # <source> - The source file. If not given, the substitutions are performed # in place on <target>. If given, a dependency of <target> to <source> # will be established. # <substitutions> - List of substitutions to be performed. Each element # specifies a substitution. It's a partial sed "s" command of the form # "<pattern>,<replacement>". # <targetMap> - A list of elements of the form "<variable>=<mappedTarget>". # <variable> specifies a name of a shell variable, <mappedTarget> a jam # target whose bound name will be assigned to the shell variable. The # variable can be used in <substitutions>. A dependency of <target> to # <mappedTarget> will be established. # We need a temporary (shell) file to which we write the target variable # mappings and the sed invocations. This is necessary, since multiple rule # invocations are allowed for a target, so that we cannot use on-target # variables. local script = [ NextID ] ; script = temp-sed-script-$(target:BS)-$(script) ; # process the target variable mappings local mappedTargets ; local targetMapElement ; for targetMapElement in $(targetMap) { local split = [ Match ([^=]+)=(.*) : $(targetMapElement) ] ; HAIKU_SED_SCRIPT_VARIABLE on $(script) += $(split[1]) ; local mappedTarget = $(split[2]) ; mappedTargets += $(mappedTarget) ; } HAIKU_SED_SCRIPT_SUBSTITUTIONS on $(script) = "-e \"s,$(substitutions),g\"" ; HAIKU_SED_SCRIPT_SOURCE on $(script) = $(source) ; if $(source) { HAIKU_SED_SCRIPT_SOURCE_ARGUMENTS on $(script) = ">" ; } else { HAIKU_SED_SCRIPT_SOURCE_ARGUMENTS on $(script) = -i ; } # build the script MakeLocate $(script) : $(HAIKU_TMP_DIR) ; Depends $(script) : $(mappedTargets) $(source) ; SedCreateScript $(script) : $(mappedTargets) ; # build the target Depends $(target) : $(script) ; Sed1 $(target) : $(script) ; RmTemps $(target) : $(script) ; } actions SedCreateScript bind HAIKU_SED_SCRIPT_SOURCE { set -o errexit $(RM) "$(1)" touch "$(1)" set -- $(2) for variable in "$(HAIKU_SED_SCRIPT_VARIABLE)" ; do echo "$variable=\"$1\"" >> "$(1)" shift done echo sed '$(HAIKU_SED_SCRIPT_SUBSTITUTIONS)' \ '"$(HAIKU_SED_SCRIPT_SOURCE)"' "$(HAIKU_SED_SCRIPT_SOURCE_ARGUMENTS)" \ '"$target"' >> "$(1)" } actions Sed1 { set -o errexit target="$(1)" . "$(2)" } rule StripFile target : source { # Note: The caller is reponsible for matching TARGET_PACKAGING_ARCH with # the architecture the target was built for. STRIP on $(target) = $(HAIKU_STRIP_$(TARGET_PACKAGING_ARCH)) ; PropagateContainerUpdateTargetFlags $(target) : $(source) ; LocalClean clean : $(target) ; Depends $(target) : $(source) <build>xres <build>copyattr ; StripFile1 $(target) : $(source) <build>xres <build>copyattr ; } actions StripFile1 { $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) "$(STRIP)" -o "$(1)" "$(2[1])" "$(2[2])" -o "$(1)" "$(2[1])" "$(2[3])" "$(2[1])" "$(1)" } rule StripFiles files { # Note: The caller is reponsible for matching TARGET_PACKAGING_ARCH with # the architecture the targets were built for. local strippedFiles ; local file ; for file in $(files) { local strippedFile = $(file:G=stripped_$(file:G)) ; # Place the stripped file in a "stripped" subdirectory of the file's # location. local location = [ on $(file) return $(LOCATE) ] ; if ! $(location) { location = $(TARGET_COMMON_DEBUG_OBJECT_DIR_$(TARGET_PACKAGING_ARCH)) ; } MakeLocateArch $(strippedFile) : [ FDirName $(location) stripped ] ; StripFile $(strippedFile) : $(file) ; strippedFiles += $(strippedFile) ; } return $(strippedFiles) ; }