haiku/build/jam/FileRules
Ingo Weinhold af559cd6ee Add DetermineEffectiveHaikuRevision rule
Simplifies PreprocessPackageInfo a bit.
2014-01-19 00:49:10 +01:00

640 lines
17 KiB
Plaintext

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-git>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)"`
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)"
wget -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) ;
}