blob: b4589ee72e10e4014dde69fe77a3696464dc75ad [file] [log] [blame]
# Status: being ported by Vladimir Prus.
# Copyright 2003, 2005 Dave Abrahams
# Copyright 2006 Rene Rivera
# Copyright 2003, 2004, 2005, 2006, 2007 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)
from b2.build.engine import Engine
from b2.manager import Manager
from b2.util.path import glob
from b2.build import feature, property_set
import b2.build.virtual_target
from b2.build.targets import ProjectTarget
from b2.util.sequence import unique
import b2.build.build_request
from b2.build.errors import ExceptionWithUserContext
import b2.tools.common
import bjam
import os
import sys
# FIXME:
# Returns the location of the build system. The primary use case
# is building Boost, where it's sometimes needed to get location
# of other components (like BoostBook files), and it's convenient
# to use location relatively to Boost.Build path.
#rule location ( )
#{
# local r = [ modules.binding build-system ] ;
# return $(r:P) ;
#}
# FIXME:
def get_boolean_option(name):
match = "--" + name
if match in argv:
return 1
else:
return 0
def get_string_option(name):
match = "--" + name + "="
for arg in argv:
if arg.startswith(match):
return arg[len(match):]
return None
def home_directories():
if os.name == "nt":
result = set()
try:
result.add(os.environ['HOMEDRIVE'] + os.environ['HOMEPATH'])
result.add(os.environ['HOME'])
result.add(os.environ['USERPROFILE'])
except KeyError:
pass
return list(result)
else:
return [os.environ['HOME']]
ignore_config = 0
debug_config = 0
def load_config(manager, basename, path):
"""Unless ignore-config is set, search configuration
basename.jam in path and loads it. The jamfile module
for that file will be loaded 'basename'."""
if not ignore_config:
found = glob(path, [basename + ".jam"])
if found:
found = found[0]
if debug_config:
print "notice: searching '%s' for '%s.jam'" % (path, basename)
if found:
print "notice: loading %s.jam from %s" % (basename, found)
manager.projects().load_standalone(basename, found)
def main():
global argv
argv = bjam.variable("ARGV")
# FIXME: document this option.
if "--profiling" in argv:
import cProfile
import pstats
cProfile.runctx('main_real()', globals(), locals(), "stones.prof")
stats = pstats.Stats("stones.prof")
stats.strip_dirs()
stats.sort_stats('time', 'calls')
stats.print_callers(20)
else:
main_real()
def main_real():
global ignore_config
global debug_config
boost_build_path = bjam.variable("BOOST_BUILD_PATH")
engine = Engine()
global_build_dir = get_string_option("build-dir")
debug_config = get_boolean_option("debug-configuration")
manager = Manager(engine, global_build_dir)
# This module defines types and generator and what not,
# and depends on manager's existence
import b2.tools.builtin
# Check if we can load 'test-config.jam'. If we can, load it and
# ignore user configs.
test_config = glob(boost_build_path, ["test-config.jam"])
if test_config:
test_config = test_config[0]
if test_config:
if debug_config:
print "notice: loading testing-config.jam from '%s'" % test_config
print "notice: user-config.jam and site-config.jam will be ignored"
manager.projects().load_standalone("test-config", test_config)
ignore_config = test_config or get_boolean_option("ignore-config")
user_path = home_directories() + boost_build_path
site_path = ["/etc"] + user_path
if bjam.variable("OS") in ["NT", "CYGWIN"]:
site_path = [os.environ("SystemRoot")] + user_path
load_config(manager, "site-config", site_path)
user_config_path = get_string_option("user-config")
if not user_config_path:
user_config_path = os.environ.get("BOOST_BUILD_USER_CONFIG")
if user_config_path:
if debug_config:
print "Loading explicitly specifier user configuration file:"
print " %s" % user_config_path
manager.projects().load_standalone("user-config", user_config_path)
else:
load_config(manager, "user-config", user_path)
# FIXME:
## #
## # Autoconfigure toolsets based on any instances of --toolset=xx,yy,...zz or
## # toolset=xx,yy,...zz in the command line
## #
## local option-toolsets = [ regex.split-list [ MATCH ^--toolset=(.*) : $(argv) ] : "," ] ;
## local feature-toolsets = [ regex.split-list [ MATCH ^toolset=(.*) : $(argv) ] : "," ] ;
## # if the user specified --toolset=..., we need to add toolset=... to
## # the build request
## local extra-build-request ;
extra_build_request = []
## if ! $(ignore-config)
## {
## for local t in $(option-toolsets) $(feature-toolsets)
## {
## # Parse toolset-version/properties
## local (t-v,t,v) = [ MATCH (([^-/]+)-?([^/]+)?)/?.* : $(t) ] ;
## local toolset-version = $((t-v,t,v)[1]) ;
## local toolset = $((t-v,t,v)[2]) ;
## local version = $((t-v,t,v)[3]) ;
## if $(debug-config)
## {
## ECHO notice: [cmdline-cfg] Detected command-line request for
## $(toolset-version): toolset= \"$(toolset)\" "version= \""$(version)\" ;
## }
## local known ;
## # if the toolset isn't known, configure it now.
## if $(toolset) in [ feature.values <toolset> ]
## {
## known = true ;
## }
## if $(known) && $(version)
## && ! [ feature.is-subvalue toolset : $(toolset) : version : $(version) ]
## {
## known = ;
## }
## if ! $(known)
## {
## if $(debug-config)
## {
## ECHO notice: [cmdline-cfg] toolset $(toolset-version)
## not previously configured; configuring now ;
## }
## toolset.using $(toolset) : $(version) ;
## }
## else
## {
## if $(debug-config)
## {
## ECHO notice: [cmdline-cfg] toolset $(toolset-version) already configured ;
## }
## }
## # make sure we get an appropriate property into the build request in
## # case the user used the "--toolset=..." form
## if ! $(t) in $(argv)
## && ! $(t) in $(feature-toolsets)
## {
## if $(debug-config)
## {
## ECHO notice: [cmdline-cfg] adding toolset=$(t) "to build request." ;
## }
## extra-build-request += toolset=$(t) ;
## }
## }
## }
# FIXME:
## if USER_MODULE in [ RULENAMES ]
## {
## USER_MODULE site-config user-config ;
## }
if get_boolean_option("version"):
# FIXME: Move to a separate module. Include bjam
# verision.
print "Boost.Build M15 (Python port in development)"
sys.exit(0)
b2.tools.common.init(manager)
# We always load project in "." so that 'use-project' directives has
# any chance of been seen. Otherwise, we won't be able to refer to
# subprojects using target ids.
current_project = None
projects = manager.projects()
if projects.find(".", "."):
current_project = projects.target(projects.load("."))
# FIXME: revive this logic, when loading of gcc works
if not feature.values("<toolset>") and not ignore_config and 0:
default_toolset = "gcc" ;
if bjam.variable("OS") == "NT":
default_toolset = "msvc"
print "warning: No toolsets are configured." ;
print "warning: Configuring default toolset '%s'" % default_toolset
print "warning: If the default is wrong, you may not be able to build C++ programs."
print "warning: Use the \"--toolset=xxxxx\" option to override our guess."
print "warning: For more configuration options, please consult"
print "warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html"
projects.project_rules().using([default_toolset])
(target_ids, properties) = b2.build.build_request.from_command_line(
argv[1:] + extra_build_request)
if properties:
expanded = b2.build.build_request.expand_no_defaults(properties)
xexpanded = []
for e in expanded:
xexpanded.append(property_set.create(feature.split(e)))
expanded = xexpanded
else:
expanded = [property_set.empty()]
targets = []
clean = get_boolean_option("clean")
clean_all = get_boolean_option("clean-all")
bjam_targets = []
# Given a target id, try to find and return corresponding target.
# This is only invoked when there's no Jamfile in "."
# This code somewhat duplicates code in project-target.find but we can't reuse
# that code without project-targets instance.
def find_target (target_id):
split = target_id.split("//")
pm = None
if len(split) > 1:
pm = projects.find(split[0], ".")
else:
pm = projects.find(target_id, ".")
result = None
if pm:
result = projects.target(pm)
if len(split) > 1:
result = result.find(split[1])
if not current_project and not target_ids:
print "error: no Jamfile in current directory found, and no target references specified."
sys.exit(1)
for id in target_ids:
if id == "clean":
clean = 1
else:
t = None
if current_project:
t = current_project.find(id, no_error=1)
else:
t = find_target(id)
if not t:
print "notice: could not find main target '%s'" % id
print "notice: assuming it's a name of file to create " ;
bjam_targets.append(id)
else:
targets.append(t)
if not targets:
targets = [projects.target(projects.module_name("."))]
virtual_targets = []
# Virtual targets obtained when building main targets references on
# the command line. When running
#
# bjam --clean main_target
#
# we want to clean the files that belong only to that main target,
# so we need to record which targets are produced.
results_of_main_targets = []
for p in expanded:
manager.set_command_line_free_features(property_set.create(p.free()))
for t in targets:
try:
g = t.generate(p)
if not isinstance(t, ProjectTarget):
results_of_main_targets.extend(g.targets())
virtual_targets.extend(g.targets())
except ExceptionWithUserContext, e:
e.report()
except Exception:
raise
# The cleaning is tricky. Say, if
# user says:
#
# bjam --clean foo
#
# where 'foo' is a directory, then we want to clean targets
# which are in 'foo' or in any children Jamfiles, but not in any
# unrelated Jamfiles. So, we collect the list of project under which
# cleaning is allowed.
#
projects_to_clean = []
targets_to_clean = []
if clean or clean_all:
for t in targets:
if isinstance(t, ProjectTarget):
projects_to_clean.append(t.project_module())
for t in results_of_main_targets:
# Don't include roots or sources.
targets_to_clean += b2.build.virtual_target.traverse(t)
targets_to_clean = unique(targets_to_clean)
is_child_cache_ = {}
# Returns 'true' if 'project' is a child of 'current-project',
# possibly indirect, or is equal to 'project'.
# Returns 'false' otherwise.
def is_child (project):
r = is_child_cache_.get(project, None)
if not r:
if project in projects_to_clean:
r = 1
else:
parent = manager.projects().attribute(project, "parent-module")
if parent and parent != "user-config":
r = is_child(parent)
else:
r = 0
is_child_cache_[project] = r
return r
actual_targets = []
for t in virtual_targets:
actual_targets.append(t.actualize())
bjam.call("NOTFILE", "all")
bjam.call("DEPENDS", "all", actual_targets)
if bjam_targets:
bjam.call("UPDATE", ["<e>%s" % x for x in bjam_targets])
elif clean_all:
bjam.call("UPDATE", "clean-all")
elif clean:
to_clean = []
for t in manager.virtual_targets().all_targets():
p = t.project()
# Remove only derived targets.
if t.action() and \
(t in targets_to_clean or is_child(p.project_module())):
to_clean.append(t)
to_clean_actual = [t.actualize() for t in to_clean]
manager.engine().set_update_action('common.Clean', 'clean',
to_clean_actual, None)
bjam.call("UPDATE", "clean")
else:
bjam.call("UPDATE", "all")