1rule Copy 2{ 3 if $(2) { 4 SEARCH on $(2) += $(SEARCH_SOURCE) ; 5 Depends $(1) : <build>copyattr $(2) ; 6 Copy1 $(1) : <build>copyattr $(2) ; 7 } 8} 9 10 11actions Copy1 12{ 13 $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) \ 14 "$(2[1])" -d "$(2[2-])" "$(1)" 15} 16 17 18rule SymLink 19{ 20 # SymLink <target> : <source> : <makeDefaultDependencies> ; 21 # Links <target> to <source>. 22 # <source> is the exact link contents. No binding is done. 23 # <makeDefaultDependencies> If true, <target> will be made a dependency 24 # of the `all' pseudo target, i.e. it will be made by default, and removed 25 # on `jam clean'. 26 27 local target = $(1) ; 28 local source = $(2) ; 29 local makeDefaultDependencies = $(3) ; 30 if ! $(makeDefaultDependencies) { 31 makeDefaultDependencies = true ; 32 } 33 LINKCONTENTS on $(target) = $(source) ; 34 SymLink1 $(target) ; 35 if $(makeDefaultDependencies) = true { 36 LocalDepends files : $(target) ; 37 LocalClean clean : $(target) ; 38 } 39} 40 41actions SymLink1 42{ 43 $(RM) "$(1)" && $(LN) -s "$(LINKCONTENTS)" "$(1)" 44} 45 46rule RelSymLink 47{ 48 # RelSymLink <link> : <link target> : <makeDefaultDependencies> ; 49 # Creates a relative symbolic link from <link> to <link target>. 50 # <link> and <link target> can be usual targets. They may have a grist 51 # and don't need to have any dirname. Their LOCATE variables are used to 52 # find their locations. 53 # <makeDefaultDependencies> If true (which is the default), <link> will be 54 # made a dependency of the `files' pseudo target, i.e. it will be made by 55 # default, and removed on `jam clean'. 56 57 local target = $(1) ; 58 local source = $(2) ; 59 local makeDefaultDependencies = $(3) ; 60 local targetDir = [ on $(target) FDirName $(LOCATE[1]) $(target:D) ] ; 61 local sourceDir = [ on $(source) FDirName $(LOCATE[1]) $(source:D) ] ; 62 local sourcePath = $(source:G=) ; 63 sourcePath = $(sourcePath:D=$(sourceDir)) ; 64 local targetDirComponents = [ FSplitPath $(targetDir) ] ; 65 local sourceComponents = [ FSplitPath $(sourcePath) ] ; 66 67 SymLink $(target) 68 : [ FRelPath $(targetDirComponents) : $(sourceComponents) ] 69 : $(makeDefaultDependencies) ; 70 NOUPDATE $(target) ; 71 Depends $(target) : $(source) ; 72} 73 74rule AbsSymLink 75{ 76 # AbsSymLink <link> : <link target> : <link dir> 77 # : <makeDefaultDependencies> ; 78 # Creates an absolute symbolic link from <link> to <link target>. 79 # <link> and <link target> must be usual targets. If <link dir> is 80 # given, then it is set as LOCATE directory on <link>. 81 # <makeDefaultDependencies> If true (which is the default), <link> will be 82 # made a dependency of the `files' pseudo target, i.e. it will be made by 83 # default, and removed on `jam clean'. 84 85 local makeDefaultDependencies = $(4) ; 86 if ! $(makeDefaultDependencies) { 87 makeDefaultDependencies = true ; 88 } 89 90 Depends $(1) : $(2) ; 91 if $(3) { 92 MakeLocate $(1) : $(3) ; 93 } 94 SEARCH on $(2) += $(SEARCH_SOURCE) ; 95 if $(makeDefaultDependencies) = true { 96 LocalDepends files : $(1) ; 97 LocalClean clean : $(1) ; 98 } 99} 100 101actions AbsSymLink 102{ 103 target="$(2)" 104 case "$target" in 105 /*) ;; 106 *) target=`pwd`/"$target";; 107 esac 108 $(RM) "$(1)" && $(LN) -s "$target" "$(1)" 109} 110 111rule HaikuInstall installAndUninstall : dir : sources : installgrist 112 : installRule : targets 113{ 114 # Usage: HaikuInstall <[ install [ and uninstall ] pseudotarget ]> 115 # : <directory> : <sources to install> : [ <installgrist> ] 116 # : [ <install rule> ] : [ <targets> ] ; 117 118 local install = $(installAndUninstall[1]) ; 119 install ?= install ; 120 local uninstall = $(installAndUninstall[2]) ; 121 uninstall ?= un$(install) ; 122 installgrist ?= $(INSTALLGRIST) ; 123 installRule ?= Install ; 124 125 targets ?= $(sources) ; 126 targets = $(targets:G=$(installgrist)) ; 127 128 NotFile $(install) ; 129 NotFile $(uninstall) ; 130 Depends $(install) : $(targets) ; 131 Clean $(uninstall) : $(targets) ; 132 133 SEARCH on $(sources) += $(SEARCH_SOURCE) ; 134 MakeLocate $(targets) : $(dir) ; 135 136 local source ; 137 for source in $(sources) { 138 local target = $(targets[1]) ; 139 targets = $(targets[2-]) ; 140 141 Depends $(target) : $(source) ; 142 $(installRule) $(target) : $(source) ; 143 144 if [ on $(target) return $(MODE) ] { 145 Chmod $(target) ; 146 } 147 148 if $(OWNER) && $(CHOWN) { 149 Chown $(target) ; 150 OWNER on $(target) = $(OWNER) ; 151 } 152 153 if $(GROUP) && $(CHGRP) { 154 Chgrp $(target) ; 155 GROUP on $(target) = $(GROUP) ; 156 } 157 } 158} 159 160rule InstallAbsSymLinkAdapter 161{ 162 # InstallAbsSymLinkAdapter <link> : <link target> 163 if ! [ on $(2) return $(TARGET) ] { 164 TARGET on $(2) = [ on $(2) return $(SEARCH) ] ; 165 } 166 AbsSymLink $(1) : $(2) : : false ; 167} 168 169rule HaikuInstallAbsSymLink 170{ 171 # Usage: HaikuInstallAbsSymLink <[ install [ and uninstall ] pseudotarget ]> 172 # : <directory> : <sources to install> 173 # : [ <installgrist> ] ; 174 HaikuInstall $(1) : $(2) : $(3) : $(4) : InstallAbsSymLinkAdapter ; 175} 176 177rule InstallRelSymLinkAdapter 178{ 179 # InstallRelSymLinkAdapter <link> : <link target> 180 if ! [ on $(2) return $(TARGET) ] { 181 TARGET on $(2) = [ on $(2) return $(SEARCH) ] ; 182 } 183 RelSymLink $(1) : $(2) : false ; 184} 185 186rule HaikuInstallRelSymLink 187{ 188 # Usage: HaikuInstallRelSymLink <[ install [ and uninstall ] pseudotarget ]> 189 # : <directory> : <sources to install> 190 # : [ <installgrist> ] ; 191 HaikuInstall $(1) : $(2) : $(3) : $(4) : InstallRelSymLinkAdapter ; 192} 193 194 195rule UnarchiveObjects 196{ 197 # UnarchiveObjects <target objects> : <static object> 198 199 MakeLocateArch $(1) ; 200 Depends $(1) : $(2) ; 201 SEARCH on $(2) = $(SEARCH_SOURCE) ; 202} 203 204actions UnarchiveObjects 205{ 206 ( cd $(1[1]:D) && $(TARGET_AR_$(TARGET_PACKAGING_ARCH)) \ 207 $(TARGET_UNARFLAGS_$(TARGET_PACKAGING_ARCH)) "$(2)" $(1:BS) ) 208} 209 210 211rule ExtractArchive directory : entries : archiveFile : grist 212{ 213 # ExtractArchive <directory> : <entries> : <archiveFile> [ : <grist> ] 214 # 215 # Extract the archive file target <archiveFile> to directory <directory>. 216 # The rule can be called multiple times for different <entries> for the same 217 # <directory> and <archiveFile> combo. 218 # 219 # <directory> - The directory into which to extract the archive file. The 220 # directory is created by this rule and it is the target 221 # that the extract action is associated with. 222 # <entries> - The entries of the archive file one is interested in. The 223 # rule always extracts the complete archive file, from the 224 # given entries the rule creates targets (using <grist>) 225 # representing the extracted entries. Those targets are 226 # returned by the rule. 227 # <archiveFile> - The archive file target to extract. 228 # <grist> - The grist used to create targets from <entries>. Defaults to 229 # "extracted". 230 231 grist ?= extracted ; 232 233 # Turn the entries into targets to build. 234 local targets ; 235 local entry ; 236 for entry in $(entries) { 237 local target = $(entry:G=$(grist)) ; 238 targets += $(target) ; 239 } 240 241 LOCATE on $(targets) = $(directory:G=) ; 242 Depends $(targets) : $(directory) $(archiveFile) ; 243 NoUpdate $(targets) ; 244 245 # one-time initialization for the main target (the directory) 246 if ! [ on $(directory) return $(INITIALIZED) ] { 247 # make sure the parent dir exists 248 local parentDir = $(directory:PG=dir) ; 249 Depends $(directory) : $(parentDir) ; 250 MkDir $(parentDir) ; 251 252 NoUpdate $(directory) ; 253 Depends $(directory) : $(archiveFile) ; 254 switch $(archiveFile:S) 255 { 256 case .zip : 257 ExtractZipArchive1 $(directory) : $(archiveFile) ; 258 259 case .tgz : 260 ExtractTarArchive1 $(directory) : $(archiveFile) ; 261 262 case .hpkg : 263 Depends $(directory) : <build>package ; 264 ExtractHPKGArchive1 $(directory) 265 : <build>package $(archiveFile) ; 266 267 case "" : 268 Exit "ExtractArchive: No archive passed" ; 269 270 case * : 271 Exit "ExtractArchive: Unhandled archive extension:" 272 "$(archiveFile:S)" ; 273 } 274 INITIALIZED on $(directory) = 1 ; 275 } 276 277 return $(targets) ; 278} 279 280 281actions ExtractZipArchive1 282{ 283 mkdir -p $(1) 284 unzip -q -u -o -d $(1) $(2) 285} 286 287 288actions ExtractTarArchive1 289{ 290 mkdir -p $(1) 291 tar -C $(1) -xf $(2) 292} 293 294 295actions ExtractHPKGArchive1 296{ 297 mkdir -p "$(1)" 298 $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) \ 299 $(2[1]) extract -C "$(1)" "$(2[2])" 300} 301 302 303rule ObjectReference 304{ 305 # ObjectReference <reference object> : <source object> 306 # Makes <reference object> refer to the same file as <source object>. 307 # The filenames must of course be identical. 308 # <source object> must have already been LOCATEd. 309 310 local ref = $(1) ; 311 local source = $(2) ; 312 if $(ref) != $(source) { 313 Depends $(ref) : $(source) ; 314 LOCATE on $(ref) = [ on $(source) return $(LOCATE) ] ; 315 } 316} 317 318rule ObjectReferences 319{ 320 # ObjectReferences <source objects> 321 # Creates local references to <source objects>, i.e. identifiers with the 322 # current grist referring to the same files. <source objects> must have 323 # already been LOCATEd. 324 325 local source ; 326 for source in $(1) { 327 ObjectReference [ FGristFiles $(source) ] : $(source) ; 328 } 329} 330 331 332rule CopySetHaikuRevision target : source 333{ 334 # CopySetHaikuRevision <target> : <source> 335 # 336 # Copy <source> to <target>, writing the Git revision of the working 337 # directory into the haiku revision section of <target>. 338 # 339 # <target> - Output file target. Gristed and located target. 340 # <source> - ELF object to be copied. Gristed and located target. 341 342 PropagateContainerUpdateTargetFlags $(target) : $(source) ; 343 344 HAIKU_TARGET_IS_EXECUTABLE on $(target) = [ on $(source) 345 return $(HAIKU_TARGET_IS_EXECUTABLE) ] ; 346 347 local revisionFile = [ DetermineHaikuRevision ] ; 348 349 Depends $(target) 350 : <build>copyattr <build>set_haiku_revision $(source) $(revisionFile) ; 351 CopySetHaikuRevision1 $(target) 352 : <build>copyattr <build>set_haiku_revision $(source) $(revisionFile) ; 353} 354 355 356actions CopySetHaikuRevision1 357{ 358 export $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) 359 360 $(2[1]) --data $(2[3]) $(1) || exit 1 361 362 revision=0 363 if [ -n "$(2[4]:E=)" ]; then 364 revision="`cat $(2[4]:E=)`" 365 fi 366 $(2[2]) $(1) "$revision" 367} 368 369 370rule DetermineHaikuRevision 371{ 372 # If existing, make the target depend on the .git/index file in the 373 # root directory, so it gets updated when the revision changes due to 374 # commits or merges. 375 local gitIndex = <haiku-rootdir-git>index ; 376 local revisionFile = <haiku-rootdir>haiku-revision ; 377 if ! [ on $(gitIndex) return $(HAIKU_GIT_REVISION_DETERMINED) ] { 378 HAIKU_GIT_REVISION_DETERMINED on $(gitIndex) = 1 ; 379 MakeLocate $(revisionFile) : $(HAIKU_BUILD_OUTPUT_DIR) ; 380 LocalClean clean : $(revisionFile) ; 381 if $(HAIKU_REVISION) { 382 DetermineHaikuRevision2 $(revisionFile) ; 383 } else if [ Glob [ FDirName $(HAIKU_TOP) .git ] : index ] { 384 SEARCH on $(gitIndex) = [ FDirName $(HAIKU_TOP) .git ] ; 385 Depends $(revisionFile) : $(gitIndex) ; 386 DetermineHaikuRevision1 $(revisionFile) : $(gitIndex) ; 387 } else { 388 revisionFile = ; 389 } 390 } 391 392 return $(revisionFile) ; 393} 394 395 396actions DetermineHaikuRevision1 397{ 398 $(HAIKU_TOP)/build/scripts/determine_haiku_revision $(HAIKU_TOP) $(1) 399} 400 401 402actions DetermineHaikuRevision2 403{ 404 echo $(HAIKU_REVISION) > $(1) 405} 406 407 408rule DataFileToSourceFile sourceFile : dataFile : dataVariable : sizeVariable 409{ 410 sourceFile = [ FGristFiles $(sourceFile) ] ; 411 MakeLocateCommonPlatform $(sourceFile) ; 412 413 sizeVariable ?= $(dataVariable)Size ; 414 415 DATA_VARIABLE on $(sourceFile) = $(dataVariable) ; 416 SIZE_VARIABLE on $(sourceFile) = $(sizeVariable) ; 417 418 Depends $(sourceFile) : <build>data_to_source $(dataFile) ; 419 DataFileToSourceFile1 $(sourceFile) : <build>data_to_source $(dataFile) ; 420 LocalClean clean : $(sourceFile) ; 421} 422 423actions DataFileToSourceFile1 424{ 425 $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) \ 426 $(2[1]) $(DATA_VARIABLE) $(SIZE_VARIABLE) $(2[2]) $(1) 427} 428 429rule DownloadLocatedFile target : url : source 430{ 431 # DownloadLocatedFile <target> : <url> [ : <source> ] ; 432 # 433 # <source> is an optional target that <target> will be made dependent on. 434 # Its resolved path can be used in <url> via '$source'. 435 436 URL on $(target) = $(url) ; 437 438 if $(source) { 439 Depends $(target) : $(source) ; 440 } 441 442 DownloadLocatedFile1 $(target) : $(source) ; 443} 444 445if $(HAIKU_NO_DOWNLOADS) = 1 { 446 actions DownloadLocatedFile1 447 { 448 source="$(2)" 449 echo "ERROR: Would need to download $(URL), but HAIKU_NO_DOWNLOADS is set!" 450 exit 1 451 } 452} else { 453 actions DownloadLocatedFile1 454 { 455 source="$(2)" 456 wget --retry-connrefused --timeout 30 -O "$(1)" $(URL) || exit 1 457 touch "$(1)" 458 } 459} 460 461rule DownloadFile file : url : source 462{ 463 # DownloadFile <file> : <url> [ : <source> ] ; 464 # 465 # <source> is an optional target that the target will be made dependent on. 466 # Its resolved path can be used in <url> via '$source'. 467 468 file = $(file:G=download) ; 469 470 # Request the download only once. 471 if [ on $(file) return $(HAIKU_FILE_DOWNLOAD) ] { 472 return $(file) ; 473 } 474 475 HAIKU_FILE_DOWNLOAD on $(file) = 1 ; 476 477 MakeLocate $(file) : $(HAIKU_DOWNLOAD_DIR) ; 478 DownloadLocatedFile $(file) : $(url) : $(source) ; 479 480 return $(file) ; 481} 482 483 484actions ChecksumFileSHA256 485{ 486 $(HOST_SHA256) $(2) \ 487 | $(HOST_EXTENDED_REGEX_SED) 's,([^[:space:]]*).*,\1,' > $(1) 488 # The sed part is only necessary for sha256sum, but it doesn't harm for 489 # sha256 either. 490} 491 492 493rule Sed target : source : substitutions : targetMap 494{ 495 # Sed <target> : [ <source> ] : <substitutions> [ : <targetMap> ] ; 496 # 497 # Performs substitutions in a text file. If <source> is given, that is the 498 # input, otherwise the substitutions are performed in place on <target>. The 499 # caller is responsible for locating <target>, <source>, and any other used 500 # target. 501 # 502 # <target> - The target file. 503 # <source> - The source file. If not given, the substitutions are performed 504 # in place on <target>. If given, a dependency of <target> to <source> 505 # will be established. 506 # <substitutions> - List of substitutions to be performed. Each element 507 # specifies a substitution. It's a partial sed "s" command of the form 508 # "<pattern>,<replacement>". 509 # <targetMap> - A list of elements of the form "<variable>=<mappedTarget>". 510 # <variable> specifies a name of a shell variable, <mappedTarget> a jam 511 # target whose bound name will be assigned to the shell variable. The 512 # variable can be used in <substitutions>. A dependency of <target> to 513 # <mappedTarget> will be established. 514 515 # We need a temporary (shell) file to which we write the target variable 516 # mappings and the sed invocations. This is necessary, since multiple rule 517 # invocations are allowed for a target, so that we cannot use on-target 518 # variables. 519 local script = [ NextID ] ; 520 script = temp-sed-script-$(target:BS)-$(script) ; 521 522 # process the target variable mappings 523 local mappedTargets ; 524 local targetMapElement ; 525 for targetMapElement in $(targetMap) { 526 local split = [ Match ([^=]+)=(.*) : $(targetMapElement) ] ; 527 HAIKU_SED_SCRIPT_VARIABLE on $(script) += $(split[1]) ; 528 local mappedTarget = $(split[2]) ; 529 mappedTargets += $(mappedTarget) ; 530 } 531 532 HAIKU_SED_SCRIPT_SUBSTITUTIONS on $(script) 533 = "-e \"s,$(substitutions),g\"" ; 534 HAIKU_SED_SCRIPT_SOURCE on $(script) = $(source) ; 535 if $(source) { 536 HAIKU_SED_SCRIPT_SOURCE_ARGUMENTS on $(script) = ">" ; 537 } else { 538 HAIKU_SED_SCRIPT_SOURCE_ARGUMENTS on $(script) = -i ; 539 } 540 541 # build the script 542 MakeLocate $(script) : $(HAIKU_TMP_DIR) ; 543 Depends $(script) : $(mappedTargets) $(source) ; 544 SedCreateScript $(script) : $(mappedTargets) ; 545 546 # build the target 547 Depends $(target) : $(script) ; 548 Sed1 $(target) : $(script) ; 549 RmTemps $(target) : $(script) ; 550} 551 552 553actions SedCreateScript bind HAIKU_SED_SCRIPT_SOURCE 554{ 555 set -o errexit 556 557 $(RM) "$(1)" 558 touch "$(1)" 559 560 set -- $(2) 561 for variable in "$(HAIKU_SED_SCRIPT_VARIABLE)" ; do 562 echo "$variable=\"$1\"" >> "$(1)" 563 shift 564 done 565 566 echo sed '$(HAIKU_SED_SCRIPT_SUBSTITUTIONS)' \ 567 '"$(HAIKU_SED_SCRIPT_SOURCE)"' "$(HAIKU_SED_SCRIPT_SOURCE_ARGUMENTS)" \ 568 '"$target"' >> "$(1)" 569} 570 571 572actions Sed1 573{ 574 set -o errexit 575 576 target="$(1)" 577 . "$(2)" 578} 579 580 581rule StripFile target : source 582{ 583 # Note: The caller is reponsible for matching TARGET_PACKAGING_ARCH with 584 # the architecture the target was built for. 585 STRIP on $(target) = $(HAIKU_STRIP_$(TARGET_PACKAGING_ARCH)) ; 586 587 PropagateContainerUpdateTargetFlags $(target) : $(source) ; 588 589 LocalClean clean : $(target) ; 590 Depends $(target) : $(source) <build>xres <build>copyattr ; 591 StripFile1 $(target) : $(source) <build>xres <build>copyattr ; 592} 593 594 595actions StripFile1 596{ 597 export $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) 598 "$(STRIP)" -o "$(1)" "$(2[1])" 599 "$(2[2])" -o "$(1)" "$(2[1])" 600 "$(2[3])" "$(2[1])" "$(1)" 601} 602 603 604rule StripFiles files 605{ 606 # Note: The caller is reponsible for matching TARGET_PACKAGING_ARCH with 607 # the architecture the targets were built for. 608 local strippedFiles ; 609 local file ; 610 for file in $(files) { 611 local strippedFile = $(file:G=stripped_$(file:G)) ; 612 # Place the stripped file in a "stripped" subdirectory of the file's 613 # location. 614 local location = [ on $(file) return $(LOCATE) ] ; 615 if ! $(location) { 616 location 617 = $(TARGET_COMMON_DEBUG_OBJECT_DIR_$(TARGET_PACKAGING_ARCH)) ; 618 } 619 MakeLocateArch $(strippedFile) : [ FDirName $(location) stripped ] ; 620 StripFile $(strippedFile) : $(file) ; 621 strippedFiles += $(strippedFile) ; 622 } 623 624 return $(strippedFiles) ; 625} 626