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 $(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 DetermineEffectiveHaikuRevision 409{ 410 local revisionFile = <haiku-rootdir>effective-haiku-revision ; 411 if ! [ on $(revisionFile) return $(HAIKU_EFFECTIVE_REVISION_DETERMINED) ] { 412 HAIKU_EFFECTIVE_REVISION_DETERMINED on $(revisionFile) = 1 ; 413 MakeLocate $(revisionFile) : $(HAIKU_BUILD_OUTPUT_DIR) ; 414 local rawRevision = [ DetermineHaikuRevision ] ; 415 Depends $(revisionFile) : $(rawRevision) ; 416 DetermineEffectiveHaikuRevision1 $(revisionFile) : $(rawRevision) ; 417 LocalClean clean : $(revisionFile) ; 418 } 419 420 return $(revisionFile) ; 421} 422 423 424actions DetermineEffectiveHaikuRevision1 425{ 426 revision=`sed -n 's,^\(hrev[0-9]*\).*,\1,p' "$(2:E=unknown-revision)"` 427 if [ -z "$revision" ]; then 428 echo "Error: unable to determine the effective Haiku revision." 429 echo " If you are using a Haiku clone without tags, you can set" 430 echo " the revision tag to use with e.g. HAIKU_REVISION=hrev43210" 431 exit 1 432 fi 433 echo "${revision:-0}" > "$(1)" 434} 435 436 437rule DataFileToSourceFile sourceFile : dataFile : dataVariable : sizeVariable 438{ 439 sourceFile = [ FGristFiles $(sourceFile) ] ; 440 MakeLocateCommonPlatform $(sourceFile) ; 441 442 sizeVariable ?= $(dataVariable)Size ; 443 444 DATA_VARIABLE on $(sourceFile) = $(dataVariable) ; 445 SIZE_VARIABLE on $(sourceFile) = $(sizeVariable) ; 446 447 Depends $(sourceFile) : <build>data_to_source $(dataFile) ; 448 DataFileToSourceFile1 $(sourceFile) : <build>data_to_source $(dataFile) ; 449 LocalClean clean : $(sourceFile) ; 450} 451 452actions DataFileToSourceFile1 453{ 454 $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) 455 $(2[1]) $(DATA_VARIABLE) $(SIZE_VARIABLE) $(2[2]) $(1) 456} 457 458rule DownloadLocatedFile target : url : source 459{ 460 # DownloadLocatedFile <target> : <url> [ : <source> ] ; 461 # 462 # <source> is an optional target that <target> will be made dependent on. 463 # Its resolved path can be used in <url> via '$source'. 464 465 URL on $(target) = $(url) ; 466 467 if $(source) { 468 Depends $(target) : $(source) ; 469 } 470 471 DownloadLocatedFile1 $(target) : $(source) ; 472} 473 474actions DownloadLocatedFile1 475{ 476 source="$(2)" 477 if [ "$(HAIKU_NO_DOWNLOADS)" = 1 ]; then 478 echo "ERROR: Would need to download $(URL), but HAIKU_NO_DOWNLOADS is set!" 479 exit 1 480 fi 481 wget --retry-connrefused --timeout 10 -O "$(1)" $(URL) || exit 1 482 touch "$(1)" 483} 484 485rule DownloadFile file : url : source 486{ 487 # DownloadFile <file> : <url> [ : <source> ] ; 488 # 489 # <source> is an optional target that the target will be made dependent on. 490 # Its resolved path can be used in <url> via '$source'. 491 492 file = $(file:G=download) ; 493 494 # Request the download only once. 495 if [ on $(file) return $(HAIKU_FILE_DOWNLOAD) ] { 496 return $(file) ; 497 } 498 499 HAIKU_FILE_DOWNLOAD on $(file) = 1 ; 500 501 MakeLocate $(file) : $(HAIKU_DOWNLOAD_DIR) ; 502 DownloadLocatedFile $(file) : $(url) : $(source) ; 503 504 return $(file) ; 505} 506 507 508actions ChecksumFileSHA256 509{ 510 $(HOST_SHA256) $(2) \ 511 | $(HOST_EXTENDED_REGEX_SED) 's,([^[:space:]]*).*,\1,' > $(1) 512 # The sed part is only necessary for sha256sum, but it doesn't harm for 513 # sha256 either. 514} 515 516 517rule Sed target : source : substitutions : targetMap 518{ 519 # Sed <target> : [ <source> ] : <substitutions> [ : <targetMap> ] ; 520 # 521 # Performs substitutions in a text file. If <source> is given, that is the 522 # input, otherwise the substitutions are performed in place on <target>. The 523 # caller is responsible for locating <target>, <source>, and any other used 524 # target. 525 # 526 # <target> - The target file. 527 # <source> - The source file. If not given, the substitutions are performed 528 # in place on <target>. If given, a dependency of <target> to <source> 529 # will be established. 530 # <substitutions> - List of substitutions to be performed. Each element 531 # specifies a substitution. It's a partial sed "s" command of the form 532 # "<pattern>,<replacement>". 533 # <targetMap> - A list of elements of the form "<variable>=<mappedTarget>". 534 # <variable> specifies a name of a shell variable, <mappedTarget> a jam 535 # target whose bound name will be assigned to the shell variable. The 536 # variable can be used in <substitutions>. A dependency of <target> to 537 # <mappedTarget> will be established. 538 539 # We need a temporary (shell) file to which we write the target variable 540 # mappings and the sed invocations. This is necessary, since multiple rule 541 # invocations are allowed for a target, so that we cannot use on-target 542 # variables. 543 local script = [ NextID ] ; 544 script = temp-sed-script-$(target:BS)-$(script) ; 545 546 # process the target variable mappings 547 local mappedTargets ; 548 local targetMapElement ; 549 for targetMapElement in $(targetMap) { 550 local split = [ Match ([^=]+)=(.*) : $(targetMapElement) ] ; 551 HAIKU_SED_SCRIPT_VARIABLE on $(script) += $(split[1]) ; 552 local mappedTarget = $(split[2]) ; 553 mappedTargets += $(mappedTarget) ; 554 } 555 556 HAIKU_SED_SCRIPT_SUBSTITUTIONS on $(script) 557 = "-e \"s,$(substitutions),g\"" ; 558 HAIKU_SED_SCRIPT_SOURCE on $(script) = $(source) ; 559 if $(source) { 560 HAIKU_SED_SCRIPT_SOURCE_ARGUMENTS on $(script) = ">" ; 561 } else { 562 HAIKU_SED_SCRIPT_SOURCE_ARGUMENTS on $(script) = -i ; 563 } 564 565 # build the script 566 MakeLocate $(script) : $(HAIKU_TMP_DIR) ; 567 Depends $(script) : $(mappedTargets) $(source) ; 568 SedCreateScript $(script) : $(mappedTargets) ; 569 570 # build the target 571 Depends $(target) : $(script) ; 572 Sed1 $(target) : $(script) ; 573 RmTemps $(target) : $(script) ; 574} 575 576 577actions SedCreateScript bind HAIKU_SED_SCRIPT_SOURCE 578{ 579 set -o errexit 580 581 $(RM) "$(1)" 582 touch "$(1)" 583 584 set -- $(2) 585 for variable in "$(HAIKU_SED_SCRIPT_VARIABLE)" ; do 586 echo "$variable=\"$1\"" >> "$(1)" 587 shift 588 done 589 590 echo sed '$(HAIKU_SED_SCRIPT_SUBSTITUTIONS)' \ 591 '"$(HAIKU_SED_SCRIPT_SOURCE)"' "$(HAIKU_SED_SCRIPT_SOURCE_ARGUMENTS)" \ 592 '"$target"' >> "$(1)" 593} 594 595 596actions Sed1 597{ 598 set -o errexit 599 600 target="$(1)" 601 . "$(2)" 602} 603 604 605rule StripFile target : source 606{ 607 # Note: The caller is reponsible for matching TARGET_PACKAGING_ARCH with 608 # the architecture the target was built for. 609 STRIP on $(target) = $(HAIKU_STRIP_$(TARGET_PACKAGING_ARCH)) ; 610 611 PropagateContainerUpdateTargetFlags $(target) : $(source) ; 612 613 LocalClean clean : $(target) ; 614 Depends $(target) : $(source) <build>xres <build>copyattr ; 615 StripFile1 $(target) : $(source) <build>xres <build>copyattr ; 616} 617 618 619actions StripFile1 620{ 621 $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) 622 "$(STRIP)" -o "$(1)" "$(2[1])" 623 "$(2[2])" -o "$(1)" "$(2[1])" 624 "$(2[3])" "$(2[1])" "$(1)" 625} 626 627 628rule StripFiles files 629{ 630 # Note: The caller is reponsible for matching TARGET_PACKAGING_ARCH with 631 # the architecture the targets were built for. 632 local strippedFiles ; 633 local file ; 634 for file in $(files) { 635 local strippedFile = $(file:G=stripped_$(file:G)) ; 636 # Place the stripped file in a "stripped" subdirectory of the file's 637 # location. 638 local location = [ on $(file) return $(LOCATE) ] ; 639 if ! $(location) { 640 location 641 = $(TARGET_COMMON_DEBUG_OBJECT_DIR_$(TARGET_PACKAGING_ARCH)) ; 642 } 643 MakeLocateArch $(strippedFile) : [ FDirName $(location) stripped ] ; 644 StripFile $(strippedFile) : $(file) ; 645 strippedFiles += $(strippedFile) ; 646 } 647 648 return $(strippedFiles) ; 649} 650