jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
14KB

  1. #
  2. # Copyright (C) 2017 Karl Linden
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions are
  6. # met:
  7. #
  8. # 1. Redistributions of source code must retain the above copyright
  9. # notice, this list of conditions and the following disclaimer.
  10. #
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. # notice, this list of conditions and the following disclaimer in the
  13. # documentation and/or other materials provided with the
  14. # distribution.
  15. #
  16. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  17. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  19. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  20. # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  21. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  22. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  26. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. #
  28. import optparse
  29. import sys
  30. from waflib import Configure, Logs, Options, Utils
  31. # A list of AutoOptions. It is local to each module, so all modules that
  32. # use AutoOptions need to run both opt.load and conf.load. In contrast
  33. # to the define and style options this does not need to and cannot be
  34. # declared in the OptionsContext, because it is needed both for the
  35. # options and the configure phase.
  36. auto_options = []
  37. class AutoOption:
  38. """
  39. This class represents an auto option that can be used in conjunction
  40. with the waf build system. By default it adds options --foo and
  41. --no-foo respectively to turn on or off foo respectively.
  42. Furthermore it incorporats logic and checks that are required for
  43. these features.
  44. An option can have an arbitrary number of dependencies that must be
  45. present for the option to be enabled. An option can be enabled or
  46. disabled by default. Here is how the logic works:
  47. 1. If the option is explicitly disabled, through --no-foo, then no
  48. checks are made and the option is disabled.
  49. 2. If the option is explicitly enabled, through --foo, then check
  50. for all required dependencies, and if some of them are not
  51. found, then print a fatal error telling the user there were
  52. dependencies missing.
  53. 3. Otherwise, if the option is enabled by default, then check for
  54. all dependencies. If all dependencies are found the option is
  55. enabled. Otherwise it is disabled.
  56. 4. Lastly, if no option was given and the option is disabled by
  57. default, then no checks are performed and the option is
  58. disabled.
  59. To add a dependency to an option use the check, check_cfg and
  60. find_program methods of this class. The methods are merely small
  61. wrappers around their configuration context counterparts and behave
  62. identically. Note that adding dependencies is done in the options
  63. phase and not in the configure phase, although the checks are
  64. actually executed during the configure phase.
  65. Custom check functions can be added using the add_function method.
  66. As with the other checks the check function will be invoked during
  67. the configuration. Refer to the documentation of the add_function
  68. method for details.
  69. When all checks have been made and the class has made a decision the
  70. result is saved in conf.env['NAME'] where 'NAME' by default is the
  71. uppercase of the name argument to __init__, with hyphens replaced by
  72. underscores. This default can be changed with the conf_dest argument
  73. to __init__.
  74. The class will define a preprocessor symbol with the result. The
  75. default name is WITH_NAME, to not collide with the standard define
  76. of check_cfg, but it can be changed using the define argument to
  77. __init__. It can also be changed globally using
  78. set_auto_options_define.
  79. """
  80. def __init__(self, opt, name, help=None, default=True,
  81. conf_dest=None, define=None, style=None):
  82. """
  83. Class initializing method.
  84. Arguments:
  85. opt OptionsContext
  86. name name of the option, e.g. alsa
  87. help help text that will be displayed in --help output
  88. conf_dest conf.env variable to define to the result
  89. define the preprocessor symbol to define with the result
  90. style the option style to use; see below for options
  91. """
  92. # The dependencies to check for. The elements are on the form
  93. # (func, k, kw) where func is the function or function name that
  94. # is used for the check and k and kw are the arguments and
  95. # options to give the function.
  96. self.deps = []
  97. # Whether or not the option should be enabled. None indicates
  98. # that the checks have not been performed yet.
  99. self.enable = None
  100. self.help = help
  101. if help:
  102. if default:
  103. help_comment = ' (enabled by default if possible)'
  104. else:
  105. help_comment = ' (disabled by default)'
  106. option_help = help + help_comment
  107. no_option_help = None
  108. else:
  109. option_help = no_option_help = optparse.SUPPRESS_HELP
  110. self.dest = 'auto_option_' + name
  111. self.default = default
  112. safe_name = Utils.quote_define_name(name)
  113. self.conf_dest = conf_dest or safe_name
  114. default_define = opt.get_auto_options_define()
  115. self.define = define or default_define % safe_name
  116. if not style:
  117. style = opt.get_auto_options_style()
  118. self.style = style
  119. # plain (default):
  120. # --foo | --no-foo
  121. # yesno:
  122. # --foo=yes | --foo=no
  123. # yesno_and_hack:
  124. # --foo[=yes] | --foo=no or --no-foo
  125. # enable:
  126. # --enable-foo | --disble-foo
  127. # with:
  128. # --with-foo | --without-foo
  129. if style in ['plain', 'yesno', 'yesno_and_hack']:
  130. self.no_option = '--no-' + name
  131. self.yes_option = '--' + name
  132. elif style == 'enable':
  133. self.no_option = '--disable-' + name
  134. self.yes_option = '--enable-' + name
  135. elif style == 'with':
  136. self.no_option = '--without-' + name
  137. self.yes_option = '--with-' + name
  138. else:
  139. opt.fatal('invalid style')
  140. if style in ['yesno', 'yesno_and_hack']:
  141. opt.add_option(
  142. self.yes_option,
  143. dest=self.dest,
  144. action='store',
  145. choices=['auto', 'no', 'yes'],
  146. default='auto',
  147. help=option_help,
  148. metavar='no|yes')
  149. else:
  150. opt.add_option(
  151. self.yes_option,
  152. dest=self.dest,
  153. action='store_const',
  154. const='yes',
  155. default='auto',
  156. help=option_help)
  157. opt.add_option(
  158. self.no_option,
  159. dest=self.dest,
  160. action='store_const',
  161. const='no',
  162. default='auto',
  163. help=no_option_help)
  164. def check(self, *k, **kw):
  165. self.deps.append(('check', k, kw))
  166. def check_cfg(self, *k, **kw):
  167. self.deps.append(('check_cfg', k, kw))
  168. def find_program(self, *k, **kw):
  169. self.deps.append(('find_program', k, kw))
  170. def add_function(self, func, *k, **kw):
  171. """
  172. Add a custom function to be invoked as part of the
  173. configuration. During the configuration the function will be
  174. invoked with the configuration context as first argument
  175. followed by the arguments to this method, except for the func
  176. argument. The function must print a 'Checking for...' message,
  177. because it is referred to if the check fails and this option is
  178. requested.
  179. On configuration error the function shall raise
  180. conf.errors.ConfigurationError.
  181. """
  182. self.deps.append((func, k, kw))
  183. def _check(self, conf, required):
  184. """
  185. This private method checks all dependencies. It checks all
  186. dependencies (even if some dependency was not found) so that the
  187. user can install all missing dependencies in one go, instead of
  188. playing the infamous hit-configure-hit-configure game.
  189. This function returns True if all dependencies were found and
  190. False otherwise.
  191. """
  192. all_found = True
  193. for (f,k,kw) in self.deps:
  194. if hasattr(f, '__call__'):
  195. # This is a function supplied by add_function.
  196. func = f
  197. k = list(k)
  198. k.insert(0, conf)
  199. k = tuple(k)
  200. else:
  201. func = getattr(conf, f)
  202. try:
  203. func(*k, **kw)
  204. except conf.errors.ConfigurationError:
  205. all_found = False
  206. if required:
  207. Logs.error('The above check failed, but the '
  208. 'checkee is required for %s.' %
  209. self.yes_option)
  210. return all_found
  211. def configure(self, conf):
  212. """
  213. This function configures the option examining the command line
  214. option. It sets self.enable to whether this options should be
  215. enabled or not, that is True or False respectively. If not all
  216. dependencies were found self.enable will be False.
  217. conf.env['NAME'] and a preprocessor symbol will be defined with
  218. the result.
  219. If the option was desired but one or more dependencies were not
  220. found the an error message will be printed for each missing
  221. dependency.
  222. This function returns True on success and False on if the option
  223. was requested but cannot be enabled.
  224. """
  225. # If the option has already been configured once, do not
  226. # configure it again.
  227. if self.enable != None:
  228. return True
  229. argument = getattr(Options.options, self.dest)
  230. if argument == 'no':
  231. self.enable = False
  232. retvalue = True
  233. elif argument == 'yes':
  234. retvalue = self.enable = self._check(conf, True)
  235. else:
  236. self.enable = self.default and self._check(conf, False)
  237. retvalue = True
  238. conf.env[self.conf_dest] = self.enable
  239. conf.define(self.define, int(self.enable))
  240. return retvalue
  241. def summarize(self, conf):
  242. """
  243. This function displays a result summary with the help text and
  244. the result of the configuration.
  245. """
  246. if self.help:
  247. if self.enable:
  248. conf.msg(self.help, 'yes', color='GREEN')
  249. else:
  250. conf.msg(self.help, 'no', color='YELLOW')
  251. def options(opt):
  252. """
  253. This function declares necessary variables in the option context.
  254. The reason for saving variables in the option context is to allow
  255. autooptions to be loaded from modules (which will receive a new
  256. instance of this module, clearing any global variables) with a
  257. uniform style and default in the entire project.
  258. Call this function through opt.load('autooptions').
  259. """
  260. if not hasattr(opt, 'auto_options_style'):
  261. opt.auto_options_style = 'plain'
  262. if not hasattr(opt, 'auto_options_define'):
  263. opt.auto_options_define = 'WITH_%s'
  264. def opt(f):
  265. """
  266. Decorator: attach a new option function to Options.OptionsContext.
  267. :param f: method to bind
  268. :type f: function
  269. """
  270. setattr(Options.OptionsContext, f.__name__, f)
  271. @opt
  272. def add_auto_option(self, *k, **kw):
  273. """
  274. This function adds an AutoOption to the options context. It takes
  275. the same arguments as the initializer function of the AutoOptions
  276. class.
  277. """
  278. option = AutoOption(self, *k, **kw)
  279. auto_options.append(option)
  280. return option
  281. @opt
  282. def get_auto_options_define(self):
  283. """
  284. This function gets the default define name. This default can be
  285. changed through set_auto_optoins_define.
  286. """
  287. return self.auto_options_define
  288. @opt
  289. def set_auto_options_define(self, define):
  290. """
  291. This function sets the default define name. The default is
  292. 'WITH_%s', where %s will be replaced with the name of the option in
  293. uppercase.
  294. """
  295. self.auto_options_define = define
  296. @opt
  297. def get_auto_options_style(self):
  298. """
  299. This function gets the default option style, which will be used for
  300. the subsequent options.
  301. """
  302. return self.auto_options_style
  303. @opt
  304. def set_auto_options_style(self, style):
  305. """
  306. This function sets the default option style, which will be used for
  307. the subsequent options.
  308. """
  309. self.auto_options_style = style
  310. @opt
  311. def apply_auto_options_hack(self):
  312. """
  313. This function applies the hack necessary for the yesno_and_hack
  314. option style. The hack turns --foo into --foo=yes and --no-foo into
  315. --foo=no.
  316. It must be called before options are parsed, that is before the
  317. configure phase.
  318. """
  319. for option in auto_options:
  320. # With the hack the yesno options simply extend plain options.
  321. if option.style == 'yesno_and_hack':
  322. for i in range(1, len(sys.argv)):
  323. if sys.argv[i] == option.yes_option:
  324. sys.argv[i] = option.yes_option + '=yes'
  325. elif sys.argv[i] == option.no_option:
  326. sys.argv[i] = option.yes_option + '=no'
  327. @Configure.conf
  328. def summarize_auto_options(self):
  329. """
  330. This function prints a summary of the configuration of the auto
  331. options. Obviously, it must be called after
  332. conf.load('autooptions').
  333. """
  334. for option in auto_options:
  335. option.summarize(self)
  336. def configure(conf):
  337. """
  338. This configures all auto options. Call it through
  339. conf.load('autooptions').
  340. """
  341. ok = True
  342. for option in auto_options:
  343. if not option.configure(conf):
  344. ok = False
  345. if not ok:
  346. conf.fatal('Some requested options had unsatisfied ' +
  347. 'dependencies.\n' +
  348. 'See the above configuration for details.')