mirror of
https://github.com/bulletphysics/bullet3
synced 2024-12-15 22:20:12 +00:00
ec56a978f7
Misc property fixes.
595 lines
17 KiB
Plaintext
595 lines
17 KiB
Plaintext
#============================================================================
|
|
# Helper rules
|
|
# Copyright (C)2003 by Matze Braun <matzebraun@users.sourceforge.net>
|
|
# Copyright (C)2004 by Eric Sunshine <sunshine@sunshineco.com>
|
|
#
|
|
# 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.
|
|
#
|
|
#============================================================================
|
|
|
|
SED ?= sed ;
|
|
DEEPCOPY ?= "cp -R" ;
|
|
DELTREE ?= "rm -rf" ;
|
|
|
|
# The -f option to `cp' is not supported on older platforms.
|
|
# The convolution of the conditional arises because CP is defined in Jambase as
|
|
# two tokens rather than a single string, so we must check the tokens
|
|
# individually; yet we also check it as a simple string for future robustness.
|
|
if $(CP) = "cp -f" || $(CP[1]) = "cp" && $(CP[2]) = "-f"
|
|
{
|
|
CP = cp ;
|
|
}
|
|
|
|
## IncludeDir [ dir [ : target [ : options ]]]
|
|
## Specify the location of a directory containing header files for a target,
|
|
## or for the whole project if no target is given. "dir" is a list of
|
|
## components composing the path. This rule will automatically generate the
|
|
## -I compiler flags and makes sure the dependency scanner is able to locate
|
|
## your header files. "dir" is assumed to be relative to the current
|
|
## subdirectory specified with the SubDir rule unless the "literal"
|
|
## option is given, in which case "dir" is used literally. If "dir" is
|
|
## omitted, then the current subdirectory specified with SubDir is used as
|
|
## the header directory. An omitted "dir" and the "literal" option are
|
|
## mutually exclusive. You may invoke this rule multiple times to specify
|
|
## any number of header file directories.
|
|
## Options:
|
|
## literal: "dir" is to be used literally without any interpretation.
|
|
## transient: "dir" is to be used at build-time only; and should not be
|
|
## recorded in any generated resources, such as project files.
|
|
##
|
|
## Implementation: The directory is simply added to the HDRS variable which
|
|
## is respected by all Jam rules.
|
|
rule IncludeDir
|
|
{
|
|
local dir = $(1) ;
|
|
local target = $(2) ;
|
|
local options = $(3) ;
|
|
|
|
CheckOptions literal transient : $(options) : $(dir) ;
|
|
if ! $(dir)
|
|
{
|
|
dir = $(SUBDIR) ;
|
|
}
|
|
else if ! [ IsElem literal : $(options) ]
|
|
{
|
|
dir = $(SUBDIR) $(dir) ;
|
|
}
|
|
dir = [ ConcatDirs $(dir) ] ;
|
|
|
|
if $(target)
|
|
{
|
|
local o ;
|
|
for o in $($(target)_OBJECTS)
|
|
{
|
|
CCHDRS on $(o) += [ FIncludes $(dir) ] ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HDRS += $(dir) ;
|
|
}
|
|
}
|
|
|
|
## Wildcard [ dir : ] patterns
|
|
## Create a list of files in a directory which match the pattern. You can
|
|
## optionally specify a subdirectory. The files will be returned with
|
|
## stripped pathnames. The difference from GLOB is that this rule respects
|
|
## subdirectories which may have been entered with the SubDir rule.
|
|
rule Wildcard
|
|
{
|
|
local files dir sdir wildcards ;
|
|
|
|
# Is a directory given?
|
|
if $(>)
|
|
{
|
|
dir = $(<)/ ;
|
|
sdir = [ ConcatDirs $(<) ] ;
|
|
wildcards = $(>) ;
|
|
}
|
|
else
|
|
{
|
|
dir = "" ;
|
|
sdir = "" ;
|
|
wildcards = $(<) ;
|
|
}
|
|
|
|
files = [ GLOB [ ConcatDirs $(SUBDIR) $(dir) ] : $(wildcards) ] ;
|
|
|
|
return $(files:BSR=$(sdir)) ;
|
|
}
|
|
|
|
## Recurse [ rule ] : types [ : prefix ]
|
|
## Recursively scan current directory, $(SUBDIR), for files matching 'types'
|
|
## and invoke 'rule' for each file which matches one of the 'types'.
|
|
## 'types' is a list of file extensions (with the leading dot). 'rule' will
|
|
## be invoked with two arguments: (1) the basename of the file including the
|
|
## extension, (2) a list of the path components from the current directory
|
|
## to the file's directory. When 'rule' is invoked, it will see a $(SUBDIR)
|
|
## value of the directory containing the file (as if the rule had been
|
|
## invoked from within the file's directory). 'prefix' is an optional list
|
|
## of path components which will be prepended to rule's second argument.
|
|
## Returns the list of visited files. It is legal to omit 'rule', if you
|
|
## are interested only in obtaining the list of files matching 'types'.
|
|
rule Recurse
|
|
{
|
|
local innerrule = $(1) ;
|
|
local types = $(2) ;
|
|
local prefix = $(3) ;
|
|
local files = [ GLOB $(SUBDIR) : * ] ;
|
|
local visited ;
|
|
|
|
local i ;
|
|
for i in $(files)
|
|
{
|
|
if [ IsElem $(i:S) : $(types) ]
|
|
{
|
|
visited += [ FDirName $(prefix) $(i:BS) ] ;
|
|
if $(innerrule)
|
|
{
|
|
$(innerrule) $(i:BS) : $(prefix) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ! [ IsElem $(i:BS) : $(DOT) $(DOTDOT) ]
|
|
{
|
|
local SUBDIR = $(i) ; # Called rules see this new temporary value.
|
|
visited += [ Recurse $(innerrule) : $(types) : $(prefix) $(i:BS) ] ;
|
|
}
|
|
}
|
|
}
|
|
return $(visited) ;
|
|
}
|
|
|
|
## ResponseFile file : [ items [ : options [ : directory [ : delim ]]]]
|
|
## Jam places a fairly restrictive limit on the length of the command string
|
|
## emitted by an 'actions' block. If the limit is exceeded, Jam rudely
|
|
## aborts. This problem is easily triggered when actions are invoked
|
|
## 'together' but not 'piecemeal'; especially when the command arguments
|
|
## involve many lengthy pathnames. To work around this type of problem,
|
|
## some tools allow the client to furnish a file containing information
|
|
## which would otherwise be specified via the command-line. This is often
|
|
## called a "response file". The ResponseFile rule can be used to create a
|
|
## response file named 'file' in 'directory' containing 'items', one per
|
|
## line. As a convenience, if 'directory' is not specified, and if the
|
|
## MakeLocate rule has not already been invoked for 'file' or LOCATE has not
|
|
## been set for 'file', then the file is placed in $(LOCATE_TARGET). If
|
|
## there is a possibility that the same 'file' name might be used in other
|
|
## contexts, be sure to grist it appropriately to avoid conflicts. This
|
|
## rule assumes that 'items' contains bound entries unless the "notfile"
|
|
## option is specified, in which case the NotFile rule is automatically
|
|
## invoked for each item. This rule may be invoked multiple times for the
|
|
## same 'file' in order to populate the file incrementally. As an internal
|
|
## optimization to keep performance relatively sane, ResponseFile
|
|
## temporarily inserts 'delim' between 'items' when emitting them, and then
|
|
## substitutes newline for 'delim' just before writing the items to
|
|
## 'file'. 'delim' must be a one-character string. If not specified, "@" is
|
|
## used. If "@" is likely to appear in 'items', then choose a different
|
|
## character for 'delim'; one which is known to not appear in 'items'. The
|
|
## rule returns 'file' to make it convenient to daisy-chain with invocations
|
|
## of other rules, such as RmTemps, Depends, or Always.
|
|
## Options:
|
|
## notfile: Invoke NotFile for each item automatically; otherwise, assume
|
|
## that each item is a bound file.
|
|
rule ResponseFile
|
|
{
|
|
local file = $(1) ;
|
|
local items = $(2) ;
|
|
local options = $(3) ;
|
|
local dir = $(4) ;
|
|
local delim = $(5) ;
|
|
|
|
CheckOptions notfile : $(options) : $(file) ;
|
|
|
|
if ! $(delim) { delim = "@" ; }
|
|
DELIM on $(file) = $(delim) ;
|
|
|
|
local firsttime = no ;
|
|
if ! [ IsElem $(file) : $(RESPONSE_FILE_REGISTRY) ]
|
|
{
|
|
firsttime = yes ;
|
|
RESPONSE_FILE_REGISTRY += $(file) ;
|
|
}
|
|
|
|
if ! $(items) && $(firsttime) = yes
|
|
{
|
|
items = "" ; # Force file creation even if list is empty.
|
|
options += notfile ;
|
|
}
|
|
|
|
if [ IsElem notfile : $(options) ] && $(items)
|
|
{
|
|
NotFile $(items) ;
|
|
}
|
|
|
|
if $(dir)
|
|
{
|
|
MakeLocate $(file) : $(dir) ;
|
|
}
|
|
else
|
|
{
|
|
local target_dir = [ on $(file) GetVar LOCATE ] ;
|
|
if ! $(target_dir)
|
|
{
|
|
MakeLocate $(file) : $(LOCATE_TARGET) ;
|
|
}
|
|
}
|
|
|
|
local i ;
|
|
for i in $(items)
|
|
{
|
|
if $(firsttime) = yes
|
|
{
|
|
ResponseFile1 $(file) : $(i) ;
|
|
firsttime = no ;
|
|
}
|
|
else
|
|
{
|
|
ResponseFile2 $(file) : $(i) ;
|
|
}
|
|
}
|
|
|
|
return $(file) ;
|
|
}
|
|
|
|
actions ResponseFile1
|
|
{
|
|
echo '$(>)' > $(<)
|
|
}
|
|
|
|
actions piecemeal together quietly ResponseFile2
|
|
{
|
|
echo '$(>)$(DELIM)' | $(SED) 's/$(DELIM) /$(DELIM)/g' | tr '$(DELIM)' '
|
|
' >> $(<)
|
|
}
|
|
|
|
## Sort list
|
|
## Given a list of items, returns a list containing the items sorted
|
|
## alphabetically.
|
|
rule Sort
|
|
{
|
|
local i sorted ;
|
|
for i in $(<)
|
|
{
|
|
local inserted = no ;
|
|
local j accum ;
|
|
for j in $(sorted)
|
|
{
|
|
if $(inserted) != yes && $(i:L) < $(j:L)
|
|
{
|
|
accum += $(i) ;
|
|
inserted = yes ;
|
|
}
|
|
accum += $(j) ;
|
|
}
|
|
if $(inserted) != yes
|
|
{
|
|
accum += $(i) ;
|
|
}
|
|
sorted = $(accum) ;
|
|
}
|
|
return $(sorted) ;
|
|
}
|
|
|
|
## StripCommon list1 : list2
|
|
## Strips from the beginning of list1 the items which it has in common with
|
|
## the beginning of list2 and returns what remains of list1.
|
|
rule StripCommon
|
|
{
|
|
local l = $(<) ;
|
|
local r = $(>) ;
|
|
FStripCommon l : r ;
|
|
return $(l) ;
|
|
}
|
|
|
|
## MasterHeader header [ : files [ : pre-boilerplate [ : post-boilerplate
|
|
## [ : options ]]]]
|
|
## Given a list of 'files', construct a 'header' file which #includes those
|
|
## files. If 'header' does not already have a suffix, ".h" will be
|
|
## appended. The generated header will be emitted to $(LOCATE_TARGET), and
|
|
## will be protected against multiple-inclusion via the standard
|
|
## #ifndef __HEADER_H__ / #define / #endif mechanism. If provided,
|
|
## 'pre-boilerplate' will be inserted verbatim immediately after the opening
|
|
## multiple-inclusion protection, but before the first #include. Likewise,
|
|
## 'post-boilerplate' will be inserted verbatim after the last #include, but
|
|
## before the closing multiple-inclusion protection. If the boilerplate
|
|
## arguments are lists, the items will be emitted one per line. 'files'
|
|
## is sorted before the #include statements are generated, unless the
|
|
## "nosort" option is given. For convenience, the gristed 'header' is
|
|
## returned. Also sets up the following pseudo-targets:
|
|
##
|
|
## masterheaders: Synthesize all requested master headers.
|
|
## cleanmasterheaders: Delete synthesized files.
|
|
## freezemasterheaders: Copy synthesized files to back into the source
|
|
## tree at $(SUBDIR).
|
|
##
|
|
## Options:
|
|
## nosort: Do not sort 'files'.
|
|
rule MasterHeader
|
|
{
|
|
local header = [ FAppendSuffix $(1) : .h ] ;
|
|
local files = $(2) ;
|
|
local boilerpre = $(3) ;
|
|
local boilerpost = $(4) ;
|
|
local options = $(5) ;
|
|
local target = $(header:G=masterheader) ;
|
|
local protect = "__$(header:US=)_H__" ;
|
|
|
|
CheckOptions nosort : $(options) : $(header) ;
|
|
if ! [ IsElem nosort : $(options) ]
|
|
{
|
|
files = [ Sort $(files) ] ;
|
|
}
|
|
|
|
Always $(target) ;
|
|
ResponseFile $(target) :
|
|
"/* $(header) -- Generated automatically; do not edit. */"
|
|
"#ifndef $(protect)"
|
|
"#define $(protect)"
|
|
$(boilerpre)
|
|
"#include \"$(files)\""
|
|
$(boilerpost)
|
|
"#endif /* $(protect) */"
|
|
: notfile ;
|
|
Depends masterheaders : $(target) ;
|
|
Clean cleanmasterheaders : $(target) ;
|
|
Clean clean : cleanmasterheaders ;
|
|
|
|
local frozen = $(target:G=frozenmasterheader) ;
|
|
MakeLocate $(frozen) : $(SUBDIR) ;
|
|
Depends $(frozen) : $(target) ;
|
|
Copy $(frozen) : $(target) ;
|
|
Depends freezemasterheaders : $(frozen) ;
|
|
|
|
if $(MASTER_HEADER_GLOBAL_TARGETS) != yes
|
|
{
|
|
MASTER_HEADER_GLOBAL_TARGETS = yes ;
|
|
|
|
Always masterheaders ;
|
|
NotFile masterheaders ;
|
|
Help masterheaders : "Generate master header files" ;
|
|
|
|
Always freezemasterheaders ;
|
|
NotFile freezemasterheaders ;
|
|
Help freezemasterheaders :
|
|
"Copy generated master headers to source tree" ;
|
|
}
|
|
|
|
return $(target) ;
|
|
}
|
|
|
|
## DirectoryMasterHeaders dirs [ : pre-boilerplate [ : post-boilerplate
|
|
## [ : options [ : rejects ]]]]
|
|
## A convenience wrapper around MasterHeader which generates a set of master
|
|
## header files for each directory in 'dirs', which are assumed to be
|
|
## subdirectories of the current directory. For each item in 'dirs', the
|
|
## subdirectory is recursively scanned for files, and MasterHeader is
|
|
## invoked with the gleaned file list. The generated header for a directory
|
|
## is emitted to the current directory; not within the subdirectory. The
|
|
## optional 'rejects' is a list of header files which should not be emitted
|
|
## to the synthesized master headers. 'pre-boilerplate',
|
|
## 'post-boilerplate', and 'options' carry the same interpretation as for
|
|
## MasterHeader.
|
|
rule DirectoryMasterHeaders
|
|
{
|
|
local dirs = $(1) ;
|
|
local boilerpre = $(2) ;
|
|
local boilerpost = $(3) ;
|
|
local options = $(4) ;
|
|
local rejects = $(5) ;
|
|
local masters ;
|
|
local d ;
|
|
for d in $(dirs)
|
|
{
|
|
local files ;
|
|
{
|
|
local SUBDIR = [ ConcatDirs $(SUBDIR) $(d) ] ; # Recurse from here...
|
|
files = [ Recurse : .h : $(d) ] ;
|
|
}
|
|
if $(rejects)
|
|
{
|
|
files = [ Filter $(files) : $(rejects) ] ;
|
|
}
|
|
masters += [ MasterHeader $(d) : $(files) : $(boilerpre) : $(boilerpost) :
|
|
$(options) ] ;
|
|
}
|
|
return $(masters) ;
|
|
}
|
|
|
|
## Prefix list : prefix
|
|
## Adds a prefix to a all elements in list.
|
|
rule Prefix
|
|
{
|
|
return $(>)$(<) ;
|
|
}
|
|
|
|
if $(JAMVERSION) >= 2.5
|
|
{
|
|
|
|
## IsElem element : list
|
|
## Returns "true" if the element is in the list. Otherwise nothing is
|
|
## returned.
|
|
rule IsElem
|
|
{
|
|
local i ;
|
|
|
|
for i in $(>)
|
|
{
|
|
if $(i) = $(<)
|
|
{
|
|
return "true" ;
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
# Jam <2.4's return statement doesn't exit the function
|
|
rule IsElem
|
|
{
|
|
local i result ;
|
|
|
|
for i in $(>)
|
|
{
|
|
if $(i) = $(<)
|
|
{
|
|
result = "true" ;
|
|
$(>) = ;
|
|
}
|
|
}
|
|
|
|
return $(result) ;
|
|
}
|
|
|
|
}
|
|
|
|
## Filter list : filter
|
|
## Returns the list without the words contained in filter.
|
|
rule Filter
|
|
{
|
|
local i result ;
|
|
|
|
for i in $(<)
|
|
{
|
|
if ! [ IsElem $(i) : $(>) ]
|
|
{
|
|
result += $(i) ;
|
|
}
|
|
}
|
|
|
|
return $(result) ;
|
|
}
|
|
|
|
## RemoveDups list
|
|
## Removes duplicates in the list (this function tries to preserve the list
|
|
## order)
|
|
rule RemoveDups
|
|
{
|
|
local i result ;
|
|
|
|
for i in $(<)
|
|
{
|
|
if ! [ IsElem $(i) : $(result) ]
|
|
{
|
|
result += $(i) ;
|
|
}
|
|
}
|
|
|
|
return $(result) ;
|
|
}
|
|
|
|
## Reverse list
|
|
## Reverse the order of items in the list.
|
|
rule Reverse
|
|
{
|
|
local result ;
|
|
|
|
for i in $(<)
|
|
{
|
|
result = $(i) $(result) ;
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
## GetVar argument
|
|
## Simply returns the value of the variable with name argument.
|
|
## This is useful to query on target variables:
|
|
## bla = [ on TARGET GetVar CFlags ] ;
|
|
rule GetVar
|
|
{
|
|
return $($(<)) ;
|
|
}
|
|
|
|
## ConcatDirs dirs
|
|
## Concatenates a set of directories. This is a substitute for FDirName in
|
|
## Jambase. It works also correctly for several rooted paths, where FDirName
|
|
## fails.
|
|
## The advantage over $(dir1)/$(dir2) is that this also works correctly if
|
|
## $(dir1) or $(dir2) is not set.
|
|
rule ConcatDirs
|
|
{
|
|
local i ;
|
|
local result = $(<[1]) ;
|
|
if ! $(result) { $result = "" ; }
|
|
local dir1 dir2 ;
|
|
|
|
for i in $(<[2-])
|
|
{
|
|
# eleminate multiple slashes because jam is somewhat buggy here
|
|
dir1 = [ MATCH (.*[^/]?) : $(result) ] ;
|
|
dir2 = [ MATCH ([^/].*) : $(i) ] ;
|
|
if ! $(dir1) { dir1 = "" ; }
|
|
if $(dir1) != "" { dir1 = $(dir1)/ ; }
|
|
if ! $(dir2) { dir2 = "" ; }
|
|
result = $(dir1)$(dir2) ;
|
|
}
|
|
|
|
return $(result) ;
|
|
}
|
|
|
|
## SplitToList var [ : separator ]
|
|
## Splits the value of var into a list using space as the separator unless
|
|
## an alterante separator is specified.
|
|
## IMPLEMENTATION NOTE
|
|
## When Jam sees an invocation of the `Match' function, it treats its first
|
|
## argument as a literal regular expression, and does not do any variable
|
|
## interpolation. This means that an expression, such as "(.*)$(sep)(.*)"
|
|
## will not be interpreted as expected; it will instead be interpreted as an
|
|
## invalid regex. To work around this limitation, we invoke `Match'
|
|
## indirectly.
|
|
rule SplitToList
|
|
{
|
|
local list = ;
|
|
local matcher = Match ; # See IMPLEMENTATION NOTE above.
|
|
local unsplit = $(<) ;
|
|
local sep = $(2) ;
|
|
if ! $(sep) { sep = " " ; }
|
|
while $(unsplit) != ""
|
|
{
|
|
local split = [ $(matcher) "(.*)$(sep)(.*)" : $(unsplit) ] ;
|
|
if $(split[1]) = ""
|
|
{
|
|
list += $(unsplit) ;
|
|
unsplit = "" ;
|
|
}
|
|
else
|
|
{
|
|
list += $(split[2]) ;
|
|
unsplit = $(split[1]) ;
|
|
}
|
|
}
|
|
|
|
return [ Reverse $(list) ] ;
|
|
}
|
|
|
|
## Copy target : source
|
|
## Copy source to target.
|
|
actions Copy
|
|
{
|
|
$(RM) $(<)
|
|
$(CP) $(>) $(<)
|
|
}
|
|
|
|
## Move target : source
|
|
## Move (or rename) source to target.
|
|
actions ignore Move
|
|
{
|
|
$(MV) $(>) $(<)
|
|
}
|