2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-14 12:42:11 +00:00

Merge improvements from Juraj, as follows:

Minor changes in feature.py.
      Prevent hard error when creating a property from string,
         in case string references an unknown feature.
      Removed unused var.
      Add support for --hash.
      Removed porting error which flattens property set into strings.
      Fix tag rule for searched libs.
      Resurrect c++-template-depth feature.
      Fix some porting errors in msvc.py. Created a new action which
         allows us to change sources for target as well as decide on
         the actions name at the last moment. This is nee
      Fix some porting errors in common.py.
      Ported boost.jam module.
      Fix syntax errors in rc.py and midl.py.
      Fix a bug causing invalid composite features due to a missing
         expand call.
      Fix mixed slash/backslash in actions.
      Fix some trivial syntax/runtime errors in stage.py.
      Fix increasing indent when running --debug-generators.
This commit is contained in:
Vladimir Prus
2014-01-15 22:53:09 +04:00
14 changed files with 492 additions and 142 deletions

View File

@@ -226,7 +226,7 @@ def valid (names):
if isinstance (names, str):
return valid_one (names)
else:
return [ valid_one (name) for name in names ]
return all([ valid_one (name) for name in names ])
def attributes (feature):
""" Returns the attributes of the given feature.
@@ -525,7 +525,7 @@ def subfeature (feature_name, value_string, subfeature, subvalues, attributes =
def compose (composite_property_s, component_properties_s):
""" Sets the components of the given composite property.
All paremeters are <feature>value strings
All parameters are <feature>value strings
"""
import property
@@ -715,7 +715,7 @@ def add_defaults (properties):
if not p.condition():
handled_features.add(p.feature())
missing_top = [f for f in __all_top_features if not f in handled_features]
missing_top = [f for f in __all_top_features if not f in handled_features]
more = defaults(missing_top)
result.extend(more)
for p in more:

View File

@@ -1060,9 +1060,9 @@ def construct (project, name, target_type, prop_set, sources, top_level=False):
__construct_stack.append (1)
increase_indent ()
if project.manager().logger().on():
increase_indent ()
dout( "*** construct " + target_type)
for s in sources:
@@ -1072,7 +1072,7 @@ def construct (project, name, target_type, prop_set, sources, top_level=False):
result = __construct_really(project, name, target_type, prop_set, sources)
project.manager().logger().decrease_indent()
decrease_indent()
__construct_stack = __construct_stack [1:]

View File

@@ -372,7 +372,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_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 not specified, standalone project will be initialized
"""
if "--debug-loading" in self.manager.argv():
@@ -395,7 +395,6 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
# 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

View File

@@ -22,6 +22,9 @@ __re_colon = re.compile (':')
__re_has_condition = re.compile (r':<')
__re_separate_condition_and_property = re.compile (r'(.*):(<.*)')
__not_applicable_feature='not-applicable-in-this-context'
feature.feature(__not_applicable_feature, [], ['free'])
class Property(object):
__slots__ = ('_feature', '_value', '_condition')
@@ -89,9 +92,24 @@ def create_from_string(s, allow_condition=False,allow_missing_value=False):
else:
raise get_manager().errors()("Invalid property '%s' -- unknown feature" % s)
else:
f = feature.get(feature_name)
if feature.valid(feature_name):
f = feature.get(feature_name)
value = get_value(s)
else:
# In case feature name is not known, it is wrong to do a hard error.
# Feature sets change depending on the toolset. So e.g.
# <toolset-X:version> is an unknown feature when using toolset Y.
#
# Ideally we would like to ignore this value, but most of
# Boost.Build code expects that we return a valid Property. For this
# reason we use a sentinel <not-applicable-in-this-context> feature.
#
# The underlying cause for this problem is that python port Property
# is more strict than its Jam counterpart and must always reference
# a valid feature.
f = feature.get(__not_applicable_feature)
value = s
value = get_value(s)
if not value and not allow_missing_value:
get_manager().errors()("Invalid property '%s' -- no value specified" % s)

View File

@@ -6,6 +6,8 @@
# all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
import hashlib
from b2.util.utility import *
import property, feature, string
import b2.build.feature
@@ -371,7 +373,9 @@ class PropertySet:
is_relative = False
else:
p = self.as_path ()
p = self.as_path()
if hash_maybe:
p = hash_maybe(p)
# Really, an ugly hack. Boost regression test system requires
# specific target paths, and it seems that changing it to handle
@@ -446,4 +450,11 @@ class PropertySet:
def __contains__(self, item):
return item in self.all_set_
def hash(p):
m = hashlib.md5()
m.update(p)
return m.hexdigest()
hash_maybe = hash if "--hash" in bjam.variable("ARGV") else None

View File

@@ -588,8 +588,9 @@ class ProjectTarget (AbstractTarget):
l = get('source-location')
value = os.path.join(l, value)
# Now make the value absolute path
value = os.path.join(os.getcwd(), value)
# Now make the value absolute path. Constants should be in
# platform-native form.
value = os.path.normpath(os.path.join(os.getcwd(), value))
self.constants_[name] = value
bjam.call("set-variable", self.project_module(), name, value)
@@ -1238,10 +1239,8 @@ class BasicTarget (AbstractTarget):
# they are propagated only to direct dependents. We might need
# a more general mechanism, but for now, only those two
# features are special.
raw = subvariant.sources_usage_requirements().raw()
raw = property.change(raw, "<pch-header>", None);
raw = property.change(raw, "<pch-file>", None);
result = result.add(property_set.create(raw))
removed_pch = filter(lambda prop: prop.feature().name() not in ['<pch-header>', '<pch-file>'], subvariant.sources_usage_requirements().all())
result = result.add(property_set.PropertySet(removed_pch))
return result
@@ -1345,7 +1344,7 @@ def apply_default_build(property_set, default_build):
compressed = feature.compress_subproperties(property_set.all())
result = build_request.expand_no_defaults(
b2.build.property_set.create([p]) for p in (compressed + defaults_to_apply))
b2.build.property_set.create(feature.expand([p])) for p in (compressed + defaults_to_apply))
else:
result.append (property_set)

View File

@@ -402,7 +402,7 @@ class AbstractFileTarget (VirtualTarget):
""" Sets the path. When generating target name, it will override any path
computation from properties.
"""
self.path_ = path
self.path_ = os.path.normpath(path)
def action (self):
""" Returns the action.
@@ -465,7 +465,7 @@ class AbstractFileTarget (VirtualTarget):
def actual_name (self):
if not self.actual_name_:
self.actual_name_ = '<' + self.grist() + '>' + self.name_
self.actual_name_ = '<' + self.grist() + '>' + os.path.normpath(self.name_)
return self.actual_name_

279
src/contrib/boost.py Normal file
View File

@@ -0,0 +1,279 @@
# $Id: boost.jam 62249 2010-05-26 19:05:19Z steven_watanabe $
# Copyright 2008 Roland Schwarz
# 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)
# Boost library support module.
#
# This module allows to use the boost library from boost-build projects.
# The location of a boost source tree or the path to a pre-built
# version of the library can be configured from either site-config.jam
# or user-config.jam. If no location is configured the module looks for
# a BOOST_ROOT environment variable, which should point to a boost source
# tree. As a last resort it tries to use pre-built libraries from the standard
# search path of the compiler.
#
# If the location to a source tree is known, the module can be configured
# from the *-config.jam files:
#
# using boost : 1.35 : <root>/path-to-boost-root ;
#
# If the location to a pre-built version is known:
#
# using boost : 1.34
# : <include>/usr/local/include/boost_1_34
# <library>/usr/local/lib
# ;
#
# It is legal to configure more than one boost library version in the config
# files. The version identifier is used to disambiguate between them.
# The first configured version becomes the default.
#
# To use a boost library you need to put a 'use' statement into your
# Jamfile:
#
# import boost ;
#
# boost.use-project 1.35 ;
#
# If you don't care about a specific version you just can omit the version
# part, in which case the default is picked up:
#
# boost.use-project ;
#
# The library can be referenced with the project identifier '/boost'. To
# reference the program_options you would specify:
#
# exe myexe : mysrc.cpp : <library>/boost//program_options ;
#
# Note that the requirements are automatically transformed into suitable
# tags to find the correct pre-built library.
#
import re
import bjam
from b2.build import alias, property, property_set, feature
from b2.manager import get_manager
from b2.tools import builtin, common
from b2.util import bjam_signature, regex
# TODO: This is currently necessary in Python Port, but was not in Jam.
feature.feature('layout', ['system', 'versioned', 'tag'], ['optional'])
feature.feature('root', [], ['optional', 'free'])
feature.feature('build-id', [], ['optional', 'free'])
__initialized = None
__boost_auto_config = property_set.create([property.Property('layout', 'system')])
__boost_configured = {}
__boost_default = None
__build_id = None
__debug = None
def debug():
global __debug
if __debug is None:
__debug = "--debug-configuration" in bjam.variable("ARGV")
return __debug
# Configuration of the boost library to use.
#
# This can either be a boost source tree or
# pre-built libraries. The 'version' parameter must be a valid boost
# version number, e.g. 1.35, if specifying a pre-built version with
# versioned layout. It may be a symbolic name, e.g. 'trunk' if specifying
# a source tree. The options are specified as named parameters (like
# properties). The following paramters are available:
#
# <root>/path-to-boost-root: Specify a source tree.
#
# <include>/path-to-include: The include directory to search.
#
# <library>/path-to-library: The library directory to search.
#
# <layout>system or <layout>versioned.
#
# <build-id>my_build_id: The custom build id to use.
#
def init(version, options = None):
assert(isinstance(version,list))
assert(len(version)==1)
version = version[0]
if version in __boost_configured:
get_manager().errors()("Boost {} already configured.".format(version));
else:
global __boost_default
if debug():
if not __boost_default:
print "notice: configuring default boost library {}".format(version)
print "notice: configuring boost library {}".format(version)
if not __boost_default:
__boost_default = version
properties = []
for option in options:
properties.append(property.create_from_string(option))
__boost_configured[ version ] = property_set.PropertySet(properties)
projects = get_manager().projects()
rules = projects.project_rules()
# Use a certain version of the library.
#
# The use-project rule causes the module to define a boost project of
# searchable pre-built boost libraries, or references a source tree
# of the boost library. If the 'version' parameter is omitted either
# the configured default (first in config files) is used or an auto
# configuration will be attempted.
#
@bjam_signature(([ "version", "?" ], ))
def use_project(version = None):
projects.push_current( projects.current() )
if not version:
version = __boost_default
if not version:
version = "auto_config"
global __initialized
if __initialized:
if __initialized != version:
get_manager().errors()('Attempt to use {} with different parameters'.format('boost'))
else:
if version in __boost_configured:
opts = __boost_configured[ version ]
root = opts.get('<root>' )
inc = opts.get('<include>')
lib = opts.get('<library>')
if debug():
print "notice: using boost library {} {}".format( version, opt.raw() )
global __layout
global __version_tag
__layout = opts.get('<layout>')
if not __layout:
__layout = 'versioned'
__build_id = opts.get('<build-id>')
__version_tag = re.sub("[*\\/:.\"\' ]", "_", version)
__initialized = version
if ( root and inc ) or \
( root and lib ) or \
( lib and not inc ) or \
( not lib and inc ):
get_manager().errors()("Ambiguous parameters, use either <root> or <inlude> with <library>.")
elif not root and not inc:
root = bjam.variable("BOOST_ROOT")
module = projects.current().project_module()
if root:
bjam.call('call-in-module', module, 'use-project', ['boost', root])
else:
projects.initialize(__name__)
if version == '0.0.1':
boost_0_0_1( inc, lib )
else:
boost_std( inc, lib )
else:
get_manager().errors()("Reference to unconfigured boost version.")
projects.pop_current()
rules.add_rule( 'boost.use-project', use_project )
def boost_std(inc = None, lib = None):
# The default definitions for pre-built libraries.
rules.project(
['boost'],
['usage-requirements'] + ['<include>{}'.format(i) for i in inc] + ['<define>BOOST_ALL_NO_LIB'],
['requirements'] + ['<search>{}'.format(l) for l in lib])
# TODO: There should be a better way to add a Python function into a
# project requirements property set.
tag_prop_set = property_set.create([property.Property('<tag>', tag_std)])
attributes = projects.attributes(projects.current().project_module())
attributes.requirements = attributes.requirements.refine(tag_prop_set)
alias('headers')
def boost_lib(lib_name, dyn_link_macro):
if (isinstance(lib_name,str)):
lib_name = [lib_name]
builtin.lib(lib_name, usage_requirements=['<link>shared:<define>{}'.format(dyn_link_macro)])
boost_lib('date_time' , 'BOOST_DATE_TIME_DYN_LINK' )
boost_lib('filesystem' , 'BOOST_FILE_SYSTEM_DYN_LINK' )
boost_lib('graph' , 'BOOST_GRAPH_DYN_LINK' )
boost_lib('graph_parallel' , 'BOOST_GRAPH_DYN_LINK' )
boost_lib('iostreams' , 'BOOST_IOSTREAMS_DYN_LINK' )
boost_lib('locale' , 'BOOST_LOG_DYN_LINK' )
boost_lib('log' , 'BOOST_LOG_DYN_LINK' )
boost_lib('log_setup' , 'BOOST_LOG_DYN_LINK' )
boost_lib('math_tr1' , 'BOOST_MATH_TR1_DYN_LINK' )
boost_lib('math_tr1f' , 'BOOST_MATH_TR1_DYN_LINK' )
boost_lib('math_tr1l' , 'BOOST_MATH_TR1_DYN_LINK' )
boost_lib('math_c99' , 'BOOST_MATH_TR1_DYN_LINK' )
boost_lib('math_c99f' , 'BOOST_MATH_TR1_DYN_LINK' )
boost_lib('math_c99l' , 'BOOST_MATH_TR1_DYN_LINK' )
boost_lib('mpi' , 'BOOST_MPI_DYN_LINK' )
boost_lib('program_options' , 'BOOST_PROGRAM_OPTIONS_DYN_LINK')
boost_lib('python' , 'BOOST_PYTHON_DYN_LINK' )
boost_lib('python3' , 'BOOST_PYTHON_DYN_LINK' )
boost_lib('random' , 'BOOST_RANDOM_DYN_LINK' )
boost_lib('regex' , 'BOOST_REGEX_DYN_LINK' )
boost_lib('serialization' , 'BOOST_SERIALIZATION_DYN_LINK' )
boost_lib('wserialization' , 'BOOST_SERIALIZATION_DYN_LINK' )
boost_lib('signals' , 'BOOST_SIGNALS_DYN_LINK' )
boost_lib('system' , 'BOOST_SYSTEM_DYN_LINK' )
boost_lib('unit_test_framework' , 'BOOST_TEST_DYN_LINK' )
boost_lib('prg_exec_monitor' , 'BOOST_TEST_DYN_LINK' )
boost_lib('test_exec_monitor' , 'BOOST_TEST_DYN_LINK' )
boost_lib('thread' , 'BOOST_THREAD_DYN_DLL' )
boost_lib('wave' , 'BOOST_WAVE_DYN_LINK' )
def boost_0_0_1( inc, lib ):
print "You are trying to use an example placeholder for boost libs." ;
# Copy this template to another place (in the file boost.jam)
# and define a project and libraries modelled after the
# boost_std rule. Please note that it is also possible to have
# a per version taging rule in case they are different between
# versions.
def tag_std(name, type, prop_set):
name = 'boost_' + name
if 'static' in prop_set.get('<link>') and 'windows' in prop_set.get('<target-os>'):
name = 'lib' + name
result = None
if __layout == 'system':
versionRe = re.search('^([0-9]+)_([0-9]+)', __version_tag)
if versionRe and versionRe.group(1) == '1' and int(versionRe.group(2)) < 39:
result = tag_tagged(name, type, prop_set)
else:
result = tag_system(name, type, prop_set)
elif __layout == 'tagged':
result = tag_tagged(name, type, prop_set)
elif __layout == 'versioned':
result = tag_versioned(name, type, prop_set)
else:
get_manager().errors()("Missing layout")
return result
def tag_maybe(param):
return ['-{}'.format(param)] if param else []
def tag_system(name, type, prop_set):
return common.format_name(['<base>'] + tag_maybe(__build_id), name, type, prop_set)
def tag_system(name, type, prop_set):
return common.format_name(['<base>', '<threading>', '<runtime>'] + tag_maybe(__build_id), name, type, prop_set)
def tag_versioned(name, type, prop_set):
return common.format_name(['<base>', '<toolset>', '<threading>', '<runtime>'] + tag_maybe(__version_tag) + tag_maybe(__build_id),
name, type, prop_set)

View File

@@ -66,7 +66,7 @@ def variant (name, parents_or_properties, explicit_properties = []):
p = parents[0]
# TODO: the check may be stricter
if not feature.is_implicit_value (p):
raise BaseException ("Invalid base varaint '%s'" % p)
raise BaseException ("Invalid base variant '%s'" % p)
inherited = __variant_explicit_properties[p]
@@ -196,6 +196,14 @@ def register_globals ():
'on'], # Fail the compilation if there are warnings.
['incidental', 'propagated'])
feature.feature('c++-template-depth',
[str(i) for i in range(64,1024+1,64)] +
[str(i) for i in range(20,1000+1,10)] +
# Maximum template instantiation depth guaranteed for ANSI/ISO C++
# conforming programs.
['17'],
['incidental', 'optional', 'propagated'])
feature.feature ('source', [], ['free', 'dependency', 'incidental'])
feature.feature ('library', [], ['free', 'dependency', 'incidental'])
feature.feature ('file', [], ['free', 'dependency', 'incidental'])
@@ -325,21 +333,15 @@ reset ()
register_globals ()
class SearchedLibTarget (virtual_target.AbstractFileTarget):
def __init__ (self, name, project, shared, real_name, search, action):
def __init__ (self, name, project, shared, search, action):
virtual_target.AbstractFileTarget.__init__ (self, name, 'SEARCHED_LIB', project, action)
self.shared_ = shared
self.real_name_ = real_name
if not self.real_name_:
self.real_name_ = name
self.search_ = search
def shared (self):
return self.shared_
def real_name (self):
return self.real_name_
def search (self):
return self.search_
@@ -506,10 +508,10 @@ class SearchedLibGenerator (generators.Generator):
if real_name:
real_name = real_name[0]
else:
real_nake = name
real_name = name
search = feature.get_values('<search>', properties)
usage_requirements = property_set.create(['<xdll-path>' + p for p in search])
t = SearchedLibTarget(name, project, shared, real_name, search, a)
t = SearchedLibTarget(real_name, project, shared, search, a)
# We return sources for a simple reason. If there's
# lib png : z : <name>png ;
@@ -669,7 +671,7 @@ class LinkingGenerator (generators.Generator):
fst = []
for s in sources:
if type.is_derived(s.type(), 'SEARCHED_LIB'):
n = s.real_name()
n = s.name()
if s.shared():
fsa.append(n)

View File

@@ -16,7 +16,10 @@ import os
import os.path
import sys
from b2.build import feature
# for some reason this fails on Python 2.7(r27:82525)
# from b2.build import virtual_target
import b2.build.virtual_target
from b2.build import feature, type
from b2.util.utility import *
from b2.util import path
@@ -640,13 +643,13 @@ def format_name(format, name, target_type, prop_set):
if grist == '<base>':
result += os.path.basename(name)
elif grist == '<toolset>':
result += join_tag(ungrist(f),
result += join_tag(get_value(f),
toolset_tag(name, target_type, prop_set))
elif grist == '<threading>':
result += join_tag(ungrist(f),
result += join_tag(get_value(f),
threading_tag(name, target_type, prop_set))
elif grist == '<runtime>':
result += join_tag(ungrist(f),
result += join_tag(get_value(f),
runtime_tag(name, target_type, prop_set))
elif grist.startswith('<version:'):
key = grist[len('<version:'):-1]
@@ -654,7 +657,7 @@ def format_name(format, name, target_type, prop_set):
if not version:
version = key
version = __re_version.match(version)
result += join_tag(ungrist(f), version[1] + '_' + version[2])
result += join_tag(get_value(f), version[1] + '_' + version[2])
elif grist.startswith('<property:'):
key = grist[len('<property:'):-1]
property_re = re.compile('<(' + key + ')>')
@@ -670,15 +673,17 @@ def format_name(format, name, target_type, prop_set):
assert(len(p) == 1)
result += join_tag(ungrist(f), p)
else:
result += ungrist(f)
result += f
result = virtual_target.add_prefix_and_suffix(
result = b2.build.virtual_target.add_prefix_and_suffix(
''.join(result), target_type, prop_set)
return result
def join_tag(joiner, tag):
if not joiner: joiner = '-'
return joiner + tag
if tag:
if not joiner: joiner = '-'
return joiner + tag
return ''
__re_toolset_version = re.compile(r"<toolset.*version>(\d+)[.](\d*)")
@@ -687,7 +692,7 @@ def toolset_tag(name, target_type, prop_set):
properties = prop_set.raw()
tools = prop_set.get('<toolset>')
assert(len(tools) == 0)
assert(len(tools) == 1)
tools = tools[0]
if tools.startswith('borland'): tag += 'bcb'
elif tools.startswith('como'): tag += 'como'

View File

@@ -11,7 +11,7 @@ from b2.build.toolset import flags
from b2.build.feature import feature
from b2.manager import get_manager
from b2.tools import builtin, common
from b2.util import regex
from b2.util import regex, utility
def init():
pass
@@ -52,8 +52,8 @@ class MidlScanner(scanner.Scanner):
imported_tlbs = regex.transform(matches, self.re_importlib, [1, 3])
# CONSIDER: the new scoping rule seem to defeat "on target" variables.
g = bjam.call('get-target-variable', target, 'HDRGRIST')
b = os.path.normalize_path(os.path.dirname(binding))
g = bjam.call('get-target-variable', target, 'HDRGRIST')[0]
b = os.path.normpath(os.path.dirname(binding))
# Attach binding of including file to included targets.
# When target is directly created from virtual target
@@ -75,10 +75,10 @@ class MidlScanner(scanner.Scanner):
bjam.call('INCLUDES', [target], all)
bjam.call('DEPENDS', [target], imported_tlbs)
bjam.call('NOCARE', all + imported_tlbs)
engine.set_target_variable(included_angle , 'SEARCH', ungrist(self.includes))
engine.set_target_variable(included_quoted, 'SEARCH', b + ungrist(self.includes))
engine.set_target_variable(imported , 'SEARCH', b + ungrist(self.includes))
engine.set_target_variable(imported_tlbs , 'SEARCH', b + ungrist(self.includes))
engine.set_target_variable(included_angle , 'SEARCH', [utility.get_value(inc) for inc in self.includes])
engine.set_target_variable(included_quoted, 'SEARCH', [utility.get_value(inc) for inc in self.includes])
engine.set_target_variable(imported , 'SEARCH', [utility.get_value(inc) for inc in self.includes])
engine.set_target_variable(imported_tlbs , 'SEARCH', [utility.get_value(inc) for inc in self.includes])
get_manager().scanners().propagate(type.get_scanner('CPP', PropertySet(self.includes)), included_angle + included_quoted)
get_manager().scanners().propagate(self, imported)

View File

@@ -152,7 +152,7 @@ def configure_version_specific(toolset_arg, version, conditions):
# options are off by default. If we are sure that the msvc version is at
# 7.*, add those options explicitly. We can be sure either if user specified
# version 7.* explicitly or if we auto-detected the version ourselves.
if not re.match('^6\\.', version):
if not re.search('^6\\.', version):
toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',conditions, ['/Zc:forScope','/Zc:wchar_t'])
toolset.flags('{}.compile.c++'.format(toolset_arg), 'C++FLAGS',conditions, ['/wd4675'])
@@ -160,7 +160,7 @@ def configure_version_specific(toolset_arg, version, conditions):
# versions have a bug, causing them to emit the deprecation warning even
# with /W0.
toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',extend_conditions(conditions,['<warnings>off']), ['/wd4996'])
if re.match('^[78]\\.', version):
if re.search('^[78]\.', version):
# 64-bit compatibility warning deprecated since 9.0, see
# http://msdn.microsoft.com/en-us/library/yt4xw8fh.aspx
toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',extend_conditions(conditions,['<warnings>all']), ['/Wp64'])
@@ -168,7 +168,7 @@ def configure_version_specific(toolset_arg, version, conditions):
#
# Processor-specific optimization.
#
if re.match('^[67]', version ):
if re.search('^[67]', version ):
# 8.0 deprecates some of the options.
toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>speed','<optimization>space']), ['/Ogiy', '/Gs'])
toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>speed']), ['/Ot'])
@@ -270,76 +270,45 @@ def expand_target_variable(target,var,prefix=None,suffix=None):
return " ".join([ ("" if prefix is None else prefix) + elem + ("" if suffix is None else suffix) for elem in list ])
compile_c_cpp_pch = '''$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" $(YLOPTION)"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" "@($(<[1]:W).cpp:E=#include $(.escaped-double-quote)$(>[1]:D=)$(.escaped-double-quote)$(.nl))" $(.CC.FILTER)'''
# Action for running the C/C++ compiler using precompiled headers. An already
# built source file for compiling the precompiled headers is expected to be
# given as one of the source parameters.
compile_c_cpp_pch_s = '''$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" $(YLOPTION)"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" $(.CC.FILTER)'''
def get_rspline(targets, lang_opt):
result = lang_opt + ' ' + \
expand_target_variable(targets, 'UNDEFS', '-U' ) + ' ' + \
expand_target_variable(targets, 'CFLAGS' ) + ' ' + \
expand_target_variable(targets, 'C++FLAGS' ) + ' ' + \
expand_target_variable(targets, 'OPTIONS' ) + ' -c ' + \
expand_target_variable(targets, 'DEFINES', '\n-D' ) + ' ' + \
expand_target_variable(targets, 'INCLUDES', '\n"-I', '"' )
result = lang_opt + '\n' + \
expand_target_variable(targets, 'UNDEFS' , '\n-U' ) + \
expand_target_variable(targets, 'CFLAGS' , '\n' ) + \
expand_target_variable(targets, 'C++FLAGS', '\n' ) + \
expand_target_variable(targets, 'OPTIONS' , '\n' ) + '\n-c' + \
expand_target_variable(targets, 'DEFINES' , '\n-D' , '\n' ) + \
expand_target_variable(targets, 'INCLUDES', '\n"-I', '"\n' )
bjam.call('set-target-variable', targets, 'CC_RSPLINE', result)
def compile_c(targets, sources = [], properties = None):
get_manager().engine().set_target_variable( targets[1], 'C++FLAGS', '' )
get_manager().engine().set_target_variable( targets[0], 'C++FLAGS', '' )
get_rspline(targets, '-TC')
sources += bjam.call('get-target-variable',targets,'PCH_FILE')
sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
compile_c_cpp(targets,sources)
def compile_c_preprocess(targets, sources = [], properties = None):
get_manager().engine().set_target_variable( target[1], 'C++FLAGS', '' )
get_manager().engine().set_target_variable( targets[0], 'C++FLAGS', '' )
get_rspline(targets, '-TC')
sources += bjam.call('get-target-variable',targets,'PCH_FILE')
sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
preprocess_c_cpp(targets,sources)
def compile_c_pch(targets, sources = [], properties = []):
get_manager().engine().set_target_variable( target[1], 'C++FLAGS', '' )
get_manager().engine().set_target_variable( targets[0], 'C++FLAGS', '' )
get_rspline([targets[0]], '-TC')
get_rspline([targets[1]], '-TC')
get_rspline([targets[2]], '-TC')
pch_source = bjam.call('get-target-variable', targets, 'PCH_SOURCE')
sources += pch_source
if pch_source:
get_manager().engine().set_update_action('compile-c-c++-pch-s', targets, sources, properties)
get_manager().engine().add_dependency(targets,pch_source)
compile_c_cpp_pch_s(targets,sources)
else:
get_manager().engine().set_update_action('compile-c-c++-pch', targets, sources, properties)
compile_c_cpp_pch(targets,sources)
toolset.flags( 'msvc', 'YLOPTION', [], ['-Yl'] )
def compile_cpp(targets,sources=[],properties=None):
get_rspline(targets,'-TP')
sources += bjam.call('get-target-variable',targets,'PCH_FILE')
sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
bjam.call('set-target-variable', targets, 'PCH_FILE', sources)
compile_c_cpp(targets,sources)
def compile_cpp_preprocess(targets,sources=[],properties=None):
get_rspline(targets,'-TP')
sources += bjam.call('get-target-variable',targets,'PCH_FILE')
sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
preprocess_c_cpp(targets,sources)
def compile_cpp_pch(targets,sources=[],properties=None):
get_rspline([targets[0]], '-TP')
get_rspline([targets[1]], '-TP')
get_rspline([targets[2]], '-TP')
pch_source = bjam.call('get-target-variable', targets, 'PCH_SOURCE')
sources += pch_source
if pch_source:
get_manager().engine().set_update_action('compile-c-c++-pch-s', targets, sources, properties)
get_manager().engine().add_dependency(targets,pch_source)
compile_c_cpp_pch_s(targets,sources)
else:
get_manager().engine().set_update_action('compile-c-c++-pch', targets, sources, properties)
compile_c_cpp_pch(targets,sources)
# Action for running the C/C++ compiler without using precompiled headers.
@@ -357,33 +326,68 @@ def compile_cpp_pch(targets,sources=[],properties=None):
# as in this case the compiler must be used to create a single PDB for our library.
#
compile_action = '$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -Fo"$(<[1]:W)" $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" $(.CC.FILTER)'
engine.register_action(
class SetupAction:
def __init__(self, setup_func, function):
self.setup_func = setup_func
self.function = function
def __call__(self, targets, sources, property_set):
assert(callable(self.setup_func))
# This can modify sources.
action_name = self.setup_func(targets, sources, property_set)
# Bjam actions defined from Python have only the command
# to execute, and no associated jam procedural code. So
# passing 'property_set' to it is not necessary.
bjam.call("set-update-action", action_name, targets, sources, [])
if self.function:
self.function(targets, sources, property_set)
def register_setup_action(action_name,setup_function,function=None):
global engine
if engine.actions.has_key(action_name):
raise "Bjam action %s is already defined" % action_name
engine.actions[action_name] = SetupAction(setup_function, function)
engine.register_action('compile-c-c++',
'$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -Fo"$(<[1]:W)" $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" $(.CC.FILTER)''',
bound_list=['PDB_NAME'])
def setup_compile_c_cpp_action(targets, sources, properties):
sources += bjam.call('get-target-variable',targets,'PCH_FILE')
sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
return 'compile-c-c++'
register_setup_action(
'msvc.compile.c',
compile_action,
function=compile_c,
bound_list=['PDB_NAME'])
setup_compile_c_cpp_action,
function=compile_c)
engine.register_action(
register_setup_action(
'msvc.compile.c++',
compile_action,
function=compile_cpp,
bound_list=['PDB_NAME'])
setup_compile_c_cpp_action,
function=compile_cpp)
preprocess_action = '$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -E $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" >"$(<[1]:W)"'
engine.register_action('preprocess-c-c++',
'$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -E $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" >"$(<[1]:W)"',
bound_list=['PDB_NAME'])
engine.register_action(
def setup_preprocess_c_cpp_action(targets, sources, properties):
sources += bjam.call('get-target-variable',targets,'PCH_FILE')
sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
return 'preprocess-c-c++'
register_setup_action(
'msvc.preprocess.c',
preprocess_action,
function=compile_c_preprocess,
bound_list=['PDB_NAME'])
setup_preprocess_c_cpp_action,
function=compile_c_preprocess)
engine.register_action(
register_setup_action(
'msvc.preprocess.c++',
preprocess_action,
function=compile_cpp_preprocess,
bound_list=['PDB_NAME'])
setup_preprocess_c_cpp_action,
function=compile_cpp_preprocess)
def compile_c_cpp(targets,sources=None):
pch_header = bjam.call('get-target-variable',targets[0],'PCH_HEADER')
@@ -400,14 +404,30 @@ def preprocess_c_cpp(targets,sources=None):
# to whatever else it needs to compile, this action also adds a temporary source
# .cpp file used to compile the precompiled headers themselves.
engine.register_action(
engine.register_action('compile-c-c++-pch',
'$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" $(YLOPTION)"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" "@($(<[1]:W).cpp:E=#include "$(>[1]:D=)"\n)" $(.CC.FILTER)')
engine.register_action('compile-c-c++-pch-s',
'$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" $(YLOPTION)"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" $(.CC.FILTER)')
def setup_c_cpp_pch(targets, sources, properties):
pch_source = bjam.call('get-target-variable', targets, 'PCH_SOURCE')
if pch_source:
sources += pch_source
get_manager().engine().add_dependency(targets,pch_source)
return 'compile-c-c++-pch-s'
else:
return 'compile-c-c++-pch'
register_setup_action(
'msvc.compile.c.pch',
None, # action set by the function
setup_c_cpp_pch,
function=compile_c_pch)
engine.register_action(
register_setup_action(
'msvc.compile.c++.pch',
None, # action set by the function
setup_c_cpp_pch,
function=compile_cpp_pch)
@@ -537,7 +557,6 @@ $(LIBRARIES)
class MsvcPchGenerator(pch.PchGenerator):
# Inherit the __init__ method
def run_pch(self, project, name, prop_set, sources):
# Find the header in sources. Ignore any CPP sources.
pch_header = None
@@ -548,18 +567,30 @@ class MsvcPchGenerator(pch.PchGenerator):
elif type.is_derived(s.type(), 'CPP') or type.is_derived(s.type(), 'C'):
pch_source = s
if not pch-header:
if not pch_header:
raise RuntimeError( "can not build pch without pch-header" )
# If we do not have the PCH source - that is fine. We will just create a
# temporary .cpp file in the action.
temp_prop_set = property_set.create([Property('pch-source',pch_source)]+prop_set.all())
generated = Generator.run(project,name,temp_prop_set,pch_header)
properties = prop_set.all()
# Passing of <pch-source> is a dirty trick, needed because
# non-composing generators with multiple inputs are subtly
# broken. For more detailed information see:
# https://zigzag.cs.msu.su:7813/boost.build/ticket/111
if pch_source:
properties.append(Property('pch-source',pch_source))
generated = Generator.run(self,project,name,property_set.create(properties),[pch_header])
pch_file = None
for g in generated:
if type.is_derived(g.type(), 'PCH'):
pch_file = g
return property_set.create([Property('pch-header',pch_header),Property('pch-file',pch_file)]+generated)
result_props = []
if pch_header:
result_props.append(Property('pch-header', pch_header))
if pch_file:
result_props.append(Property('pch-file', pch_file))
return property_set.PropertySet(result_props), generated
################################################################################
@@ -577,9 +608,9 @@ def auto_detect_toolset_versions():
versionVarName = '__version_{}_reg'.format(version.replace('.','_'))
if versionVarName in globals():
vc_path = None
for x in [ '', 'Wow6432Node\\' ]:
for x64elt in [ '', 'Wow6432Node\\' ]:
try:
with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\{}{}'.format(x, globals()[versionVarName])) as reg_key:
with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\{}Microsoft\\{}'.format(x64elt, globals()[versionVarName])) as reg_key:
vc_path = _winreg.QueryValueEx(reg_key, "ProductDir")[0]
except:
pass
@@ -830,12 +861,12 @@ def configure_really(version=None, options=[]):
cpu_assembler = locals()['default_assembler_{}'.format(c)]
toolset.flags('msvc.compile', '.CC' , cpu_conditions, ['{}{} /Zm800 -nologo' .format(setup_script, compiler)])
toolset.flags('msvc.compile', '.RC' , cpu_conditions, ['{}{} -nologo' .format(setup_script, resource_compiler)])
toolset.flags('msvc.compile', '.ASM', cpu_conditions, ['{}{} ' .format(setup_script, cpu_assembler)])
toolset.flags('msvc.compile', '.RC' , cpu_conditions, ['{}{}' .format(setup_script, resource_compiler)])
toolset.flags('msvc.compile', '.ASM', cpu_conditions, ['{}{} -nologo' .format(setup_script, cpu_assembler)])
toolset.flags('msvc.link' , '.LD' , cpu_conditions, ['{}{} /NOLOGO /INCREMENTAL:NO'.format(setup_script, linker)])
toolset.flags('msvc.archive', '.LD' , cpu_conditions, ['{}{} /lib /NOLOGO' .format(setup_script, linker)])
toolset.flags('msvc.compile', '.IDL', cpu_conditions, ['{}{} ' .format(setup_script, idl_compiler)])
toolset.flags('msvc.compile', '.MC' , cpu_conditions, ['{}{} ' .format(setup_script, mc_compiler)])
toolset.flags('msvc.compile', '.IDL', cpu_conditions, ['{}{}' .format(setup_script, idl_compiler)])
toolset.flags('msvc.compile', '.MC' , cpu_conditions, ['{}{}' .format(setup_script, mc_compiler)])
toolset.flags('msvc.link' , '.MT' , cpu_conditions, ['{}{} -nologo' .format(setup_script, manifest_tool)])
if cc_filter:
@@ -1061,10 +1092,10 @@ def register_toolset_really():
toolset.flags('msvc.link', 'OPTIONS', [], ['<linkflags>'])
toolset.flags('msvc.link', 'LINKPATH', [], ['<library-path>'])
toolset.flags('msvc.link', 'FINDLIBS_ST', ['<find-static-library>'])
toolset.flags('msvc.link', 'FINDLIBS_SA', ['<find-shared-library>'])
toolset.flags('msvc.link', 'LIBRARY_OPTION', ['<toolset>msvc'])
toolset.flags('msvc.link', 'LIBRARIES_MENTIONED_BY_FILE', ['<library-file>'])
toolset.flags('msvc.link', 'FINDLIBS_ST', [], ['<find-static-library>'])
toolset.flags('msvc.link', 'FINDLIBS_SA', [], ['<find-shared-library>'])
toolset.flags('msvc.link', 'LIBRARY_OPTION', ['<toolset>msvc'], [''])
toolset.flags('msvc.link', 'LIBRARIES_MENTIONED_BY_FILE', [], ['<library-file>'])
toolset.flags('msvc.archive', 'AROPTIONS', [], ['<archiveflags>'])

View File

@@ -21,11 +21,17 @@
##import scanner ;
##import toolset : flags ;
import os.path
import re
import bjam
from b2.build import type, toolset, generators, scanner, feature
from b2.tools import builtin
from b2.util import regex
from b2.build.toolset import flags
from b2.manager import get_manager
from b2.util import utility
__debug = None
@@ -135,7 +141,7 @@ class ResScanner(scanner.Scanner):
"[ ]+([^ \"]+|\"[^\"]+\"))|(#include[ ]*(<[^<]+>|\"[^\"]+\")))" ;
def process(self, target, matches, binding):
binding = binding[0]
angle = regex.transform(matches, "#include[ ]*<([^<]+)>")
quoted = regex.transform(matches, "#include[ ]*\"([^\"]+)\"")
res = regex.transform(matches,
@@ -147,11 +153,11 @@ class ResScanner(scanner.Scanner):
# IDR_MAINFRAME ICON "res\\icon.ico"
#
# so we have to replace double backslashes to single ones.
res = [ re.sub(r'\\\\', '/', match) for match in res ]
res = [ re.sub(r'\\\\', '/', match) for match in res if match is not None ]
# CONSIDER: the new scoping rule seem to defeat "on target" variables.
g = bjam.call('get-target-variable', target, 'HDRGRIST')
b = os.path.normalize_path(os.path.dirname(binding))
g = bjam.call('get-target-variable', target, 'HDRGRIST')[0]
b = os.path.normpath(os.path.dirname(binding))
# Attach binding of including file to included targets.
# When target is directly created from virtual target
@@ -177,9 +183,9 @@ class ResScanner(scanner.Scanner):
engine.add_dependency(target, res)
bjam.call('NOCARE', all + res)
engine.set_target_variable(angle, 'SEARCH', ungrist(self.includes))
engine.set_target_variable(quoted, 'SEARCH', b + ungrist(self.includes))
engine.set_target_variable(res, 'SEARCH', b + ungrist(self.includes)) ;
engine.set_target_variable(angle, 'SEARCH', [utility.get_value(inc) for inc in self.includes])
engine.set_target_variable(quoted, 'SEARCH', [b + utility.get_value(inc) for inc in self.includes])
engine.set_target_variable(res, 'SEARCH', [b + utility.get_value(inc) for inc in self.includes])
# Just propagate current scanner to includes, in a hope
# that includes do not change scanners.

View File

@@ -170,7 +170,7 @@ class InstallTargetClass(targets.BasicTarget):
def collect_targets(self, targets):
s = [t.creating_subvariant() for t in targets]
s = unique(s)
s = unique(filter(lambda l: l != None,s))
result = set(targets)
for i in s:
@@ -251,7 +251,7 @@ class InstalledExeGenerator(generators.Generator):
else:
# See if the dll-path properties are not changed during
# install. If so, copy, don't relink.
need_relink = ps.get('dll-path') != source[0].action().properties().get('dll-path')
need_relink = source[0].action() and ps.get('dll-path') != source[0].action().properties().get('dll-path')
if need_relink:
return [relink_file(project, source, ps)]
@@ -280,7 +280,7 @@ class InstalledSharedLibGenerator(generators.Generator):
a = source.action()
if not a:
# Non-derived file, just copy.
copied = copy_file(project, source, ps)
copied = copy_file(project, None, source, ps)
else:
need_relink = ps.get('dll-path') != source.action().properties().get('dll-path')