summaryrefslogtreecommitdiff
path: root/jam-files/boost-build/build/project.py
diff options
context:
space:
mode:
authorChris Dyer <cdyer@cs.cmu.edu>2012-10-11 14:06:32 -0400
committerChris Dyer <cdyer@cs.cmu.edu>2012-10-11 14:06:32 -0400
commit9339c80d465545aec5a6dccfef7c83ca715bf11f (patch)
tree64c56d558331edad1db3832018c80e799551c39a /jam-files/boost-build/build/project.py
parent438dac41810b7c69fa10203ac5130d20efa2da9f (diff)
parentafd7da3b2338661657ad0c4e9eec681e014d37bf (diff)
Merge branch 'master' of https://github.com/redpony/cdec
Diffstat (limited to 'jam-files/boost-build/build/project.py')
-rw-r--r--jam-files/boost-build/build/project.py1120
1 files changed, 0 insertions, 1120 deletions
diff --git a/jam-files/boost-build/build/project.py b/jam-files/boost-build/build/project.py
deleted file mode 100644
index 1e1e16fa..00000000
--- a/jam-files/boost-build/build/project.py
+++ /dev/null
@@ -1,1120 +0,0 @@
-# Status: ported.
-# Base revision: 64488
-
-# Copyright 2002, 2003 Dave Abrahams
-# Copyright 2002, 2005, 2006 Rene Rivera
-# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# Implements project representation and loading.
-# Each project is represented by
-# - a module where all the Jamfile content live.
-# - an instance of 'project-attributes' class.
-# (given module name, can be obtained by 'attributes' rule)
-# - an instance of 'project-target' class (from targets.jam)
-# (given a module name, can be obtained by 'target' rule)
-#
-# Typically, projects are created as result of loading Jamfile, which is
-# do by rules 'load' and 'initialize', below. First, module for Jamfile
-# is loaded and new project-attributes instance is created. Some rules
-# necessary for project are added to the module (see 'project-rules' module)
-# at the bottom of this file.
-# Default project attributes are set (inheriting attributes of parent project, if
-# it exists). After that, Jamfile is read. It can declare its own attributes,
-# via 'project' rule, which will be combined with already set attributes.
-#
-#
-# The 'project' rule can also declare project id, which will be associated with
-# the project module.
-#
-# There can also be 'standalone' projects. They are created by calling 'initialize'
-# on arbitrary module, and not specifying location. After the call, the module can
-# call 'project' rule, declare main target and behave as regular projects. However,
-# since it's not associated with any location, it's better declare only prebuilt
-# targets.
-#
-# The list of all loaded Jamfile is stored in variable .project-locations. It's possible
-# to obtain module name for a location using 'module-name' rule. The standalone projects
-# are not recorded, the only way to use them is by project id.
-
-import b2.util.path
-from b2.build import property_set, property
-from b2.build.errors import ExceptionWithUserContext
-import b2.build.targets
-
-import bjam
-
-import re
-import sys
-import os
-import string
-import imp
-import traceback
-import b2.util.option as option
-
-from b2.util import record_jam_to_value_mapping, qualify_jam_action
-
-class ProjectRegistry:
-
- def __init__(self, manager, global_build_dir):
- self.manager = manager
- self.global_build_dir = global_build_dir
- self.project_rules_ = ProjectRules(self)
-
- # The target corresponding to the project being loaded now
- self.current_project = None
-
- # The set of names of loaded project modules
- self.jamfile_modules = {}
-
- # Mapping from location to module name
- self.location2module = {}
-
- # Mapping from project id to project module
- self.id2module = {}
-
- # Map from Jamfile directory to parent Jamfile/Jamroot
- # location.
- self.dir2parent_jamfile = {}
-
- # Map from directory to the name of Jamfile in
- # that directory (or None).
- self.dir2jamfile = {}
-
- # Map from project module to attributes object.
- self.module2attributes = {}
-
- # Map from project module to target for the project
- self.module2target = {}
-
- # Map from names to Python modules, for modules loaded
- # via 'using' and 'import' rules in Jamfiles.
- self.loaded_tool_modules_ = {}
-
- self.loaded_tool_module_path_ = {}
-
- # Map from project target to the list of
- # (id,location) pairs corresponding to all 'use-project'
- # invocations.
- # TODO: should not have a global map, keep this
- # in ProjectTarget.
- self.used_projects = {}
-
- self.saved_current_project = []
-
- self.JAMROOT = self.manager.getenv("JAMROOT");
-
- # Note the use of character groups, as opposed to listing
- # 'Jamroot' and 'jamroot'. With the latter, we'd get duplicate
- # matches on windows and would have to eliminate duplicates.
- if not self.JAMROOT:
- self.JAMROOT = ["project-root.jam", "[Jj]amroot", "[Jj]amroot.jam"]
-
- # Default patterns to search for the Jamfiles to use for build
- # declarations.
- self.JAMFILE = self.manager.getenv("JAMFILE")
-
- if not self.JAMFILE:
- self.JAMFILE = ["[Bb]uild.jam", "[Jj]amfile.v2", "[Jj]amfile",
- "[Jj]amfile.jam"]
-
-
- def load (self, jamfile_location):
- """Loads jamfile at the given location. After loading, project global
- file and jamfile needed by the loaded one will be loaded recursively.
- If the jamfile at that location is loaded already, does nothing.
- Returns the project module for the Jamfile."""
-
- absolute = os.path.join(os.getcwd(), jamfile_location)
- absolute = os.path.normpath(absolute)
- jamfile_location = b2.util.path.relpath(os.getcwd(), absolute)
-
- if "--debug-loading" in self.manager.argv():
- print "Loading Jamfile at '%s'" % jamfile_location
-
-
- mname = self.module_name(jamfile_location)
- # If Jamfile is already loaded, don't try again.
- if not mname in self.jamfile_modules:
-
- self.load_jamfile(jamfile_location, mname)
-
- # We want to make sure that child project are loaded only
- # after parent projects. In particular, because parent projects
- # define attributes whch are inherited by children, and we don't
- # want children to be loaded before parents has defined everything.
- #
- # While "build-project" and "use-project" can potentially refer
- # to child projects from parent projects, we don't immediately
- # load child projects when seing those attributes. Instead,
- # we record the minimal information that will be used only later.
-
- self.load_used_projects(mname)
-
- return mname
-
- def load_used_projects(self, module_name):
- # local used = [ modules.peek $(module-name) : .used-projects ] ;
- used = self.used_projects[module_name]
-
- location = self.attribute(module_name, "location")
- for u in used:
- id = u[0]
- where = u[1]
-
- self.use(id, os.path.join(location, where))
-
- def load_parent(self, location):
- """Loads parent of Jamfile at 'location'.
- Issues an error if nothing is found."""
-
- found = b2.util.path.glob_in_parents(
- location, self.JAMROOT + self.JAMFILE)
-
- if not found:
- print "error: Could not find parent for project at '%s'" % location
- print "error: Did not find Jamfile or project-root.jam in any parent directory."
- sys.exit(1)
-
- return self.load(os.path.dirname(found[0]))
-
- def act_as_jamfile(self, module, location):
- """Makes the specified 'module' act as if it were a regularly loaded Jamfile
- at 'location'. If Jamfile is already located for that location, it's an
- error."""
-
- if self.module_name(location) in self.jamfile_modules:
- self.manager.errors()(
- "Jamfile was already loaded for '%s'" % location)
-
- # Set up non-default mapping from location to module.
- self.location2module[location] = module
-
- # Add the location to the list of project locations
- # so that we don't try to load Jamfile in future
- self.jamfile_modules.append(location)
-
- self.initialize(module, location)
-
- def find(self, name, current_location):
- """Given 'name' which can be project-id or plain directory name,
- return project module corresponding to that id or directory.
- Returns nothing of project is not found."""
-
- project_module = None
-
- # Try interpreting name as project id.
- if name[0] == '/':
- project_module = self.id2module.get(name)
-
- if not project_module:
- location = os.path.join(current_location, name)
- # If no project is registered for the given location, try to
- # load it. First see if we have Jamfile. If not we might have project
- # root, willing to act as Jamfile. In that case, project-root
- # must be placed in the directory referred by id.
-
- project_module = self.module_name(location)
- if not project_module in self.jamfile_modules:
- if b2.util.path.glob([location], self.JAMROOT + self.JAMFILE):
- project_module = self.load(location)
- else:
- project_module = None
-
- return project_module
-
- def module_name(self, jamfile_location):
- """Returns the name of module corresponding to 'jamfile-location'.
- If no module corresponds to location yet, associates default
- module name with that location."""
- module = self.location2module.get(jamfile_location)
- if not module:
- # Root the path, so that locations are always umbiguious.
- # Without this, we can't decide if '../../exe/program1' and '.'
- # are the same paths, or not.
- jamfile_location = os.path.realpath(
- os.path.join(os.getcwd(), jamfile_location))
- module = "Jamfile<%s>" % jamfile_location
- self.location2module[jamfile_location] = module
- return module
-
- def find_jamfile (self, dir, parent_root=0, no_errors=0):
- """Find the Jamfile at the given location. This returns the
- exact names of all the Jamfiles in the given directory. The optional
- parent-root argument causes this to search not the given directory
- but the ones above it up to the directory given in it."""
-
- # Glob for all the possible Jamfiles according to the match pattern.
- #
- jamfile_glob = None
- if parent_root:
- parent = self.dir2parent_jamfile.get(dir)
- if not parent:
- parent = b2.util.path.glob_in_parents(dir,
- self.JAMFILE)
- self.dir2parent_jamfile[dir] = parent
- jamfile_glob = parent
- else:
- jamfile = self.dir2jamfile.get(dir)
- if not jamfile:
- jamfile = b2.util.path.glob([dir], self.JAMFILE)
- self.dir2jamfile[dir] = jamfile
- jamfile_glob = jamfile
-
- if len(jamfile_glob) > 1:
- # Multiple Jamfiles found in the same place. Warn about this.
- # And ensure we use only one of them.
- # As a temporary convenience measure, if there's Jamfile.v2 amount
- # found files, suppress the warning and use it.
- #
- pattern = "(.*[Jj]amfile\\.v2)|(.*[Bb]uild\\.jam)"
- v2_jamfiles = [x for x in jamfile_glob if re.match(pattern, x)]
- if len(v2_jamfiles) == 1:
- jamfile_glob = v2_jamfiles
- else:
- print """warning: Found multiple Jamfiles at '%s'!""" % (dir)
- for j in jamfile_glob:
- print " -", j
- print "Loading the first one"
-
- # Could not find it, error.
- if not no_errors and not jamfile_glob:
- self.manager.errors()(
- """Unable to load Jamfile.
-Could not find a Jamfile in directory '%s'
-Attempted to find it with pattern '%s'.
-Please consult the documentation at 'http://boost.org/boost-build2'."""
- % (dir, string.join(self.JAMFILE)))
-
- if jamfile_glob:
- return jamfile_glob[0]
-
- def load_jamfile(self, dir, jamfile_module):
- """Load a Jamfile at the given directory. Returns nothing.
- Will attempt to load the file as indicated by the JAMFILE patterns.
- Effect of calling this rule twice with the same 'dir' is underfined."""
-
- # See if the Jamfile is where it should be.
- is_jamroot = False
- jamfile_to_load = b2.util.path.glob([dir], self.JAMROOT)
- if not jamfile_to_load:
- jamfile_to_load = self.find_jamfile(dir)
- else:
- if len(jamfile_to_load) > 1:
- get_manager().errors()("Multiple Jamfiles found at '%s'\n" +\
- "Filenames are: %s"
- % (dir, [os.path.basename(j) for j in jamfile_to_load]))
-
- is_jamroot = True
- jamfile_to_load = jamfile_to_load[0]
-
- dir = os.path.dirname(jamfile_to_load)
- if not dir:
- dir = "."
-
- self.used_projects[jamfile_module] = []
-
- # Now load the Jamfile in it's own context.
- # The call to 'initialize' may load parent Jamfile, which might have
- # 'use-project' statement that causes a second attempt to load the
- # same project we're loading now. Checking inside .jamfile-modules
- # prevents that second attempt from messing up.
- if not jamfile_module in self.jamfile_modules:
- self.jamfile_modules[jamfile_module] = True
-
- # Initialize the jamfile module before loading.
- #
- self.initialize(jamfile_module, dir, os.path.basename(jamfile_to_load))
-
- saved_project = self.current_project
-
- bjam.call("load", jamfile_module, jamfile_to_load)
- basename = os.path.basename(jamfile_to_load)
-
- if is_jamroot:
- jamfile = self.find_jamfile(dir, no_errors=True)
- if jamfile:
- bjam.call("load", jamfile_module, jamfile)
-
- # Now do some checks
- if self.current_project != saved_project:
- self.manager.errors()(
-"""The value of the .current-project variable
-has magically changed after loading a Jamfile.
-This means some of the targets might be defined a the wrong project.
-after loading %s
-expected value %s
-actual value %s""" % (jamfile_module, saved_project, self.current_project))
-
- if self.global_build_dir:
- id = self.attributeDefault(jamfile_module, "id", None)
- project_root = self.attribute(jamfile_module, "project-root")
- location = self.attribute(jamfile_module, "location")
-
- if location and project_root == dir:
- # This is Jamroot
- if not id:
- # FIXME: go via errors module, so that contexts are
- # shown?
- print "warning: the --build-dir option was specified"
- print "warning: but Jamroot at '%s'" % dir
- print "warning: specified no project id"
- print "warning: the --build-dir option will be ignored"
-
-
- def load_standalone(self, jamfile_module, file):
- """Loads 'file' as standalone project that has no location
- associated with it. This is mostly useful for user-config.jam,
- which should be able to define targets, but although it has
- some location in filesystem, we don't want any build to
- happen in user's HOME, for example.
-
- The caller is required to never call this method twice on
- the same file.
- """
-
- self.used_projects[jamfile_module] = []
- bjam.call("load", jamfile_module, file)
- self.load_used_projects(jamfile_module)
-
- def is_jamroot(self, basename):
- match = [ pat for pat in self.JAMROOT if re.match(pat, basename)]
- if match:
- return 1
- else:
- return 0
-
- def initialize(self, module_name, location=None, basename=None):
- """Initialize the module for a project.
-
- module-name is the name of the project module.
- location is the location (directory) of the project to initialize.
- If not specified, stanalone project will be initialized
- """
-
- if "--debug-loading" in self.manager.argv():
- print "Initializing project '%s'" % module_name
-
- # TODO: need to consider if standalone projects can do anything but defining
- # prebuilt targets. If so, we need to give more sensible "location", so that
- # source paths are correct.
- if not location:
- location = ""
-
- attributes = ProjectAttributes(self.manager, location, module_name)
- self.module2attributes[module_name] = attributes
-
- python_standalone = False
- if location:
- attributes.set("source-location", [location], exact=1)
- elif not module_name in ["test-config", "site-config", "user-config", "project-config"]:
- # This is a standalone project with known location. Set source location
- # so that it can declare targets. This is intended so that you can put
- # a .jam file in your sources and use it via 'using'. Standard modules
- # (in 'tools' subdir) may not assume source dir is set.
- module = sys.modules[module_name]
- attributes.set("source-location", self.loaded_tool_module_path_[module_name], exact=1)
- python_standalone = True
-
- attributes.set("requirements", property_set.empty(), exact=True)
- attributes.set("usage-requirements", property_set.empty(), exact=True)
- attributes.set("default-build", property_set.empty(), exact=True)
- attributes.set("projects-to-build", [], exact=True)
- attributes.set("project-root", None, exact=True)
- attributes.set("build-dir", None, exact=True)
-
- self.project_rules_.init_project(module_name, python_standalone)
-
- jamroot = False
-
- parent_module = None;
- if module_name == "test-config":
- # No parent
- pass
- elif module_name == "site-config":
- parent_module = "test-config"
- elif module_name == "user-config":
- parent_module = "site-config"
- elif module_name == "project-config":
- parent_module = "user-config"
- elif location and not self.is_jamroot(basename):
- # We search for parent/project-root only if jamfile was specified
- # --- i.e
- # if the project is not standalone.
- parent_module = self.load_parent(location)
- else:
- # It's either jamroot, or standalone project.
- # If it's jamroot, inherit from user-config.
- if location:
- # If project-config module exist, inherit from it.
- if self.module2attributes.has_key("project-config"):
- parent_module = "project-config"
- else:
- parent_module = "user-config" ;
-
- jamroot = True ;
-
- if parent_module:
- self.inherit_attributes(module_name, parent_module)
- attributes.set("parent-module", parent_module, exact=1)
-
- if jamroot:
- attributes.set("project-root", location, exact=1)
-
- parent = None
- if parent_module:
- parent = self.target(parent_module)
-
- if not self.module2target.has_key(module_name):
- target = b2.build.targets.ProjectTarget(self.manager,
- module_name, module_name, parent,
- self.attribute(module_name,"requirements"),
- # FIXME: why we need to pass this? It's not
- # passed in jam code.
- self.attribute(module_name, "default-build"))
- self.module2target[module_name] = target
-
- self.current_project = self.target(module_name)
-
- def inherit_attributes(self, project_module, parent_module):
- """Make 'project-module' inherit attributes of project
- root and parent module."""
-
- attributes = self.module2attributes[project_module]
- pattributes = self.module2attributes[parent_module]
-
- # Parent module might be locationless user-config.
- # FIXME:
- #if [ modules.binding $(parent-module) ]
- #{
- # $(attributes).set parent : [ path.parent
- # [ path.make [ modules.binding $(parent-module) ] ] ] ;
- # }
-
- attributes.set("project-root", pattributes.get("project-root"), exact=True)
- attributes.set("default-build", pattributes.get("default-build"), exact=True)
- attributes.set("requirements", pattributes.get("requirements"), exact=True)
- attributes.set("usage-requirements",
- pattributes.get("usage-requirements"), exact=1)
-
- parent_build_dir = pattributes.get("build-dir")
-
- if parent_build_dir:
- # Have to compute relative path from parent dir to our dir
- # Convert both paths to absolute, since we cannot
- # find relative path from ".." to "."
-
- location = attributes.get("location")
- parent_location = pattributes.get("location")
-
- our_dir = os.path.join(os.getcwd(), location)
- parent_dir = os.path.join(os.getcwd(), parent_location)
-
- build_dir = os.path.join(parent_build_dir,
- os.path.relpath(our_dir, parent_dir))
- attributes.set("build-dir", build_dir, exact=True)
-
- def register_id(self, id, module):
- """Associate the given id with the given project module."""
- self.id2module[id] = module
-
- def current(self):
- """Returns the project which is currently being loaded."""
- return self.current_project
-
- def set_current(self, c):
- self.current_project = c
-
- def push_current(self, project):
- """Temporary changes the current project to 'project'. Should
- be followed by 'pop-current'."""
- self.saved_current_project.append(self.current_project)
- self.current_project = project
-
- def pop_current(self):
- self.current_project = self.saved_current_project[-1]
- del self.saved_current_project[-1]
-
- def attributes(self, project):
- """Returns the project-attribute instance for the
- specified jamfile module."""
- return self.module2attributes[project]
-
- def attribute(self, project, attribute):
- """Returns the value of the specified attribute in the
- specified jamfile module."""
- return self.module2attributes[project].get(attribute)
- try:
- return self.module2attributes[project].get(attribute)
- except:
- raise BaseException("No attribute '%s' for project" % (attribute, project))
-
- def attributeDefault(self, project, attribute, default):
- """Returns the value of the specified attribute in the
- specified jamfile module."""
- return self.module2attributes[project].getDefault(attribute, default)
-
- def target(self, project_module):
- """Returns the project target corresponding to the 'project-module'."""
- if not self.module2target.has_key(project_module):
- self.module2target[project_module] = \
- b2.build.targets.ProjectTarget(project_module, project_module,
- self.attribute(project_module, "requirements"))
-
- return self.module2target[project_module]
-
- def use(self, id, location):
- # Use/load a project.
- saved_project = self.current_project
- project_module = self.load(location)
- declared_id = self.attributeDefault(project_module, "id", "")
-
- if not declared_id or declared_id != id:
- # The project at 'location' either have no id or
- # that id is not equal to the 'id' parameter.
- if self.id2module.has_key(id) and self.id2module[id] != project_module:
- self.manager.errors()(
-"""Attempt to redeclare already existing project id '%s' at location '%s'""" % (id, location))
- self.id2module[id] = project_module
-
- self.current_module = saved_project
-
- def add_rule(self, name, callable):
- """Makes rule 'name' available to all subsequently loaded Jamfiles.
-
- Calling that rule wil relay to 'callable'."""
- self.project_rules_.add_rule(name, callable)
-
- def project_rules(self):
- return self.project_rules_
-
- def glob_internal(self, project, wildcards, excludes, rule_name):
- location = project.get("source-location")[0]
-
- result = []
- callable = b2.util.path.__dict__[rule_name]
-
- paths = callable([location], wildcards, excludes)
- has_dir = 0
- for w in wildcards:
- if os.path.dirname(w):
- has_dir = 1
- break
-
- if has_dir or rule_name != "glob":
- result = []
- # The paths we've found are relative to current directory,
- # but the names specified in sources list are assumed to
- # be relative to source directory of the corresponding
- # prject. Either translate them or make absolute.
-
- for p in paths:
- rel = os.path.relpath(p, location)
- # If the path is below source location, use relative path.
- if not ".." in rel:
- result.append(rel)
- else:
- # Otherwise, use full path just to avoid any ambiguities.
- result.append(os.path.abspath(p))
-
- else:
- # There were not directory in wildcard, so the files are all
- # in the source directory of the project. Just drop the
- # directory, instead of making paths absolute.
- result = [os.path.basename(p) for p in paths]
-
- return result
-
- def load_module(self, name, extra_path=None):
- """Load a Python module that should be useable from Jamfiles.
-
- There are generally two types of modules Jamfiles might want to
- use:
- - Core Boost.Build. Those are imported using plain names, e.g.
- 'toolset', so this function checks if we have module named
- b2.package.module already.
- - Python modules in the same directory as Jamfile. We don't
- want to even temporary add Jamfile's directory to sys.path,
- since then we might get naming conflicts between standard
- Python modules and those.
- """
-
- # See if we loaded module of this name already
- existing = self.loaded_tool_modules_.get(name)
- if existing:
- return existing
-
- # See if we have a module b2.whatever.<name>, where <name>
- # is what is passed to this function
- modules = sys.modules
- for class_name in modules:
- parts = class_name.split('.')
- if name is class_name or parts[0] == "b2" \
- and parts[-1] == name.replace("-", "_"):
- module = modules[class_name]
- self.loaded_tool_modules_[name] = module
- return module
-
- # Lookup a module in BOOST_BUILD_PATH
- path = extra_path
- if not path:
- path = []
- path.extend(self.manager.boost_build_path())
- location = None
- for p in path:
- l = os.path.join(p, name + ".py")
- if os.path.exists(l):
- location = l
- break
-
- if not location:
- self.manager.errors()("Cannot find module '%s'" % name)
-
- mname = name + "__for_jamfile"
- file = open(location)
- try:
- # TODO: this means we'll never make use of .pyc module,
- # which might be a problem, or not.
- self.loaded_tool_module_path_[mname] = location
- module = imp.load_module(mname, file, os.path.basename(location),
- (".py", "r", imp.PY_SOURCE))
- self.loaded_tool_modules_[name] = module
- return module
- finally:
- file.close()
-
-
-
-# FIXME:
-# Defines a Boost.Build extension project. Such extensions usually
-# contain library targets and features that can be used by many people.
-# Even though extensions are really projects, they can be initialize as
-# a module would be with the "using" (project.project-rules.using)
-# mechanism.
-#rule extension ( id : options * : * )
-#{
-# # The caller is a standalone module for the extension.
-# local mod = [ CALLER_MODULE ] ;
-#
-# # We need to do the rest within the extension module.
-# module $(mod)
-# {
-# import path ;
-#
-# # Find the root project.
-# local root-project = [ project.current ] ;
-# root-project = [ $(root-project).project-module ] ;
-# while
-# [ project.attribute $(root-project) parent-module ] &&
-# [ project.attribute $(root-project) parent-module ] != user-config
-# {
-# root-project = [ project.attribute $(root-project) parent-module ] ;
-# }
-#
-# # Create the project data, and bring in the project rules
-# # into the module.
-# project.initialize $(__name__) :
-# [ path.join [ project.attribute $(root-project) location ] ext $(1:L) ] ;
-#
-# # Create the project itself, i.e. the attributes.
-# # All extensions are created in the "/ext" project space.
-# project /ext/$(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
-# local attributes = [ project.attributes $(__name__) ] ;
-#
-# # Inherit from the root project of whomever is defining us.
-# project.inherit-attributes $(__name__) : $(root-project) ;
-# $(attributes).set parent-module : $(root-project) : exact ;
-# }
-#}
-
-
-class ProjectAttributes:
- """Class keeping all the attributes of a project.
-
- The standard attributes are 'id', "location", "project-root", "parent"
- "requirements", "default-build", "source-location" and "projects-to-build".
- """
-
- def __init__(self, manager, location, project_module):
- self.manager = manager
- self.location = location
- self.project_module = project_module
- self.attributes = {}
- self.usage_requirements = None
-
- def set(self, attribute, specification, exact=False):
- """Set the named attribute from the specification given by the user.
- The value actually set may be different."""
-
- if exact:
- self.__dict__[attribute] = specification
-
- elif attribute == "requirements":
- self.requirements = property_set.refine_from_user_input(
- self.requirements, specification,
- self.project_module, self.location)
-
- elif attribute == "usage-requirements":
- unconditional = []
- for p in specification:
- split = property.split_conditional(p)
- if split:
- unconditional.append(split[1])
- else:
- unconditional.append(p)
-
- non_free = property.remove("free", unconditional)
- if non_free:
- get_manager().errors()("usage-requirements %s have non-free properties %s" \
- % (specification, non_free))
-
- t = property.translate_paths(
- property.create_from_strings(specification, allow_condition=True),
- self.location)
-
- existing = self.__dict__.get("usage-requirements")
- if existing:
- new = property_set.create(existing.all() + t)
- else:
- new = property_set.create(t)
- self.__dict__["usage-requirements"] = new
-
-
- elif attribute == "default-build":
- self.__dict__["default-build"] = property_set.create(specification)
-
- elif attribute == "source-location":
- source_location = []
- for path in specification:
- source_location.append(os.path.join(self.location, path))
- self.__dict__["source-location"] = source_location
-
- elif attribute == "build-dir":
- self.__dict__["build-dir"] = os.path.join(self.location, specification[0])
-
- elif attribute == "id":
- id = specification[0]
- if id[0] != '/':
- id = "/" + id
- self.manager.projects().register_id(id, self.project_module)
- self.__dict__["id"] = id
-
- elif not attribute in ["default-build", "location",
- "source-location", "parent",
- "projects-to-build", "project-root"]:
- self.manager.errors()(
-"""Invalid project attribute '%s' specified
-for project at '%s'""" % (attribute, self.location))
- else:
- self.__dict__[attribute] = specification
-
- def get(self, attribute):
- return self.__dict__[attribute]
-
- def getDefault(self, attribute, default):
- return self.__dict__.get(attribute, default)
-
- def dump(self):
- """Prints the project attributes."""
- id = self.get("id")
- if not id:
- id = "(none)"
- else:
- id = id[0]
-
- parent = self.get("parent")
- if not parent:
- parent = "(none)"
- else:
- parent = parent[0]
-
- print "'%s'" % id
- print "Parent project:%s", parent
- print "Requirements:%s", self.get("requirements")
- print "Default build:%s", string.join(self.get("debuild-build"))
- print "Source location:%s", string.join(self.get("source-location"))
- print "Projects to build:%s", string.join(self.get("projects-to-build").sort());
-
-class ProjectRules:
- """Class keeping all rules that are made available to Jamfile."""
-
- def __init__(self, registry):
- self.registry = registry
- self.manager_ = registry.manager
- self.rules = {}
- self.local_names = [x for x in self.__class__.__dict__
- if x not in ["__init__", "init_project", "add_rule",
- "error_reporting_wrapper", "add_rule_for_type", "reverse"]]
- self.all_names_ = [x for x in self.local_names]
-
- def _import_rule(self, bjam_module, name, callable):
- if hasattr(callable, "bjam_signature"):
- bjam.import_rule(bjam_module, name, self.make_wrapper(callable), callable.bjam_signature)
- else:
- bjam.import_rule(bjam_module, name, self.make_wrapper(callable))
-
-
- def add_rule_for_type(self, type):
- rule_name = type.lower().replace("_", "-")
-
- def xpto (name, sources = [], requirements = [], default_build = [], usage_requirements = []):
- return self.manager_.targets().create_typed_target(
- type, self.registry.current(), name[0], sources,
- requirements, default_build, usage_requirements)
-
- self.add_rule(rule_name, xpto)
-
- def add_rule(self, name, callable):
- self.rules[name] = callable
- self.all_names_.append(name)
-
- # Add new rule at global bjam scope. This might not be ideal,
- # added because if a jamroot does 'import foo' where foo calls
- # add_rule, we need to import new rule to jamroot scope, and
- # I'm lazy to do this now.
- self._import_rule("", name, callable)
-
- def all_names(self):
- return self.all_names_
-
- def call_and_report_errors(self, callable, *args, **kw):
- result = None
- try:
- self.manager_.errors().push_jamfile_context()
- result = callable(*args, **kw)
- except ExceptionWithUserContext, e:
- e.report()
- except Exception, e:
- try:
- self.manager_.errors().handle_stray_exception (e)
- except ExceptionWithUserContext, e:
- e.report()
- finally:
- self.manager_.errors().pop_jamfile_context()
-
- return result
-
- def make_wrapper(self, callable):
- """Given a free-standing function 'callable', return a new
- callable that will call 'callable' and report all exceptins,
- using 'call_and_report_errors'."""
- def wrapper(*args, **kw):
- return self.call_and_report_errors(callable, *args, **kw)
- return wrapper
-
- def init_project(self, project_module, python_standalone=False):
-
- if python_standalone:
- m = sys.modules[project_module]
-
- for n in self.local_names:
- if n != "import_":
- setattr(m, n, getattr(self, n))
-
- for n in self.rules:
- setattr(m, n, self.rules[n])
-
- return
-
- for n in self.local_names:
- # Using 'getattr' here gives us a bound method,
- # while using self.__dict__[r] would give unbound one.
- v = getattr(self, n)
- if callable(v):
- if n == "import_":
- n = "import"
- else:
- n = string.replace(n, "_", "-")
-
- self._import_rule(project_module, n, v)
-
- for n in self.rules:
- self._import_rule(project_module, n, self.rules[n])
-
- def project(self, *args):
-
- jamfile_module = self.registry.current().project_module()
- attributes = self.registry.attributes(jamfile_module)
-
- id = None
- if args and args[0]:
- id = args[0][0]
- args = args[1:]
-
- if id:
- attributes.set('id', [id])
-
- explicit_build_dir = None
- for a in args:
- if a:
- attributes.set(a[0], a[1:], exact=0)
- if a[0] == "build-dir":
- explicit_build_dir = a[1]
-
- # If '--build-dir' is specified, change the build dir for the project.
- if self.registry.global_build_dir:
-
- location = attributes.get("location")
- # Project with empty location is 'standalone' project, like
- # user-config, or qt. It has no build dir.
- # If we try to set build dir for user-config, we'll then
- # try to inherit it, with either weird, or wrong consequences.
- if location and location == attributes.get("project-root"):
- # Re-read the project id, since it might have been changed in
- # the project's attributes.
- id = attributes.get('id')
-
- # This is Jamroot.
- if id:
- if explicit_build_dir and os.path.isabs(explicit_build_dir):
- self.registry.manager.errors()(
-"""Absolute directory specified via 'build-dir' project attribute
-Don't know how to combine that with the --build-dir option.""")
-
- rid = id
- if rid[0] == '/':
- rid = rid[1:]
-
- p = os.path.join(self.registry.global_build_dir, rid)
- if explicit_build_dir:
- p = os.path.join(p, explicit_build_dir)
- attributes.set("build-dir", p, exact=1)
- elif explicit_build_dir:
- self.registry.manager.errors()(
-"""When --build-dir is specified, the 'build-dir'
-attribute is allowed only for top-level 'project' invocations""")
-
- def constant(self, name, value):
- """Declare and set a project global constant.
- Project global constants are normal variables but should
- not be changed. They are applied to every child Jamfile."""
- m = "Jamfile</home/ghost/Work/Boost/boost-svn/tools/build/v2_python/python/tests/bjam/make>"
- self.registry.current().add_constant(name[0], value)
-
- def path_constant(self, name, value):
- """Declare and set a project global constant, whose value is a path. The
- path is adjusted to be relative to the invocation directory. The given
- value path is taken to be either absolute, or relative to this project
- root."""
- if len(value) > 1:
- self.registry.manager.error()("path constant should have one element")
- self.registry.current().add_constant(name[0], value[0], path=1)
-
- def use_project(self, id, where):
- # See comment in 'load' for explanation why we record the
- # parameters as opposed to loading the project now.
- m = self.registry.current().project_module();
- self.registry.used_projects[m].append((id[0], where[0]))
-
- def build_project(self, dir):
- assert(isinstance(dir, list))
- jamfile_module = self.registry.current().project_module()
- attributes = self.registry.attributes(jamfile_module)
- now = attributes.get("projects-to-build")
- attributes.set("projects-to-build", now + dir, exact=True)
-
- def explicit(self, target_names):
- self.registry.current().mark_targets_as_explicit(target_names)
-
- def always(self, target_names):
- self.registry.current().mark_targets_as_alays(target_names)
-
- def glob(self, wildcards, excludes=None):
- return self.registry.glob_internal(self.registry.current(),
- wildcards, excludes, "glob")
-
- def glob_tree(self, wildcards, excludes=None):
- bad = 0
- for p in wildcards:
- if os.path.dirname(p):
- bad = 1
-
- if excludes:
- for p in excludes:
- if os.path.dirname(p):
- bad = 1
-
- if bad:
- self.registry.manager.errors()(
-"The patterns to 'glob-tree' may not include directory")
- return self.registry.glob_internal(self.registry.current(),
- wildcards, excludes, "glob_tree")
-
-
- def using(self, toolset, *args):
- # The module referred by 'using' can be placed in
- # the same directory as Jamfile, and the user
- # will expect the module to be found even though
- # the directory is not in BOOST_BUILD_PATH.
- # So temporary change the search path.
- current = self.registry.current()
- location = current.get('location')
-
- m = self.registry.load_module(toolset[0], [location])
- if not m.__dict__.has_key("init"):
- self.registry.manager.errors()(
- "Tool module '%s' does not define the 'init' method" % toolset[0])
- m.init(*args)
-
- # The above might have clobbered .current-project. Restore the correct
- # value.
- self.registry.set_current(current)
-
- def import_(self, name, names_to_import=None, local_names=None):
-
- name = name[0]
- py_name = name
- if py_name == "os":
- py_name = "os_j"
- jamfile_module = self.registry.current().project_module()
- attributes = self.registry.attributes(jamfile_module)
- location = attributes.get("location")
-
- saved = self.registry.current()
-
- m = self.registry.load_module(py_name, [location])
-
- for f in m.__dict__:
- v = m.__dict__[f]
- f = f.replace("_", "-")
- if callable(v):
- qn = name + "." + f
- self._import_rule(jamfile_module, qn, v)
- record_jam_to_value_mapping(qualify_jam_action(qn, jamfile_module), v)
-
-
- if names_to_import:
- if not local_names:
- local_names = names_to_import
-
- if len(names_to_import) != len(local_names):
- self.registry.manager.errors()(
-"""The number of names to import and local names do not match.""")
-
- for n, l in zip(names_to_import, local_names):
- self._import_rule(jamfile_module, l, m.__dict__[n])
-
- self.registry.set_current(saved)
-
- def conditional(self, condition, requirements):
- """Calculates conditional requirements for multiple requirements
- at once. This is a shorthand to be reduce duplication and to
- keep an inline declarative syntax. For example:
-
- lib x : x.cpp : [ conditional <toolset>gcc <variant>debug :
- <define>DEBUG_EXCEPTION <define>DEBUG_TRACE ] ;
- """
-
- c = string.join(condition, ",")
- if c.find(":") != -1:
- return [c + r for r in requirements]
- else:
- return [c + ":" + r for r in requirements]
-
- def option(self, name, value):
- name = name[0]
- if not name in ["site-config", "user-config", "project-config"]:
- get_manager().errors()("The 'option' rule may be used only in site-config or user-config")
-
- option.set(name, value[0])