1 rule FQualifiedBuildFeatureName features
3 # FQualifiedBuildFeatureName <features>
5 # Prepends the name of the current target packaging architecture to the
8 return $(TARGET_PACKAGING_ARCH):$(features) ;
12 rule FIsBuildFeatureEnabled feature
14 # FIsBuildFeatureEnabled <feature> ;
15 # Returns whether the given build feature <feature> is enabled (if so: "1",
16 # if not: empty list).
18 # <feature> - The name of the build feature (all lower case).
20 feature = [ FQualifiedBuildFeatureName $(feature) ] ;
21 return $(HAIKU_BUILD_FEATURE_$(feature:U)_ENABLED) ;
25 rule FMatchesBuildFeatures specification
27 # FMatchesBuildFeatures <specification> ;
28 # Returns whether the given build feature specification <specification>
29 # holds. <specification> consists of positive and negative build feature
30 # conditions. Conditions can be individual list elements and multiple
31 # conditions can be joined, separated by ",", in a single list element. The
32 # effect is the same; they are considered as single set of conditions.
33 # A positive condition does not start with a "!". It holds when the build
34 # feature named by the element is enabled.
35 # A negative condition starts with a "!". It holds when the build feature
36 # named by the string resulting from removing the leading "!" is not
38 # <specification> holds when it is not empty and
39 # * none of the negative conditions it contains hold and
40 # * if it contains any positive conditions, at least one one of them holds.
42 # <specification> - The build feature specification. A list of individual
43 # conditions or conditions joined by ",".
45 local splitSpecification ;
47 for element in $(specification) {
48 splitSpecification += [ FSplitString $(element) : "," ] ;
50 return [ FConditionsHold $(splitSpecification) : FIsBuildFeatureEnabled ] ;
54 rule FFilterByBuildFeatures list
56 # FFilterByBuildFeatures <list> ;
57 # Filters the list annotated by build feature specifications and returns the
58 # resulting list. The list can be annotated in two different ways:
59 # * A single list element can be annotated by appending "@<specification>"
60 # to it, with <specification> being a build feature specification (a
61 # single comma-separated string). The element appears in the resulting
62 # list, only if <specification> holds.
63 # * A sublist can be annotated by enclosing it in "<specification> @{" (two
64 # separate list elements) and "}@", with <specification> being a build
65 # feature specification (a single comma-separated string). The enclosed
66 # sublist appears in the resulting list, only if <specification> holds.
67 # The sublist annotations can be nested. The annotations themselves don't
68 # appear in the resulting list.
70 # <list> - A list annotated with build feature specifications.
74 # Since we must look ahead one element to be able to decide whether an
75 # element is a regular list element or a features specification for a
76 # subsequent "@{". Hence we always process an element other than "@{" and
77 # "}@" in the next iteration. We append a dummy element to the list so we
78 # don't need special handling for the last element.
79 local evaluationStack = 1 ;
80 local previousElement ;
82 for element in $(list) dummy {
83 local stackTop = $(evaluationStack[1]) ;
84 local processElement = $(previousElement) ;
88 # Pop the topmost specification off the stack.
89 evaluationStack = $(evaluationStack[2-]) ;
90 if ! $(evaluationStack) {
91 Exit "FFilterByBuildFeatures: Unbalanced @{ in: " $(list) ;
94 processElement = $(previousElement) ;
99 if ! $(previousElement) {
100 Exit "FFilterByBuildFeatures: No feature specification"
101 "after }@ in: " $(list) ;
104 if $(evaluationStack[1]) = 1
105 && [ FMatchesBuildFeatures $(previousElement) ] {
106 evaluationStack = 1 $(evaluationStack) ;
108 evaluationStack = 0 $(evaluationStack) ;
116 processElement = $(previousElement) ;
117 previousElement = $(element) ;
121 if $(processElement) && $(stackTop) = 1 {
122 local splitElement = [ Match "(.*)@([^@]*)" : $(processElement) ] ;
124 if [ FMatchesBuildFeatures $(splitElement[2]) ] {
125 filteredList += $(splitElement[1]) ;
128 filteredList += $(processElement) ;
133 if $(evaluationStack[2-]) {
134 Exit "FFilterByBuildFeatures: Unbalanced )@ in: " $(list) ;
137 return $(filteredList) ;
141 rule EnableBuildFeatures features : specification
143 # EnableBuildFeatures <features> : <specification> ;
144 # Enables the build features <features>, if the build features specification
145 # <specification> holds. If <specification> is omitted, the features are
146 # enabled unconditionally.
147 # The rule enables a build feature by adding its given lower case name to
148 # the build variable HAIKU_BUILD_FEATURES and defining a build variable
149 # HAIKU_BUILD_FEATURE_<FEATURE>_ENABLED (<FEATURE> being the upper case name
150 # of the build feature) to "1".
152 # <features> - A list of build feature names (lower case).
153 # <specification> - An optional build features specification (cf.
154 # FMatchesBuildFeatures).
156 features = [ FQualifiedBuildFeatureName $(features) ] ;
159 for feature in $(features) {
160 if ! $(HAIKU_BUILD_FEATURE_$(feature:U)_ENABLED)
161 && ( ! $(specification)
162 || [ FMatchesBuildFeatures $(specification) ] ) {
163 HAIKU_BUILD_FEATURES += $(feature) ;
164 HAIKU_BUILD_FEATURE_$(feature:U)_ENABLED = 1 ;
170 rule BuildFeatureObject feature
172 # BuildFeatureObject <feature> ;
173 # Returns a unique object for the given build feature. It is used for
174 # attaching attribute values to it.
176 feature = [ FQualifiedBuildFeatureName $(feature) ] ;
178 local featureObject = $(HAIKU_BUILD_FEATURE_$(feature:U)) ;
179 if ! $(featureObject) {
180 featureObject = [ NewUniqueTarget ] ;
181 HAIKU_BUILD_FEATURE_$(feature:U) = $(featureObject) ;
184 return $(featureObject) ;
188 rule SetBuildFeatureAttribute feature : attribute : values : package
190 # SetBuildFeatureAttribute <feature> : <attribute> : <values>
192 # Sets attribute <attribute> of a build feature <feature> to value <values>.
193 # If <package> is specified, it names the package the attribute belongs to.
195 local featureObject = [ BuildFeatureObject $(feature) ] ;
196 HAIKU_ATTRIBUTE_$(attribute) on $(featureObject) = $(values) ;
198 HAIKU_ATTRIBUTE_$(attribute):package on $(featureObject) = $(package) ;
203 rule BuildFeatureAttribute feature : attribute : flags
205 # BuildFeatureAttribute <feature> : <attribute> [ : <flags> ] ;
206 # Returns the value of attribute <attribute> of a build feature <feature>.
207 # Flags can be a list of flags which influence the returned value. Currently
208 # only flag "path" is defined, which will convert the attribute value --
209 # which is assumed to be a list of (gristed) targets with a path relative to
210 # the extraction directory of the build feature archive files -- to paths.
211 # A typical example is the "headers" attribute, whose value can be used as
212 # dependency, but which must be converted to a path to be a valid headers
215 local featureObject = [ BuildFeatureObject $(feature) ] ;
217 = [ on $(featureObject) return $(HAIKU_ATTRIBUTE_$(attribute)) ] ;
218 if path in $(flags) {
219 # get the attribute's package and the corresponding extraction dir
221 = [ BuildFeatureAttribute $(feature) : $(attribute):package ] ;
224 directory = [ BuildFeatureAttribute $(feature)
225 : $(package):directory ] ;
228 # translate the values
231 for value in $(values:G=) {
232 paths += [ FDirName $(directory) $(value) ] ;
241 rule ExtractBuildFeatureArchivesExpandValue value : fileName
250 local components = [ Match "([^%]*)(%[^%]*%)(.*)" : $(value) ] ;
252 splitValue += $(value) ;
256 if $(components[1]) {
257 splitValue += $(components[1]) ;
259 splitValue += $(components[2]) ;
260 value = $(components[3]) ;
263 # reassemble the value, performing the substitutions
264 local %packageName% ;
266 local %packageFullVersion% ;
268 while $(splitValue) {
269 local component = $(splitValue[1]) ;
270 splitValue = $(splitValue[2-]) ;
271 switch $(component) {
272 case %packageRevisionedName% :
273 splitValue = %packageName% "-" %packageFullVersion%
276 case %portRevisionedName% :
277 splitValue = %portName% "-" %packageFullVersion% $(splitValue) ;
280 if ! x$(%packageName%) {
281 # extract package name and version from file name
283 = [ Match "([^-]*)-(.*).hpkg" : $(fileName) ] ;
285 %packageName% = $(splitName[1]) ;
287 = [ Match "([^-]*-[^-]*)-.*" : $(splitName[2]) ] ;
288 if ! $(packageFullVersion%) {
289 packageFullVersion% = $(splitName[2]) ;
292 %packageName% = [ Match "(.*).hpkg" : $(fileName) ] ;
293 if ! $(%packageName%) {
294 %packageName% = $(fileName) ;
296 %packageFullVersion% = "" ;
299 # get the port name from the package name
300 splitName = [ FSplitPackageName $(%packageName%) ] ;
301 %portName% = $(splitName[1]) ;
304 value = "$(value)$($(component):E=)" ;
307 value = "$(value)$(component)" ;
315 rule ExtractBuildFeatureArchives feature : list
317 # ExtractBuildFeatureArchives <feature> : <list> ;
318 # Downloads and extracts one or more archives for build feature <feature>
319 # and sets attributes for the build feature to extracted entries. The syntax
321 # "file:" <packageAlias> <packageName>
322 # <attribute>: <value> ...
324 # "file:" <packageAlias2> <packageName2>
327 # <packageAlias> specifies a short name for the archive (e.g. "base" for the
328 # base package, "devel" for the development package, etc.), <packageName>
329 # the unversioned name of the package (e.g. "libsolv_devel").
330 # <attribute> can be any name and <value> any relative path in the
331 # extraction directory. The following placeholders in <value> will be
332 # replaced with the respective value:
333 # * %packageName% is replaced with the name of the package as extracted from
334 # the package file name (may differ from the specified package name e.g.
335 # for bootstrap packages).
336 # * %portName% is replaced with the name of the port the package belongs to.
337 # That is %packageName% with any well-known package type suffix ("_devel",
338 # "_source", etc.) removed.
339 # * %packageFullVersion% is replaced with the the full version string of the
340 # package (i.e. including the revision) as extracted frmo the package file
342 # * %packageRevisionedName% is replaced with what
343 # %packageName%-%packageFullVersion% would be replaced.
344 # * %portRevisionedName% is replaced with what
345 # %portName%-%packageFullVersion% would be replaced.
347 # The attribute with the name "depends" will be handled specially. Its
348 # <value> specifies the name of a package the current package depends on
349 # (e.g. "devel" typically depends on "base"). If such a dependency is
350 # specified the current package will be extracted to the same directory as
351 # the package it depends on. The "depends" attribute must precede any other
352 # attribute for the package.
354 # The rule also sets the build feature attribute "<packageAlias>:directory"
355 # to the extraction directory for each package.
357 local qualifiedFeature = [ FQualifiedBuildFeatureName $(feature) ] ;
358 list = [ FFilterByBuildFeatures $(list) ] ;
361 if $(list[1]) != file: {
362 Exit "ExtractBuildFeatureArchives: Expected \"file: ...\", got:"
366 local package = $(list[2]) ;
367 local file = [ FetchPackage $(list[3]) ] ;
368 local fileName = $(file:BS) ;
371 local directory = [ FDirName $(HAIKU_OPTIONAL_BUILD_PACKAGES_DIR)
373 directory = $(directory:G=$(package)) ;
376 local attribute = [ Match "(.*):" : $(list[1]) ] ;
378 Exit "ExtractBuildFeatureArchives: Expected attribute, got:"
381 if $(attribute) = file {
397 values += [ ExtractBuildFeatureArchivesExpandValue
398 $(list[1]) : $(fileName) ] ;
404 if $(attribute) = depends {
405 # Inherit the extraction directory (with a different grist) and
406 # depend on the extraction directory of the base package.
407 local basePackage = $(values[1]) ;
408 local baseDirectory = [ BuildFeatureAttribute $(feature)
409 : $(basePackage):directory ] ;
410 directory = $(baseDirectory:G=$(package)) ;
411 Depends $(directory) : $(directory:G=$(basePackage)) ;
413 SetBuildFeatureAttribute $(feature) : $(attribute)
414 : [ ExtractArchive $(directory)
415 : $(values) : $(file)
416 : extracted-$(qualifiedFeature)-$(package) ] ;
417 SetBuildFeatureAttribute $(feature) : $(attribute):package
422 SetBuildFeatureAttribute $(feature) : $(package):directory
428 rule InitArchitectureBuildFeatures architecture
430 # InitArchitectureBuildFeatures <architecture> ;
432 # Enable the build features that can be derived directly from the
435 # The build feature rule use TARGET_PACKAGING_ARCH, so set that temporarily.
436 local savedArchitecture = $(TARGET_PACKAGING_ARCH) ;
437 TARGET_PACKAGING_ARCH = $(architecture) ;
439 # Add the target architecture as a build feature.
440 EnableBuildFeatures $(TARGET_ARCH_$(architecture)) ;
442 # For the primary architecture add the "primary" build feature.
443 if $(architecture) = $(TARGET_PACKAGING_ARCHS[1]) {
444 EnableBuildFeatures primary ;
447 # Add all secondary architectures as build features (with prefix).
448 EnableBuildFeatures secondary_$(TARGET_PACKAGING_ARCHS[2-]) ;
450 if $(TARGET_GCC_VERSION_$(architecture)[1]) = 2 {
451 EnableBuildFeatures gcc2 ;
454 TARGET_PACKAGING_ARCH = $(savedArchitecture) ;