vfs: check userland buffers before reading them.
[haiku.git] / build / jam / BuildFeatureRules
blob62d5545da451508d9786e17503aa38793a2c4179
1 rule FQualifiedBuildFeatureName features
3         # FQualifiedBuildFeatureName <features>
4         #
5         # Prepends the name of the current target packaging architecture to the
6         # given feature names.
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).
17         #
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
37         # enabled.
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.
41         #
42         # <specification> - The build feature specification. A list of individual
43         #       conditions or conditions joined by ",".
45         local splitSpecification ;
46         local element ;
47         for element in $(specification) {
48                 splitSpecification += [ FSplitString $(element) : "," ] ;
49         }
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.
69         #
70         # <list> - A list annotated with build feature specifications.
72         local filteredList ;
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 ;
81         local element ;
82         for element in $(list) dummy {
83                 local stackTop = $(evaluationStack[1]) ;
84                 local processElement = $(previousElement) ;
85                 switch $(element) {
86                         case }@ :
87                         {
88                                 # Pop the topmost specification off the stack.
89                                 evaluationStack = $(evaluationStack[2-]) ;
90                                 if ! $(evaluationStack) {
91                                         Exit "FFilterByBuildFeatures: Unbalanced @{ in: " $(list) ;
92                                 }
94                                 processElement = $(previousElement) ;
95                                 previousElement = ;
96                         }
97                         case @{ :
98                         {
99                                 if ! $(previousElement) {
100                                         Exit "FFilterByBuildFeatures: No feature specification"
101                                                 "after }@ in: " $(list) ;
102                                 }
104                                 if $(evaluationStack[1]) = 1
105                                         && [ FMatchesBuildFeatures $(previousElement) ] {
106                                         evaluationStack = 1 $(evaluationStack) ;
107                                 } else {
108                                         evaluationStack = 0 $(evaluationStack) ;
109                                 }
111                                 processElement = ;
112                                 previousElement = ;
113                         }
114                         case * :
115                         {
116                                 processElement = $(previousElement) ;
117                                 previousElement = $(element) ;
118                         }
119                 }
121                 if $(processElement) && $(stackTop) = 1 {
122                         local splitElement = [ Match "(.*)@([^@]*)" : $(processElement) ] ;
123                         if $(splitElement) {
124                                 if [ FMatchesBuildFeatures $(splitElement[2]) ] {
125                                         filteredList += $(splitElement[1]) ;
126                                 }
127                         } else {
128                                 filteredList += $(processElement) ;
129                         }
130                 }
131         }
133         if $(evaluationStack[2-]) {
134                 Exit "FFilterByBuildFeatures: Unbalanced )@ in: " $(list) ;
135         }
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".
151         #
152         # <features> - A list of build feature names (lower case).
153         # <specification> - An optional build features specification (cf.
154         #       FMatchesBuildFeatures).
156         features = [ FQualifiedBuildFeatureName $(features) ] ;
158         local feature ;
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 ;
165                 }
166         }
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) ;
182         }
184         return $(featureObject) ;
188 rule SetBuildFeatureAttribute feature : attribute : values : package
190         # SetBuildFeatureAttribute <feature> : <attribute> : <values>
191         #       [ : <package> ] ;
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) ;
197         if $(package) {
198                 HAIKU_ATTRIBUTE_$(attribute):package on $(featureObject) = $(package) ;
199         }
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
213         # search path.
215         local featureObject = [ BuildFeatureObject $(feature) ] ;
216         local values
217                 = [ on $(featureObject) return $(HAIKU_ATTRIBUTE_$(attribute)) ] ;
218         if path in $(flags) {
219                 # get the attribute's package and the corresponding extraction dir
220                 local package
221                         = [ BuildFeatureAttribute $(feature) : $(attribute):package ] ;
222                 local directory ;
223                 if $(package) {
224                         directory = [ BuildFeatureAttribute $(feature)
225                                 : $(package):directory ] ;
226                 }
228                 # translate the values
229                 local paths ;
230                 local value ;
231                 for value in $(values:G=) {
232                         paths += [ FDirName $(directory) $(value) ] ;
233                 }
234                 values = $(paths) ;
235         }
237         return $(values) ;
241 rule ExtractBuildFeatureArchivesExpandValue value : fileName
243         if ! $(value) {
244                 return $(value) ;
245         }
247         # split the value
248         local splitValue ;
249         while $(value) {
250                 local components = [ Match "([^%]*)(%[^%]*%)(.*)" : $(value) ] ;
251                 if ! $(components) {
252                         splitValue += $(value) ;
253                         break ;
254                 }
256                 if $(components[1]) {
257                         splitValue += $(components[1]) ;
258                 }
259                 splitValue += $(components[2]) ;
260                 value = $(components[3]) ;
261         }
263         # reassemble the value, performing the substitutions
264         local %packageName% ;
265         local %portName% ;
266         local %packageFullVersion% ;
267         value = "" ;
268         while $(splitValue) {
269                 local component = $(splitValue[1]) ;
270                 splitValue = $(splitValue[2-]) ;
271                 switch $(component) {
272                         case %packageRevisionedName% :
273                                 splitValue = %packageName% "-" %packageFullVersion%
274                                         $(splitValue) ;
276                         case %portRevisionedName% :
277                                 splitValue = %portName% "-" %packageFullVersion% $(splitValue) ;
279                         case %*% :
280                                 if ! x$(%packageName%) {
281                                         # extract package name and version from file name
282                                         local splitName
283                                                 = [ Match "([^-]*)-(.*).hpkg" : $(fileName) ] ;
284                                         if $(splitName) {
285                                                 %packageName% = $(splitName[1]) ;
286                                                 %packageFullVersion%
287                                                         = [ Match "([^-]*-[^-]*)-.*" : $(splitName[2]) ] ;
288                                                 if ! $(packageFullVersion%) {
289                                                         packageFullVersion% = $(splitName[2]) ;
290                                                 }
291                                         } else {
292                                                 %packageName% = [ Match "(.*).hpkg" : $(fileName) ] ;
293                                                 if ! $(%packageName%) {
294                                                         %packageName% = $(fileName) ;
295                                                 }
296                                                 %packageFullVersion% = "" ;
297                                         }
299                                         # get the port name from the package name
300                                         splitName = [ FSplitPackageName $(%packageName%) ] ;
301                                         %portName% = $(splitName[1]) ;
302                                 }
304                                 value = "$(value)$($(component):E=)" ;
306                         case * :
307                                 value = "$(value)$(component)" ;
308                 }
309         }
311         return $(value) ;
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
320         # for <list> is:
321         # "file:" <packageAlias> <packageName>
322         #    <attribute>: <value> ...
323         #    ...
324         # "file:" <packageAlias2> <packageName2>
325         # ...
326         #
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
341         #   name.
342         # * %packageRevisionedName% is replaced with what
343         #   %packageName%-%packageFullVersion% would be replaced.
344         # * %portRevisionedName% is replaced with what
345         #   %portName%-%packageFullVersion% would be replaced.
346         #
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.
353         #
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) ] ;
360         while $(list) {
361                 if $(list[1]) != file: {
362                         Exit "ExtractBuildFeatureArchives: Expected \"file: ...\", got:"
363                                 $(list) ;
364                 }
366                 local package = $(list[2]) ;
367                 local file = [ FetchPackage $(list[3]) ] ;
368                 local fileName = $(file:BS) ;
369                 list = $(list[4-]) ;
371                 local directory = [ FDirName $(HAIKU_OPTIONAL_BUILD_PACKAGES_DIR)
372                         $(fileName:B) ] ;
373                 directory = $(directory:G=$(package)) ;
375                 while $(list) {
376                         local attribute = [ Match "(.*):" : $(list[1]) ] ;
377                         if ! $(attribute) {
378                                 Exit "ExtractBuildFeatureArchives: Expected attribute, got:"
379                                         $(list) ;
380                         }
381                         if $(attribute) = file {
382                                 break ;
383                         }
385                         list = $(list[2-]) ;
387                         local values ;
389                         while $(list) {
390                                 switch $(list[1]) {
391                                         case *: :
392                                         {
393                                                 break ;
394                                         }
395                                         case * :
396                                         {
397                                                 values += [ ExtractBuildFeatureArchivesExpandValue
398                                                         $(list[1]) : $(fileName) ] ;
399                                                 list = $(list[2-]) ;
400                                         }
401                                 }
402                         }
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)) ;
412                         } else {
413                                 SetBuildFeatureAttribute $(feature) : $(attribute)
414                                         : [ ExtractArchive $(directory)
415                                                 : $(values) : $(file)
416                                                 : extracted-$(qualifiedFeature)-$(package) ] ;
417                                 SetBuildFeatureAttribute $(feature) : $(attribute):package
418                                         : $(package) ;
419                         }
420                 }
422                 SetBuildFeatureAttribute $(feature) : $(package):directory
423                         : $(directory:G=) ;
424         }
428 rule InitArchitectureBuildFeatures architecture
430         # InitArchitectureBuildFeatures <architecture> ;
431         #
432         # Enable the build features that can be derived directly from the
433         # architecture.
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 ;
445         }
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 ;
452         }
454         TARGET_PACKAGING_ARCH = $(savedArchitecture) ;