common.jam 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. # Copyright 2003, 2005 Dave Abrahams
  2. # Copyright 2005, 2006 Rene Rivera
  3. # Copyright 2005 Toon Knapen
  4. # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
  5. # Distributed under the Boost Software License, Version 1.0.
  6. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  7. # Provides actions common to all toolsets, such as creating directories and
  8. # removing files.
  9. import os ;
  10. import modules ;
  11. import utility ;
  12. import print ;
  13. import type ;
  14. import feature ;
  15. import errors ;
  16. import path ;
  17. import sequence ;
  18. import toolset ;
  19. import virtual-target ;
  20. import numbers ;
  21. if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
  22. {
  23. .debug-configuration = true ;
  24. }
  25. if [ MATCH (--show-configuration) : [ modules.peek : ARGV ] ]
  26. {
  27. .show-configuration = true ;
  28. }
  29. # Configurations
  30. #
  31. # The following class helps to manage toolset configurations. Each configuration
  32. # has a unique ID and one or more parameters. A typical example of a unique ID
  33. # is a condition generated by 'common.check-init-parameters' rule. Other kinds
  34. # of IDs can be used. Parameters may include any details about the configuration
  35. # like 'command', 'path', etc.
  36. #
  37. # A toolset configuration may be in one of the following states:
  38. #
  39. # - registered
  40. # Configuration has been registered (e.g. explicitly or by auto-detection
  41. # code) but has not yet been marked as used, i.e. 'toolset.using' rule has
  42. # not yet been called for it.
  43. # - used
  44. # Once called 'toolset.using' rule marks the configuration as 'used'.
  45. #
  46. # The main difference between the states above is that while a configuration is
  47. # 'registered' its options can be freely changed. This is useful in particular
  48. # for autodetection code - all detected configurations may be safely overwritten
  49. # by user code.
  50. class configurations
  51. {
  52. import errors ;
  53. rule __init__ ( )
  54. {
  55. }
  56. # Registers a configuration.
  57. #
  58. # Returns 'true' if the configuration has been added and an empty value if
  59. # it already exists. Reports an error if the configuration is 'used'.
  60. #
  61. rule register ( id )
  62. {
  63. if $(id) in $(self.used)
  64. {
  65. errors.error "common: the configuration '$(id)' is in use" ;
  66. }
  67. local retval ;
  68. if ! $(id) in $(self.all)
  69. {
  70. self.all += $(id) ;
  71. # Indicate that a new configuration has been added.
  72. retval = true ;
  73. }
  74. return $(retval) ;
  75. }
  76. # Mark a configuration as 'used'.
  77. #
  78. # Returns 'true' if the state of the configuration has been changed to
  79. # 'used' and an empty value if it the state has not been changed. Reports an
  80. # error if the configuration is not known.
  81. #
  82. rule use ( id )
  83. {
  84. if ! $(id) in $(self.all)
  85. {
  86. errors.error "common: the configuration '$(id)' is not known" ;
  87. }
  88. local retval ;
  89. if ! $(id) in $(self.used)
  90. {
  91. self.used += $(id) ;
  92. # Indicate that the configuration has been marked as 'used'.
  93. retval = true ;
  94. }
  95. return $(retval) ;
  96. }
  97. # Return all registered configurations.
  98. #
  99. rule all ( )
  100. {
  101. return $(self.all) ;
  102. }
  103. # Return all used configurations.
  104. #
  105. rule used ( )
  106. {
  107. return $(self.used) ;
  108. }
  109. # Returns the value of a configuration parameter.
  110. #
  111. rule get ( id : param )
  112. {
  113. return $(self.$(param).$(id)) ;
  114. }
  115. # Sets the value of a configuration parameter.
  116. #
  117. rule set ( id : param : value * )
  118. {
  119. self.$(param).$(id) = $(value) ;
  120. }
  121. }
  122. # The rule for checking toolset parameters. Trailing parameters should all be
  123. # parameter name/value pairs. The rule will check that each parameter either has
  124. # a value in each invocation or has no value in each invocation. Also, the rule
  125. # will check that the combination of all parameter values is unique in all
  126. # invocations.
  127. #
  128. # Each parameter name corresponds to a subfeature. This rule will declare a
  129. # subfeature the first time a non-empty parameter value is passed and will
  130. # extend it with all the values.
  131. #
  132. # The return value from this rule is a condition to be used for flags settings.
  133. #
  134. rule check-init-parameters ( toolset requirement * : * )
  135. {
  136. local sig = $(toolset) ;
  137. local condition = <toolset>$(toolset) ;
  138. local subcondition ;
  139. for local index in 2 3 4 5 6 7 8 9
  140. {
  141. local name = $($(index)[1]) ;
  142. local value = $($(index)[2]) ;
  143. if $(value)-is-not-empty
  144. {
  145. condition = $(condition)-$(value) ;
  146. if $(.had-unspecified-value.$(toolset).$(name))
  147. {
  148. errors.user-error
  149. "$(toolset) initialization: parameter '$(name)'"
  150. "inconsistent" : "no value was specified in earlier"
  151. "initialization" : "an explicit value is specified now" ;
  152. }
  153. # The below logic is for intel compiler. It calls this rule with
  154. # 'intel-linux' and 'intel-win' as toolset, so we need to get the
  155. # base part of toolset name. We can not pass 'intel' as toolset
  156. # because in that case it will be impossible to register versionless
  157. # intel-linux and intel-win toolsets of a specific version.
  158. local t = $(toolset) ;
  159. local m = [ MATCH "([^-]*)-" : $(toolset) ] ;
  160. if $(m)
  161. {
  162. t = $(m[1]) ;
  163. }
  164. if ! $(.had-value.$(toolset).$(name))
  165. {
  166. if ! $(.declared-subfeature.$(t).$(name))
  167. {
  168. feature.subfeature toolset $(t) : $(name) : : propagated ;
  169. .declared-subfeature.$(t).$(name) = true ;
  170. }
  171. .had-value.$(toolset).$(name) = true ;
  172. }
  173. feature.extend-subfeature toolset $(t) : $(name) : $(value) ;
  174. subcondition += <toolset-$(t):$(name)>$(value) ;
  175. }
  176. else
  177. {
  178. if $(.had-value.$(toolset).$(name))
  179. {
  180. errors.user-error
  181. "$(toolset) initialization: parameter '$(name)'"
  182. "inconsistent" : "an explicit value was specified in an"
  183. "earlier initialization" : "no value is specified now" ;
  184. }
  185. .had-unspecified-value.$(toolset).$(name) = true ;
  186. }
  187. sig = $(sig)$(value:E="")- ;
  188. }
  189. # We also need to consider requirements on the toolset as we can
  190. # configure the same toolset multiple times with different options that
  191. # are selected with the requirements.
  192. if $(requirement)
  193. {
  194. sig = $(sig)$(requirement:J=,) ;
  195. }
  196. if $(sig) in $(.all-signatures)
  197. {
  198. local message =
  199. "duplicate initialization of $(toolset) with the following parameters: " ;
  200. for local index in 2 3 4 5 6 7 8 9
  201. {
  202. local p = $($(index)) ;
  203. if $(p)
  204. {
  205. message += "$(p[1]) = $(p[2]:E=<unspecified>)" ;
  206. }
  207. }
  208. message += "previous initialization at $(.init-loc.$(sig))" ;
  209. errors.user-error
  210. $(message[1]) : $(message[2]) : $(message[3]) : $(message[4]) :
  211. $(message[5]) : $(message[6]) : $(message[7]) : $(message[8]) ;
  212. }
  213. .all-signatures += $(sig) ;
  214. .init-loc.$(sig) = [ errors.nearest-user-location ] ;
  215. # If we have a requirement, this version should only be applied under that
  216. # condition. To accomplish this we add a toolset requirement that imposes
  217. # the toolset subcondition, which encodes the version.
  218. if $(requirement)
  219. {
  220. local r = <toolset>$(toolset) $(requirement) ;
  221. r = $(r:J=,) ;
  222. toolset.add-requirements "$(r):$(subcondition)" ;
  223. }
  224. # We add the requirements, if any, to the condition to scope the toolset
  225. # variables and options to this specific version.
  226. condition += $(requirement) ;
  227. if $(.show-configuration)
  228. {
  229. ECHO "notice:" $(condition) ;
  230. }
  231. return $(condition:J=/) ;
  232. }
  233. # A helper rule to get the command to invoke some tool. If
  234. # 'user-provided-command' is not given, tries to find binary named 'tool' in
  235. # PATH and in the passed 'additional-path'. Otherwise, verifies that the first
  236. # element of 'user-provided-command' is an existing program.
  237. #
  238. # This rule returns the command to be used when invoking the tool. If we can not
  239. # find the tool, a warning is issued. If 'path-last' is specified, PATH is
  240. # checked after 'additional-paths' when searching for 'tool'.
  241. #
  242. rule get-invocation-command-nodefault ( toolset : tool :
  243. user-provided-command * : additional-paths * : path-last ? )
  244. {
  245. local command ;
  246. if ! $(user-provided-command)
  247. {
  248. command = [ find-tool $(tool) : $(additional-paths) : $(path-last) ] ;
  249. if ! $(command) && $(.debug-configuration)
  250. {
  251. ECHO "warning:" toolset $(toolset) "initialization:" can not find tool
  252. $(tool) ;
  253. ECHO "warning:" initialized from [ errors.nearest-user-location ] ;
  254. }
  255. }
  256. else
  257. {
  258. command = [ check-tool $(user-provided-command) ] ;
  259. if ! $(command) && $(.debug-configuration)
  260. {
  261. ECHO "warning:" toolset $(toolset) "initialization:" ;
  262. ECHO "warning:" can not find user-provided command
  263. '$(user-provided-command)' ;
  264. ECHO "warning:" initialized from [ errors.nearest-user-location ] ;
  265. }
  266. }
  267. return $(command) ;
  268. }
  269. # Same as get-invocation-command-nodefault, except that if no tool is found,
  270. # returns either the user-provided-command, if present, or the 'tool' parameter.
  271. #
  272. rule get-invocation-command ( toolset : tool : user-provided-command * :
  273. additional-paths * : path-last ? )
  274. {
  275. local result = [ get-invocation-command-nodefault $(toolset) : $(tool) :
  276. $(user-provided-command) : $(additional-paths) : $(path-last) ] ;
  277. if ! $(result)
  278. {
  279. if $(user-provided-command)
  280. {
  281. result = $(user-provided-command) ;
  282. }
  283. else
  284. {
  285. result = $(tool) ;
  286. }
  287. }
  288. return $(result) ;
  289. }
  290. # Given an invocation command return the absolute path to the command. This
  291. # works even if command has no path element and was found on the PATH.
  292. #
  293. rule get-absolute-tool-path ( command )
  294. {
  295. if $(command:D)
  296. {
  297. return $(command:D) ;
  298. }
  299. else
  300. {
  301. local m = [ GLOB [ modules.peek : PATH Path path ] : $(command)
  302. $(command).exe ] ;
  303. return $(m[1]:D) ;
  304. }
  305. }
  306. # Attempts to find tool (binary) named 'name' in PATH and in 'additional-paths'.
  307. # If found in PATH, returns 'name' and if found in additional paths, returns
  308. # absolute name. If the tool is found in several directories, returns the first
  309. # path found. Otherwise, returns an empty string. If 'path-last' is specified,
  310. # PATH is searched after 'additional-paths'.
  311. #
  312. rule find-tool ( name : additional-paths * : path-last ? )
  313. {
  314. if $(name:D)
  315. {
  316. return [ check-tool-aux $(name) ] ;
  317. }
  318. local path = [ path.programs-path ] ;
  319. local match = [ path.glob $(path) : $(name) $(name).exe ] ;
  320. local additional-match = [ path.glob $(additional-paths) : $(name)
  321. $(name).exe ] ;
  322. local result ;
  323. if $(path-last)
  324. {
  325. result = $(additional-match) ;
  326. if ! $(result) && $(match)
  327. {
  328. result = $(name) ;
  329. }
  330. }
  331. else
  332. {
  333. if $(match)
  334. {
  335. result = $(name) ;
  336. }
  337. else
  338. {
  339. result = $(additional-match) ;
  340. }
  341. }
  342. if $(result)
  343. {
  344. return [ path.native $(result[1]) ] ;
  345. }
  346. }
  347. # Checks if 'command' can be found either in path or is a full name to an
  348. # existing file.
  349. #
  350. local rule check-tool-aux ( command )
  351. {
  352. if $(command:D)
  353. {
  354. if [ path.exists $(command) ]
  355. # Both NT and Cygwin will run .exe files by their unqualified names.
  356. || ( [ os.on-windows ] && [ path.exists $(command).exe ] )
  357. # Only NT will run .bat & .cmd files by their unqualified names.
  358. || ( ( [ os.name ] = NT ) && ( [ path.exists $(command).bat ] ||
  359. [ path.exists $(command).cmd ] ) )
  360. {
  361. return $(command) ;
  362. }
  363. }
  364. else
  365. {
  366. if [ GLOB [ modules.peek : PATH Path path ] : $(command) ]
  367. {
  368. return $(command) ;
  369. }
  370. }
  371. }
  372. # Checks that a tool can be invoked by 'command'. If command is not an absolute
  373. # path, checks if it can be found in 'path'. If command is an absolute path,
  374. # check that it exists. Returns 'command' if ok or empty string otherwise.
  375. #
  376. local rule check-tool ( xcommand + )
  377. {
  378. if [ check-tool-aux $(xcommand[1]) ] ||
  379. [ check-tool-aux $(xcommand[-1]) ]
  380. {
  381. return $(xcommand) ;
  382. }
  383. }
  384. # Handle common options for toolset, specifically sets the following flag
  385. # variables:
  386. # - CONFIG_COMMAND to $(command)
  387. # - OPTIONS for compile to the value of <compileflags> in $(options)
  388. # - OPTIONS for compile.c to the value of <cflags> in $(options)
  389. # - OPTIONS for compile.c++ to the value of <cxxflags> in $(options)
  390. # - OPTIONS for compile.asm to the value of <asmflags> in $(options)
  391. # - OPTIONS for compile.fortran to the value of <fflags> in $(options)
  392. # - OPTIONS for link to the value of <linkflags> in $(options)
  393. #
  394. rule handle-options ( toolset : condition * : command * : options * )
  395. {
  396. if $(.debug-configuration)
  397. {
  398. ECHO "notice:" will use '$(command)' for $(toolset), condition
  399. $(condition:E=(empty)) ;
  400. }
  401. # The last parameter ('unchecked') says it is OK to set flags for another
  402. # module.
  403. toolset.flags $(toolset) CONFIG_COMMAND $(condition) : $(command)
  404. : unchecked ;
  405. toolset.flags $(toolset).compile OPTIONS $(condition) :
  406. [ feature.get-values <compileflags> : $(options) ] : unchecked ;
  407. toolset.flags $(toolset).compile.c OPTIONS $(condition) :
  408. [ feature.get-values <cflags> : $(options) ] : unchecked ;
  409. toolset.flags $(toolset).compile.c++ OPTIONS $(condition) :
  410. [ feature.get-values <cxxflags> : $(options) ] : unchecked ;
  411. toolset.flags $(toolset).compile.asm OPTIONS $(condition) :
  412. [ feature.get-values <asmflags> : $(options) ] : unchecked ;
  413. toolset.flags $(toolset).compile.fortran OPTIONS $(condition) :
  414. [ feature.get-values <fflags> : $(options) ] : unchecked ;
  415. toolset.flags $(toolset).link OPTIONS $(condition) :
  416. [ feature.get-values <linkflags> : $(options) ] : unchecked ;
  417. }
  418. # Returns the location of the "program files" directory on a Windows platform.
  419. #
  420. rule get-program-files-dir ( )
  421. {
  422. local ProgramFiles = [ modules.peek : ProgramFiles ] ;
  423. if $(ProgramFiles)
  424. {
  425. ProgramFiles = "$(ProgramFiles:J= )" ;
  426. }
  427. else
  428. {
  429. ProgramFiles = "c:\\Program Files" ;
  430. }
  431. return $(ProgramFiles) ;
  432. }
  433. if [ os.name ] = NT
  434. {
  435. NULL_DEVICE = "NUL" ;
  436. IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE) & setlocal" ;
  437. RM = del /f /q ;
  438. CP = copy /b ;
  439. LN ?= $(CP) ;
  440. # Ugly hack to convince copy to set the timestamp of the destination to the
  441. # current time by concatenating the source with a nonexistent file. Note
  442. # that this requires /b (binary) as the default when concatenating files is
  443. # /a (ascii).
  444. WINDOWS-CP-HACK = "+ this-file-does-not-exist-A698EE7806899E69" ;
  445. }
  446. else if [ os.name ] = VMS
  447. {
  448. NULL_DEVICE = "NL:" ;
  449. PIPE = PIPE ;
  450. IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE)" ;
  451. RM = DELETE /NOCONF ;
  452. CP = COPY /OVERWRITE ;
  453. LN = $(CP) ;
  454. }
  455. else
  456. {
  457. NULL_DEVICE = "/dev/null" ;
  458. IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE)" ;
  459. RM = rm -f ;
  460. CP = cp ;
  461. LN = ln ;
  462. }
  463. NULL_OUT = ">$(NULL_DEVICE)" ;
  464. rule null-device ( )
  465. {
  466. return $(NULL_DEVICE) ;
  467. }
  468. rule rm-command ( )
  469. {
  470. return $(RM) ;
  471. }
  472. rule copy-command ( )
  473. {
  474. return $(CP) ;
  475. }
  476. if "\n" = "n"
  477. {
  478. # Escape characters not supported so use ugly hacks. Will not work on Cygwin
  479. # - see below.
  480. nl = "
  481. " ;
  482. q = "" ;
  483. }
  484. else
  485. {
  486. nl = "\n" ;
  487. q = "\"" ;
  488. }
  489. rule newline-char ( )
  490. {
  491. return $(nl) ;
  492. }
  493. # Returns the command needed to set an environment variable on the current
  494. # platform. The variable setting persists through all following commands and is
  495. # visible in the environment seen by subsequently executed commands. In other
  496. # words, on Unix systems, the variable is exported, which is consistent with the
  497. # only possible behavior on Windows systems.
  498. #
  499. rule variable-setting-command ( variable : value )
  500. {
  501. if [ os.name ] = NT
  502. {
  503. return "set $(variable)=$(value)$(nl)" ;
  504. }
  505. else if [ os.name ] = VMS
  506. {
  507. return "$(variable) == $(q)$(value)$(q)$(nl)" ;
  508. }
  509. else
  510. {
  511. # If we do not have escape character support in bjam, the cod below
  512. # blows up on CYGWIN, since the $(nl) variable holds a Windows new-line
  513. # \r\n sequence that messes up the executed export command which then
  514. # reports that the passed variable name is incorrect.
  515. # But we have a check for cygwin in kernel/bootstrap.jam already.
  516. return "$(variable)=$(q)$(value)$(q)$(nl)export $(variable)$(nl)" ;
  517. }
  518. }
  519. # Returns a command to sets a named shell path variable to the given NATIVE
  520. # paths on the current platform.
  521. #
  522. rule path-variable-setting-command ( variable : paths * )
  523. {
  524. local sep = [ os.path-separator ] ;
  525. return [ variable-setting-command $(variable) : $(paths:J=$(sep)) ] ;
  526. }
  527. # Returns a command that prepends the given paths to the named path variable on
  528. # the current platform.
  529. #
  530. rule prepend-path-variable-command ( variable : paths * )
  531. {
  532. return [ path-variable-setting-command $(variable)
  533. : $(paths) [ os.expand-variable $(variable) ] ] ;
  534. }
  535. # Return a command which can create a file. If 'r' is result of invocation, then
  536. # 'r foobar' will create foobar with unspecified content. What happens if file
  537. # already exists is unspecified.
  538. #
  539. rule file-creation-command ( )
  540. {
  541. if [ os.name ] = NT
  542. {
  543. # A few alternative implementations on Windows:
  544. #
  545. # 'type NUL >> '
  546. # That would construct an empty file instead of a file containing
  547. # a space and an end-of-line marker but it would also not change
  548. # the target's timestamp in case the file already exists.
  549. #
  550. # 'type NUL > '
  551. # That would construct an empty file instead of a file containing
  552. # a space and an end-of-line marker but it would also destroy an
  553. # already existing file by overwriting it with an empty one.
  554. #
  555. # I guess the best solution would be to allow Boost Jam to define
  556. # built-in functions such as 'create a file', 'touch a file' or 'copy a
  557. # file' which could be used from inside action code. That would allow
  558. # completely portable operations without this kind of kludge.
  559. # (22.02.2009.) (Jurko)
  560. return "echo. > " ;
  561. }
  562. else if [ os.name ] = VMS
  563. {
  564. return "APPEND /NEW NL: " ;
  565. }
  566. else
  567. {
  568. return "touch " ;
  569. }
  570. }
  571. # Returns a command that may be used for 'touching' files. It is not a real
  572. # 'touch' command on NT because it adds an empty line at the end of file but it
  573. # works with source files.
  574. #
  575. rule file-touch-command ( )
  576. {
  577. if [ os.name ] = NT
  578. {
  579. return "echo. >> " ;
  580. }
  581. else if [ os.name ] = VMS
  582. {
  583. return "APPEND /NEW NL: " ;
  584. }
  585. else
  586. {
  587. return "touch " ;
  588. }
  589. }
  590. rule MkDir
  591. {
  592. # If dir exists, do not update it. Do this even for $(DOT).
  593. NOUPDATE $(<) ;
  594. if $(<) != $(DOT) && ! $($(<)-mkdir)
  595. {
  596. # Cheesy gate to prevent multiple invocations on same dir.
  597. $(<)-mkdir = true ;
  598. # Schedule the mkdir build action.
  599. common.mkdir $(<) ;
  600. # Prepare a Jam 'dirs' target that can be used to make the build only
  601. # construct all the target directories.
  602. DEPENDS dirs : $(<) ;
  603. # Recursively create parent directories. $(<:P) = $(<)'s parent & we
  604. # recurse until root.
  605. local s = $(<:P) ;
  606. if [ os.name ] = NT
  607. {
  608. switch $(s)
  609. {
  610. case "*:" : s = ;
  611. case "*:\\" : s = ;
  612. }
  613. }
  614. if $(s)
  615. {
  616. if $(s) != $(<)
  617. {
  618. DEPENDS $(<) : $(s) ;
  619. MkDir $(s) ;
  620. }
  621. else
  622. {
  623. NOTFILE $(s) ;
  624. }
  625. }
  626. }
  627. }
  628. #actions MkDir1
  629. #{
  630. # mkdir "$(<)"
  631. #}
  632. # The following quick-fix actions should be replaced using the original MkDir1
  633. # action once Boost Jam gets updated to correctly detect different paths leading
  634. # up to the same filesystem target and triggers their build action only once.
  635. # (todo) (04.07.2008.) (Jurko)
  636. if [ os.name ] = NT
  637. {
  638. actions quietly mkdir
  639. {
  640. if not exist "$(<)\\" mkdir "$(<)"
  641. }
  642. }
  643. else
  644. {
  645. actions quietly mkdir
  646. {
  647. mkdir -p "$(<)"
  648. }
  649. }
  650. actions piecemeal together existing Clean
  651. {
  652. $(RM) "$(>)"
  653. }
  654. rule copy
  655. {
  656. }
  657. actions copy
  658. {
  659. $(CP) "$(>)" $(WINDOWS-CP-HACK) "$(<)"
  660. }
  661. rule RmTemps
  662. {
  663. }
  664. actions quietly updated piecemeal together RmTemps
  665. {
  666. $(RM) "$(>)" $(IGNORE)
  667. }
  668. actions hard-link
  669. {
  670. $(RM) "$(<)" 2$(NULL_OUT) $(NULL_OUT)
  671. $(LN) "$(>)" "$(<)" $(NULL_OUT)
  672. }
  673. if [ os.name ] = VMS
  674. {
  675. actions mkdir
  676. {
  677. IF F$PARSE("$(<:W)") .EQS. "" THEN CREATE /DIR $(<:W)
  678. }
  679. actions piecemeal together existing Clean
  680. {
  681. $(RM) $(>:WJ=;*,);*
  682. }
  683. actions copy
  684. {
  685. $(CP) $(>:WJ=,) $(<:W)
  686. }
  687. actions quietly updated piecemeal together RmTemps
  688. {
  689. $(PIPE) $(RM) $(>:WJ=;*,);* $(IGNORE)
  690. }
  691. actions hard-link
  692. {
  693. $(PIPE) $(RM) $(>[1]:W);* $(IGNORE)
  694. $(PIPE) $(LN) $(>[1]:W) $(<:W) $(NULL_OUT)
  695. }
  696. }
  697. # Given a target, as given to a custom tag rule, returns a string formatted
  698. # according to the passed format. Format is a list of properties that is
  699. # represented in the result. For each element of format the corresponding target
  700. # information is obtained and added to the result string. For all, but the
  701. # literal, the format value is taken as the as string to prepend to the output
  702. # to join the item to the rest of the result. If not given "-" is used as a
  703. # joiner.
  704. #
  705. # The format options can be:
  706. #
  707. # <base>[joiner]
  708. # :: The basename of the target name.
  709. # <toolset>[joiner]
  710. # :: The abbreviated toolset tag being used to build the target.
  711. # <threading>[joiner]
  712. # :: Indication of a multi-threaded build.
  713. # <runtime>[joiner]
  714. # :: Collective tag of the build runtime.
  715. # <version:/version-feature | X.Y[.Z]/>[joiner]
  716. # :: Short version tag taken from the given "version-feature" in the
  717. # build properties. Or if not present, the literal value as the
  718. # version number.
  719. # <property:/property-name/>[joiner]
  720. # :: Direct lookup of the given property-name value in the build
  721. # properties. /property-name/ is a regular expression. E.g.
  722. # <property:toolset-.*:flavor> will match every toolset.
  723. # /otherwise/
  724. # :: The literal value of the format argument.
  725. #
  726. # For example this format:
  727. #
  728. # boost_ <base> <toolset> <threading> <runtime> <version:boost-version>
  729. #
  730. # Might return:
  731. #
  732. # boost_thread-vc80-mt-gd-1_33.dll, or
  733. # boost_regex-vc80-gd-1_33.dll
  734. #
  735. # The returned name also has the target type specific prefix and suffix which
  736. # puts it in a ready form to use as the value from a custom tag rule.
  737. #
  738. rule format-name ( format * : name : type ? : property-set )
  739. {
  740. local result = "" ;
  741. for local f in $(format)
  742. {
  743. switch $(f:G)
  744. {
  745. case <base> :
  746. result += $(name:B) ;
  747. case <toolset> :
  748. result += [ join-tag $(f:G=) : [ toolset-tag $(name) : $(type) :
  749. $(property-set) ] ] ;
  750. case <threading> :
  751. result += [ join-tag $(f:G=) : [ threading-tag $(name) : $(type)
  752. : $(property-set) ] ] ;
  753. case <runtime> :
  754. result += [ join-tag $(f:G=) : [ runtime-tag $(name) : $(type) :
  755. $(property-set) ] ] ;
  756. case <qt> :
  757. result += [ join-tag $(f:G=) : [ qt-tag $(name) : $(type) :
  758. $(property-set) ] ] ;
  759. case <address-model> :
  760. result += [ join-tag $(f:G=) : [ address-model-tag $(name) :
  761. $(type) : $(property-set) ] ] ;
  762. case <arch-and-model> :
  763. result += [ join-tag $(f:G=) : [ arch-and-model-tag $(name) :
  764. $(type) : $(property-set) ] ] ;
  765. case <version:*> :
  766. local key = [ MATCH <version:(.*)> : $(f:G) ] ;
  767. local version = [ $(property-set).get <$(key)> ] ;
  768. version ?= $(key) ;
  769. version = [ MATCH "^([^.]+)[.]([^.]+)[.]?([^.]*)" : $(version) ] ;
  770. result += [ join-tag $(f:G=) : $(version[1])_$(version[2]) ] ;
  771. case <property:*> :
  772. local key = [ MATCH <property:(.*)> : $(f:G) ] ;
  773. local p0 = [ MATCH <($(key))> : [ $(property-set).raw ] ] ;
  774. if $(p0)
  775. {
  776. local p = [ $(property-set).get <$(p0)> ] ;
  777. if $(p)
  778. {
  779. result += [ join-tag $(f:G=) : $(p) ] ;
  780. }
  781. }
  782. case * :
  783. result += $(f:G=) ;
  784. }
  785. }
  786. return [ virtual-target.add-prefix-and-suffix $(result:J=) : $(type) :
  787. $(property-set) ] ;
  788. }
  789. local rule join-tag ( joiner ? : tag ? )
  790. {
  791. if ! $(joiner) { joiner = - ; }
  792. return $(joiner)$(tag) ;
  793. }
  794. local rule toolset-tag ( name : type ? : property-set )
  795. {
  796. local tag = ;
  797. local properties = [ $(property-set).raw ] ;
  798. switch [ $(property-set).get <toolset> ]
  799. {
  800. case borland* : tag += bcb ;
  801. case clang* :
  802. {
  803. switch [ $(property-set).get <toolset-clang:platform> ]
  804. {
  805. case darwin : tag += clang-darwin ;
  806. case linux : tag += clang ;
  807. case win : tag += clangw ;
  808. }
  809. }
  810. case como* : tag += como ;
  811. case cw : tag += cw ;
  812. case darwin* : tag += xgcc ;
  813. case edg* : tag += edg ;
  814. case gcc* :
  815. {
  816. switch [ $(property-set).get <target-os> ]
  817. {
  818. case *windows* : tag += mgw ;
  819. case * : tag += gcc ;
  820. }
  821. }
  822. case intel :
  823. if [ $(property-set).get <toolset-intel:platform> ] = win
  824. {
  825. tag += iw ;
  826. }
  827. else
  828. {
  829. tag += il ;
  830. }
  831. case kcc* : tag += kcc ;
  832. case kylix* : tag += bck ;
  833. #case metrowerks* : tag += cw ;
  834. #case mingw* : tag += mgw ;
  835. case mipspro* : tag += mp ;
  836. case msvc* : tag += vc ;
  837. case qcc* : tag += qcc ;
  838. case sun* : tag += sw ;
  839. case tru64cxx* : tag += tru ;
  840. case vacpp* : tag += xlc ;
  841. }
  842. local version = [ MATCH "<toolset.*version>([0123456789]+)[.]?([0123456789]*)"
  843. : $(properties) ] ;
  844. # For historical reasons, vc6.0 and vc7.0 use different naming.
  845. if $(tag) = vc
  846. {
  847. if $(version[1]) = 6
  848. {
  849. # Cancel minor version.
  850. version = 6 ;
  851. }
  852. else if $(version[1]) = 7 && $(version[2]) = 0
  853. {
  854. version = 7 ;
  855. }
  856. }
  857. # From GCC 5, versioning changes and minor becomes patch
  858. if ( $(tag) = gcc || $(tag) = mgw ) && [ numbers.less 4 $(version[1]) ]
  859. {
  860. version = $(version[1]) ;
  861. }
  862. # Ditto, from Clang 4
  863. if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ]
  864. {
  865. version = $(version[1]) ;
  866. }
  867. # On intel, version is not added, because it does not matter and it is the
  868. # version of vc used as backend that matters. Ideally, we should encode the
  869. # backend version but that would break compatibility with V1.
  870. if $(tag) = iw
  871. {
  872. version = ;
  873. }
  874. # On borland, version is not added for compatibility with V1.
  875. if $(tag) = bcb
  876. {
  877. version = ;
  878. }
  879. tag += $(version) ;
  880. return $(tag:J=) ;
  881. }
  882. local rule threading-tag ( name : type ? : property-set )
  883. {
  884. if <threading>multi in [ $(property-set).raw ]
  885. {
  886. return mt ;
  887. }
  888. }
  889. local rule runtime-tag ( name : type ? : property-set )
  890. {
  891. local tag = ;
  892. local properties = [ $(property-set).raw ] ;
  893. if <runtime-link>static in $(properties) { tag += s ; }
  894. # This is an ugly thing. In V1, there is code to automatically detect which
  895. # properties affect a target. So, if <runtime-debugging> does not affect gcc
  896. # toolset, the tag rules will not even see <runtime-debugging>. Similar
  897. # functionality in V2 is not implemented yet, so we just check for toolsets
  898. # known to care about runtime debugging.
  899. if ( <toolset>msvc in $(properties) ) ||
  900. ( <stdlib>stlport in $(properties) ) ||
  901. ( <toolset-intel:platform>win in $(properties) )
  902. {
  903. if <runtime-debugging>on in $(properties) { tag += g ; }
  904. }
  905. if <python-debugging>on in $(properties) { tag += y ; }
  906. if <variant>debug in $(properties) { tag += d ; }
  907. if <stdlib>stlport in $(properties) { tag += p ; }
  908. if <stdlib-stlport:iostream>hostios in $(properties) { tag += n ; }
  909. return $(tag:J=) ;
  910. }
  911. # Create a tag for the Qt library version
  912. # "<qt>4.6.0" will result in tag "qt460"
  913. local rule qt-tag ( name : type ? : property-set )
  914. {
  915. local v = [ MATCH "([0123456789]+)[.]?([0123456789]*)[.]?([0123456789]*)" :
  916. [ $(property-set).get <qt> ] ] ;
  917. return qt$(v:J=) ;
  918. }
  919. # Create a tag for the address-model
  920. # <address-model>64 will simply generate "64"
  921. local rule address-model-tag ( name : type ? : property-set )
  922. {
  923. return [ $(property-set).get <address-model> ] ;
  924. }
  925. # Create a tag for the architecture and model
  926. # <architecture>x86 <address-model>32 would generate "x32"
  927. # This relies on the fact that all architectures start with
  928. # unique letters.
  929. local rule arch-and-model-tag ( name : type ? : property-set )
  930. {
  931. local architecture = [ $(property-set).get <architecture> ] ;
  932. local address-model = [ $(property-set).get <address-model> ] ;
  933. local arch = [ MATCH ^(.) : $(architecture) ] ;
  934. return $(arch)$(address-model) ;
  935. }
  936. rule __test__ ( )
  937. {
  938. import assert ;
  939. local save-os = [ modules.peek os : .name ] ;
  940. modules.poke os : .name : LINUX ;
  941. assert.result "PATH=\"foo:bar:baz\"\nexport PATH\n"
  942. : path-variable-setting-command PATH : foo bar baz ;
  943. assert.result "PATH=\"foo:bar:$PATH\"\nexport PATH\n"
  944. : prepend-path-variable-command PATH : foo bar ;
  945. modules.poke os : .name : NT ;
  946. assert.result "set PATH=foo;bar;baz\n"
  947. : path-variable-setting-command PATH : foo bar baz ;
  948. assert.result "set PATH=foo;bar;%PATH%\n"
  949. : prepend-path-variable-command PATH : foo bar ;
  950. modules.poke os : .name : $(save-os) ;
  951. }