1#!/usr/local/bin/python3.8 2 3# Copyright (C) 2012. Jurko Gospodnetic 4# Distributed under the Boost Software License, Version 1.0. 5# (See accompanying file LICENSE_1_0.txt or copy at 6# http://www.boost.org/LICENSE_1_0.txt) 7 8# Tests Boost Build's project-id handling. 9 10import BoostBuild 11import sys 12 13 14def test_assigning_project_ids(): 15 t = BoostBuild.Tester(pass_toolset=False) 16 t.write("jamroot.jam", """\ 17import assert ; 18import modules ; 19import notfile ; 20import project ; 21 22rule assert-project-id ( id ? : module-name ? ) 23{ 24 module-name ?= [ CALLER_MODULE ] ; 25 assert.result $(id) : project.attribute $(module-name) id ; 26} 27 28# Project rule modifies the main project id. 29assert-project-id ; # Initial project id is empty 30project foo ; assert-project-id /foo ; 31project ; assert-project-id /foo ; 32project foo ; assert-project-id /foo ; 33project bar ; assert-project-id /bar ; 34project /foo ; assert-project-id /foo ; 35project "" ; assert-project-id /foo ; 36 37# Calling the use-project rule does not modify the project's main id. 38use-project id1 : a ; 39# We need to load the 'a' Jamfile module manually as the use-project rule will 40# only schedule the load to be done after the current module load finishes. 41a-module = [ project.load a ] ; 42assert-project-id : $(a-module) ; 43use-project id2 : a ; 44assert-project-id : $(a-module) ; 45modules.call-in $(a-module) : project baz ; 46assert-project-id /baz : $(a-module) ; 47use-project id3 : a ; 48assert-project-id /baz : $(a-module) ; 49 50# Make sure the project id still holds after all the scheduled use-project loads 51# complete. We do this by scheduling the assert for the Jam action scheduling 52# phase. 53notfile x : @assert-a-rule ; 54rule assert-a-rule ( target : : properties * ) 55{ 56 assert-project-id /baz : $(a-module) ; 57} 58""") 59 t.write("a/jamfile.jam", """\ 60# Initial project id for this module is empty. 61assert-project-id ; 62""") 63 t.run_build_system() 64 t.cleanup() 65 66 67def test_using_project_ids_in_target_references(): 68 t = BoostBuild.Tester() 69 __write_appender(t, "appender.jam") 70 t.write("jamroot.jam", """\ 71import type ; 72type.register AAA : _a ; 73type.register BBB : _b ; 74 75import appender ; 76appender.register aaa-to-bbb : AAA : BBB ; 77 78use-project id1 : a ; 79use-project /id2 : a ; 80 81bbb b1 : /id1//target ; 82bbb b2 : /id2//target ; 83bbb b3 : /id3//target ; 84bbb b4 : a//target ; 85bbb b5 : /project-a1//target ; 86bbb b6 : /project-a2//target ; 87bbb b7 : /project-a3//target ; 88 89use-project id3 : a ; 90""") 91 t.write("a/source._a", "") 92 t.write("a/jamfile.jam", """\ 93project project-a1 ; 94project /project-a2 ; 95import alias ; 96alias target : source._a ; 97project /project-a3 ; 98""") 99 100 t.run_build_system() 101 t.expect_addition("bin/b%d._b" % x for x in range(1, 8)) 102 t.expect_nothing_more() 103 104 t.cleanup() 105 106 107def test_repeated_ids_for_different_projects(): 108 t = BoostBuild.Tester() 109 110 t.write("a/jamfile.jam", "") 111 t.write("jamroot.jam", "project foo ; use-project foo : a ;") 112 t.run_build_system(status=1) 113 t.expect_output_lines("""\ 114error: Attempt to redeclare already registered project id '/foo'. 115error: Original project: 116error: Name: Jamfile<*> 117error: Module: Jamfile<*> 118error: Main id: /foo 119error: File: jamroot.jam 120error: Location: . 121error: New project: 122error: Module: Jamfile<*> 123error: File: a*jamfile.jam 124error: Location: a""") 125 126 t.write("jamroot.jam", "use-project foo : a ; project foo ;") 127 t.run_build_system(status=1) 128 t.expect_output_lines("""\ 129error: Attempt to redeclare already registered project id '/foo'. 130error: Original project: 131error: Name: Jamfile<*> 132error: Module: Jamfile<*> 133error: Main id: /foo 134error: File: jamroot.jam 135error: Location: . 136error: New project: 137error: Module: Jamfile<*> 138error: File: a*jamfile.jam 139error: Location: a""") 140 141 t.write("jamroot.jam", """\ 142import modules ; 143import project ; 144modules.call-in [ project.load a ] : project foo ; 145project foo ; 146""") 147 t.run_build_system(status=1) 148 t.expect_output_lines("""\ 149error: at jamroot.jam:4 150error: Attempt to redeclare already registered project id '/foo'. 151error: Original project: 152error: Name: Jamfile<*> 153error: Module: Jamfile<*> 154error: Main id: /foo 155error: File: a*jamfile.jam 156error: Location: a 157error: New project: 158error: Module: Jamfile<*> 159error: File: jamroot.jam 160error: Location: .""") 161 162 t.cleanup() 163 164 165def test_repeated_ids_for_same_project(): 166 t = BoostBuild.Tester() 167 168 t.write("jamroot.jam", "project foo ; project foo ;") 169 t.run_build_system() 170 171 t.write("jamroot.jam", "project foo ; use-project foo : . ;") 172 t.run_build_system() 173 174 t.write("jamroot.jam", "project foo ; use-project foo : ./. ;") 175 t.run_build_system() 176 177 t.write("jamroot.jam", """\ 178project foo ; 179use-project foo : . ; 180use-project foo : ./aaa/.. ; 181use-project foo : ./. ; 182""") 183 t.run_build_system() 184 185 # On Windows we have a case-insensitive file system and we can use 186 # backslashes as path separators. 187 # FIXME: Make a similar test pass on Cygwin. 188 if sys.platform in ['win32']: 189 t.write("a/fOo bAr/b/jamfile.jam", "") 190 t.write("jamroot.jam", r""" 191use-project bar : "a/foo bar/b" ; 192use-project bar : "a/foO Bar/b" ; 193use-project bar : "a/foo BAR/b/" ; 194use-project bar : "a\\.\\FOO bar\\b\\" ; 195""") 196 t.run_build_system() 197 t.rm("a") 198 199 t.write("bar/jamfile.jam", "") 200 t.write("jamroot.jam", """\ 201use-project bar : bar ; 202use-project bar : bar/ ; 203use-project bar : bar// ; 204use-project bar : bar/// ; 205use-project bar : bar//// ; 206use-project bar : bar/. ; 207use-project bar : bar/./ ; 208use-project bar : bar/////./ ; 209use-project bar : bar/../bar/xxx/.. ; 210use-project bar : bar/..///bar/xxx///////.. ; 211use-project bar : bar/./../bar/xxx/.. ; 212use-project bar : bar/.////../bar/xxx/.. ; 213use-project bar : bar/././../bar/xxx/.. ; 214use-project bar : bar/././//////////../bar/xxx/.. ; 215use-project bar : bar/.///.////../bar/xxx/.. ; 216use-project bar : bar/./././xxx/.. ; 217use-project bar : bar/xxx////.. ; 218use-project bar : bar/xxx/.. ; 219use-project bar : bar///////xxx/.. ; 220""") 221 t.run_build_system() 222 t.rm("bar") 223 224 # On Windows we have a case-insensitive file system and we can use 225 # backslashes as path separators. 226 # FIXME: Make a similar test pass on Cygwin. 227 if sys.platform in ['win32']: 228 t.write("baR/jamfile.jam", "") 229 t.write("jamroot.jam", r""" 230use-project bar : bar ; 231use-project bar : BAR ; 232use-project bar : bAr ; 233use-project bar : bAr/ ; 234use-project bar : bAr\\ ; 235use-project bar : bAr\\\\ ; 236use-project bar : bAr\\\\///// ; 237use-project bar : bAr/. ; 238use-project bar : bAr/./././ ; 239use-project bar : bAr\\.\\.\\.\\ ; 240use-project bar : bAr\\./\\/.\\.\\ ; 241use-project bar : bAr/.\\././ ; 242use-project bar : Bar ; 243use-project bar : BaR ; 244use-project bar : BaR/./../bAr/xxx/.. ; 245use-project bar : BaR/./..\\bAr\\xxx/.. ; 246use-project bar : BaR/xxx/.. ; 247use-project bar : BaR///\\\\\\//xxx/.. ; 248use-project bar : Bar\\xxx/.. ; 249use-project bar : BAR/xXx/.. ; 250use-project bar : BAR/xXx\\\\/\\/\\//\\.. ; 251""") 252 t.run_build_system() 253 t.rm("baR") 254 255 t.cleanup() 256 257 258def test_unresolved_project_references(): 259 t = BoostBuild.Tester() 260 261 __write_appender(t, "appender.jam") 262 t.write("a/source._a", "") 263 t.write("a/jamfile.jam", "import alias ; alias target : source._a ;") 264 t.write("jamroot.jam", """\ 265import type ; 266type.register AAA : _a ; 267type.register BBB : _b ; 268 269import appender ; 270appender.register aaa-to-bbb : AAA : BBB ; 271 272use-project foo : a ; 273 274bbb b1 : a//target ; 275bbb b2 : /foo//target ; 276bbb b-invalid : invalid//target ; 277bbb b-root-invalid : /invalid//target ; 278bbb b-missing-root : foo//target ; 279bbb b-invalid-target : /foo//invalid ; 280""") 281 282 t.run_build_system(["b1", "b2"]) 283 t.expect_addition("bin/b%d._b" % x for x in range(1, 3)) 284 t.expect_nothing_more() 285 286 t.run_build_system(["b-invalid"], status=1) 287 t.expect_output_lines("""\ 288error: Unable to find file or target named 289error: 'invalid//target' 290error: referred to from project at 291error: '.' 292error: could not resolve project reference 'invalid'""") 293 294 t.run_build_system(["b-root-invalid"], status=1) 295 t.expect_output_lines("""\ 296error: Unable to find file or target named 297error: '/invalid//target' 298error: referred to from project at 299error: '.' 300error: could not resolve project reference '/invalid'""") 301 302 t.run_build_system(["b-missing-root"], status=1) 303 t.expect_output_lines("""\ 304error: Unable to find file or target named 305error: 'foo//target' 306error: referred to from project at 307error: '.' 308error: could not resolve project reference 'foo' - possibly missing a """ 309 "leading slash ('/') character.") 310 311 t.run_build_system(["b-invalid-target"], status=1) 312 t.expect_output_lines("""\ 313error: Unable to find file or target named 314error: '/foo//invalid' 315error: referred to from project at 316error: '.'""") 317 t.expect_output_lines("*could not resolve project reference*", False) 318 319 t.cleanup() 320 321 322def __write_appender(t, name): 323 t.write(name, 324r"""# Copyright 2012 Jurko Gospodnetic 325# Distributed under the Boost Software License, Version 1.0. 326# (See accompanying file LICENSE_1_0.txt or copy at 327# http://www.boost.org/LICENSE_1_0.txt) 328 329# Support for registering test generators that construct their targets by 330# simply appending their given input data, e.g. list of sources & targets. 331 332import "class" : new ; 333import generators ; 334import modules ; 335import sequence ; 336 337rule register ( id composing ? : source-types + : target-types + ) 338{ 339 local caller-module = [ CALLER_MODULE ] ; 340 id = $(caller-module).$(id) ; 341 local g = [ new generator $(id) $(composing) : $(source-types) : 342 $(target-types) ] ; 343 $(g).set-rule-name $(__name__).appender ; 344 generators.register $(g) ; 345 return $(id) ; 346} 347 348if [ modules.peek : NT ] 349{ 350 X = ")" ; 351 ECHO_CMD = (echo. ; 352} 353else 354{ 355 X = \" ; 356 ECHO_CMD = "echo $(X)" ; 357} 358 359local appender-runs ; 360 361# We set up separate actions for building each target in order to avoid having 362# to iterate over them in action (i.e. shell) code. We have to be extra careful 363# though to achieve the exact same effect as if doing all the work in just one 364# action. Otherwise Boost Jam might, under some circumstances, run only some of 365# our actions. To achieve this we register a series of actions for all the 366# targets (since they all have the same target list - either all or none of them 367# get run independent of which target actually needs to get built), each 368# building only a single target. Since all our actions use the same targets, we 369# can not use 'on-target' parameters to pass data to a specific action so we 370# pass them using the second 'sources' parameter which our actions then know how 371# to interpret correctly. This works well since Boost Jam does not automatically 372# add dependency relations between specified action targets & sources and so the 373# second argument, even though most often used to pass in a list of sources, can 374# actually be used for passing in any type of information. 375rule appender ( targets + : sources + : properties * ) 376{ 377 appender-runs = [ CALC $(appender-runs:E=0) + 1 ] ; 378 local target-index = 0 ; 379 local target-count = [ sequence.length $(targets) ] ; 380 local original-targets ; 381 for t in $(targets) 382 { 383 target-index = [ CALC $(target-index) + 1 ] ; 384 local appender-run = $(appender-runs) ; 385 if $(targets[2])-defined 386 { 387 appender-run += [$(target-index)/$(target-count)] ; 388 } 389 append $(targets) : $(appender-run:J=" ") $(t) $(sources) ; 390 } 391} 392 393actions append 394{ 395 $(ECHO_CMD)-------------------------------------------------$(X) 396 $(ECHO_CMD)Appender run: $(>[1])$(X) 397 $(ECHO_CMD)Appender run: $(>[1])$(X)>> "$(>[2])" 398 $(ECHO_CMD)Target group: $(<:J=' ')$(X) 399 $(ECHO_CMD)Target group: $(<:J=' ')$(X)>> "$(>[2])" 400 $(ECHO_CMD) Target: '$(>[2])'$(X) 401 $(ECHO_CMD) Target: '$(>[2])'$(X)>> "$(>[2])" 402 $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X) 403 $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X)>> "$(>[2])" 404 $(ECHO_CMD)=================================================$(X) 405 $(ECHO_CMD)-------------------------------------------------$(X)>> "$(>[2])" 406} 407""") 408 409 410test_assigning_project_ids() 411test_using_project_ids_in_target_references() 412test_repeated_ids_for_same_project() 413test_repeated_ids_for_different_projects() 414test_unresolved_project_references() 415