mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 00:52:16 +00:00
Merge Boost.Build from the trunk.
[SVN r86768]
This commit is contained in:
@@ -123,10 +123,71 @@ rule print-configure-checks-summary ( )
|
||||
}
|
||||
}
|
||||
|
||||
# Attempts to build a set of virtual targets
|
||||
rule try-build ( targets * : ps : what : retry ? )
|
||||
{
|
||||
local cache-name = $(what) [ $(ps).raw ] ;
|
||||
cache-name = $(cache-name:J=-) ;
|
||||
local value = [ config-cache.get $(cache-name) ] ;
|
||||
|
||||
local result ;
|
||||
local jam-targets ;
|
||||
|
||||
# Attempt to build a metatarget named by 'metatarget-reference' in context of
|
||||
# 'project' with properties 'ps'. Returns non-empty value if build is OK.
|
||||
#
|
||||
for local t in $(targets)
|
||||
{
|
||||
jam-targets += [ $(t).actualize ] ;
|
||||
}
|
||||
|
||||
if $(value)
|
||||
{
|
||||
local x = [ PAD " - $(what)" : $(.width) ] ;
|
||||
if $(value) = true
|
||||
{
|
||||
.$(what)-supported.$(ps) = yes ;
|
||||
result = true ;
|
||||
log-check-result "$(x) : yes (cached)" ;
|
||||
}
|
||||
else
|
||||
{
|
||||
log-check-result "$(x) : no (cached)" ;
|
||||
}
|
||||
}
|
||||
else if ! UPDATE_NOW in [ RULENAMES ]
|
||||
{
|
||||
# Cannot determine. Assume existance.
|
||||
}
|
||||
else
|
||||
{
|
||||
local x = [ PAD " - $(what)" : $(.width) ] ;
|
||||
if [ UPDATE_NOW $(jam-targets) :
|
||||
$(.log-fd) : ignore-minus-n : ignore-minus-q ]
|
||||
{
|
||||
.$(what)-supported.$(ps) = yes ;
|
||||
result = true ;
|
||||
log-check-result "$(x) : yes" ;
|
||||
}
|
||||
else
|
||||
{
|
||||
log-check-result "$(x) : no" ;
|
||||
}
|
||||
}
|
||||
if ! $(value)
|
||||
{
|
||||
if $(result)
|
||||
{
|
||||
config-cache.set $(cache-name) : true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
config-cache.set $(cache-name) : false ;
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
# Attempt to build a metatarget named by 'metatarget-reference'
|
||||
# in context of 'project' with properties 'ps'.
|
||||
# Returns non-empty value if build is OK.
|
||||
rule builds-raw ( metatarget-reference : project : ps : what : retry ? )
|
||||
{
|
||||
local result ;
|
||||
@@ -135,64 +196,14 @@ rule builds-raw ( metatarget-reference : project : ps : what : retry ? )
|
||||
{
|
||||
.$(what)-tested.$(ps) = true ;
|
||||
|
||||
local cache-name = $(what) [ $(ps).raw ] ;
|
||||
cache-name = $(cache-name:J=-) ;
|
||||
local value = [ config-cache.get $(cache-name) ] ;
|
||||
|
||||
local targets = [ targets.generate-from-reference
|
||||
$(metatarget-reference) : $(project) : $(ps) ] ;
|
||||
|
||||
local jam-targets ;
|
||||
for local t in $(targets[2-])
|
||||
{
|
||||
jam-targets += [ $(t).actualize ] ;
|
||||
}
|
||||
|
||||
if $(value)
|
||||
{
|
||||
local x = [ PAD " - $(what)" : $(.width) ] ;
|
||||
if $(value) = true
|
||||
{
|
||||
.$(what)-supported.$(ps) = yes ;
|
||||
result = true ;
|
||||
log-check-result "$(x) : yes (cached)" ;
|
||||
}
|
||||
else
|
||||
{
|
||||
log-check-result "$(x) : no (cached)" ;
|
||||
}
|
||||
}
|
||||
else if ! UPDATE_NOW in [ RULENAMES ]
|
||||
{
|
||||
# Cannot determine. Assume existance.
|
||||
}
|
||||
else
|
||||
{
|
||||
local x = [ PAD " - $(what)" : $(.width) ] ;
|
||||
if [ UPDATE_NOW $(jam-targets) :
|
||||
$(.log-fd) : ignore-minus-n : ignore-minus-q ]
|
||||
{
|
||||
.$(what)-supported.$(ps) = yes ;
|
||||
result = true ;
|
||||
log-check-result "$(x) : yes" ;
|
||||
}
|
||||
else
|
||||
{
|
||||
log-check-result "$(x) : no" ;
|
||||
}
|
||||
}
|
||||
if ! $(value)
|
||||
{
|
||||
if $(result)
|
||||
{
|
||||
config-cache.set $(cache-name) : true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
config-cache.set $(cache-name) : false ;
|
||||
}
|
||||
}
|
||||
result = [ try-build $(targets[2-]) : $(ps) : $(what) : $(retry) ] ;
|
||||
.$(what)-supported.$(ps) = $(result) ;
|
||||
|
||||
return $(result) ;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -667,7 +667,7 @@ class generator
|
||||
result += $(source) ;
|
||||
}
|
||||
}
|
||||
return [ sequence.unique $(result) ] ;
|
||||
return [ sequence.unique $(result) : stable ] ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
import numbers ;
|
||||
|
||||
|
||||
.major = "2011" ;
|
||||
.minor = "12" ;
|
||||
.major = "2013" ;
|
||||
.minor = "05" ;
|
||||
|
||||
|
||||
rule boost-build ( )
|
||||
|
||||
@@ -1324,8 +1324,9 @@ class subvariant
|
||||
for local t in $(self.created-targets)
|
||||
{
|
||||
# Skip targets of the wrong type.
|
||||
local type = [ $(t).type ] ;
|
||||
if ! $(target-type) ||
|
||||
[ type.is-derived [ $(t).type ] $(target-type) ]
|
||||
( $(type) && [ type.is-derived $(type) $(target-type) ] )
|
||||
{
|
||||
result = [ sequence.merge $(result) : [ $(t).path ] ] ;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
<section id="bbv2.arch.overview">
|
||||
<title>Overview</title>
|
||||
|
||||
<!-- FIXME: the below does not mention engine at all, making rest of the
|
||||
text confusing. Things like 'kernel' and 'util' don't have to be
|
||||
mentioned at all. -->
|
||||
<para>
|
||||
Boost.Build implementation is structured in four different components:
|
||||
"kernel", "util", "build" and "tools". The first two are relatively
|
||||
@@ -58,6 +61,7 @@
|
||||
from them.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -78,13 +82,14 @@
|
||||
<listitem><para>
|
||||
A generator appropriate for the build properties is selected and its
|
||||
<code>run</code> method is called. The method returns a list of virtual
|
||||
targets
|
||||
targets.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
The targets are returned to the top level code. They are converted
|
||||
into bjam targets (via <code>virtual-target.actualize</code>) and passed
|
||||
to bjam for building.
|
||||
The virtual targets are returned to the top level code, and for each instance,
|
||||
the <literal>actualize</literal> method is called to setup nodes and updating
|
||||
actions in the depenendency graph kepts inside Boost.Build engine. This dependency
|
||||
graph is then updated, which runs necessary commands.
|
||||
</para></listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
@@ -163,11 +168,11 @@ lib a : a.cpp : <toolset>gcc ;
|
||||
<title>Virtual targets</title>
|
||||
|
||||
<para>
|
||||
Virtual targets correspond to atomic updatable entities. Each virtual
|
||||
Virtual targets are atomic updatable entities. Each virtual
|
||||
target can be assigned an updating action -- instance of the
|
||||
<code>action</code> class. The action class, in turn, contains a list of
|
||||
source targets, properties, and a name of an bjam action which should be
|
||||
executed.
|
||||
source targets, properties, and a name of an action which
|
||||
should be executed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -178,12 +183,13 @@ lib a : a.cpp : <toolset>gcc ;
|
||||
already been created. In that case, the preexisting target is returned.
|
||||
</para>
|
||||
|
||||
<!-- FIXME: the below 2 para are rubbish, must be totally rewritten. -->
|
||||
<para>
|
||||
When all virtual targets are produced, they are "actualized". This means
|
||||
that the real file names are computed, and the commands that should be run
|
||||
are generated. This is done by the <code>virtual-target.actualize</code>
|
||||
and <code>action.actualize</code> methods. The first is conceptually
|
||||
simple, while the second needs additional explanation. Commands in bjam
|
||||
simple, while the second needs additional explanation. Commands in Boost.Build
|
||||
are generated in a two-stage process. First, a rule with an appropriate
|
||||
name (for example "gcc.compile") is called and is given a list of target
|
||||
names. The rule sets some variables, like "OPTIONS". After that, the
|
||||
@@ -308,20 +314,14 @@ lib a : a.cpp : <toolset>gcc ;
|
||||
<para>
|
||||
As stated above, it is possible to compile a C++ file multiple times,
|
||||
using different include paths. Therefore, include dependencies for those
|
||||
compilations can be different. The problem is that bjam does not allow
|
||||
multiple scans of the same target.
|
||||
compilations can be different. The problem is that Boost.Build engine does
|
||||
not allow multiple scans of the same target. To solve that, we pass the
|
||||
scanner object when calling <literal>virtual-target.actualize</literal>
|
||||
and it creates different engine targets for different scanners.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The solution in Boost.Build is straightforward. When a virtual target is
|
||||
converted to a bjam target (via the
|
||||
<literal>virtual-target.actualize</literal> method), we specify the
|
||||
scanner object to be used. The actualize method will create different bjam
|
||||
targets for different scanners.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For each Boost Jam target created with a scanner is created, a
|
||||
For each engine target created with a specified scanner, a
|
||||
corresponding one is created without it. The updating action is
|
||||
associated with the scanner-less target, and the target with the scanner
|
||||
is made to depend on it. That way if sources for that action are touched,
|
||||
@@ -355,7 +355,7 @@ a.cpp (installed copy) <--(copy) ----------------------- a.cpp (no scanner
|
||||
<listitem><simpara>
|
||||
If when compiling "a.cpp" there is an include of "a.h", the "dir"
|
||||
directory is on the include path, and a target called "a.h" will be
|
||||
generated in "dir", then bjam should discover the include, and create
|
||||
generated in "dir", then Boost.Build should discover the include, and create
|
||||
"a.h" before compiling "a.cpp".
|
||||
</simpara></listitem>
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ local t = [ new file-target $(name) : CPP : $(project) : $(a) ] ;
|
||||
once with the same properties. Returning to different instance of <classname>file-target</classname>
|
||||
that correspond to the same file clearly will result in problems. Therefore, whenever
|
||||
returning targets you should pass them via the <code>virtual-target.register</code>
|
||||
function, besides allowing Boost Build to track which virtual targets
|
||||
function, besides allowing Boost.Build to track which virtual targets
|
||||
got created for each metatarget, this will also replace targets with previously created identical
|
||||
ones, as necessary.<footnote><para>This create-then-register pattern is caused by limitations
|
||||
of the Boost.Jam language. Python port is likely to never create duplicate targets.</para></footnote>
|
||||
@@ -613,7 +613,7 @@ actions inline-file
|
||||
and the target type. When invoked, the generator will create a target
|
||||
of type <literal>CPP</literal> with a source target of
|
||||
type <literal>VERBATIM</literal> as the only source. But what command
|
||||
will be used to actually generate the file? In bjam, actions are
|
||||
will be used to actually generate the file? In Boost.Build, actions are
|
||||
specified using named "actions" blocks and the name of the action
|
||||
block should be specified when creating targets. By convention,
|
||||
generators use the same name of the action block as their own id. So,
|
||||
@@ -888,7 +888,7 @@ actions inline-file
|
||||
|
||||
<listitem><para>if a feature is used to refer to a path relative
|
||||
to the Jamfile, it must be a “path” feature. Such features will
|
||||
also get their values automatically converted to Boost Build's
|
||||
also get their values automatically converted to Boost.Build's
|
||||
internal path representation. For example, <code>include</code>
|
||||
is a path feature.</para></listitem>
|
||||
|
||||
@@ -970,7 +970,7 @@ actions link bind DEF_FILE
|
||||
|
||||
|
||||
<para> Note the <code>bind DEF_FILE</code> part. It tells
|
||||
bjam to translate the internal target name in
|
||||
Boost.Build to translate the internal target name in
|
||||
<varname>DEF_FILE</varname> to a corresponding filename in
|
||||
the <code>link</code> action. Without it the expansion of
|
||||
<code>$(DEF_FILE)</code> would be a strange symbol that is
|
||||
@@ -981,8 +981,7 @@ actions link bind DEF_FILE
|
||||
targets in general, only source files." I'm not sure
|
||||
what I meant by that; maybe you can figure it out. -->
|
||||
<para>
|
||||
We are almost done, but we should stop for a small workaround. Add the following
|
||||
code to msvc.jam
|
||||
We are almost done, except for adding the follwing code to <filename>msvc.jam</filename>:
|
||||
|
||||
<programlisting>
|
||||
rule link
|
||||
@@ -992,8 +991,8 @@ rule link
|
||||
</programlisting>
|
||||
<!-- You *must* explain the part in [...] above. It's completely opaque to the casual reader -->
|
||||
|
||||
This is needed to accomodate some bug in bjam, which hopefully
|
||||
will be fixed one day.
|
||||
This is a workaround for a bug in Boost.Build engine, which will hopefully
|
||||
be fixed one day.
|
||||
<!-- This is *NOT* a bug!! Anyway, BBv2 shouild handle this automatically. Why doesn't it? -->
|
||||
</para></listitem>
|
||||
|
||||
|
||||
@@ -446,6 +446,37 @@ alias mylib ;
|
||||
</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="bbv2.faq.names">
|
||||
<title>
|
||||
What is the difference between Boost.Build,
|
||||
<filename>b2</filename>, <filename>bjam</filename> and Perforce Jam?
|
||||
</title>
|
||||
|
||||
<para>
|
||||
Boost.Build is the name of the complete build system. The executable that runs
|
||||
it is <filename>b2</filename>. That executable is written in C and implements
|
||||
performance-critical algorithms, like traversal of dependency graph and executing
|
||||
commands. It also implements an interpreted language used to implement the rest of
|
||||
Boost.Build. This executable is formally called "Boost.Build engine".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The Boost.Build engine is derived from an earlier build tool called Perforce Jam. Originally,
|
||||
there were just minor changes, and the filename was <filename>bjam</filename>. Later on,
|
||||
with more and more changes, the similarity of names because a disservice to users, and as of
|
||||
Boost 1.47.0, the official name of the executable was changed to <filename>b2</filename>.
|
||||
A copy named <filename>bjam</filename> is still created for compatibility,
|
||||
but you are encouraged to use the new name in all cases.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Perforce Jam was an important foundation, and we gratefully acknowledge its influence,
|
||||
but for users today, these tools share only some basics of the interpreted language.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
<!--
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
</para>
|
||||
|
||||
<para>Placing Boost.Build into <filename>/usr/share/boost-build</filename>
|
||||
will make sure that <command>bjam</command> will find Boost.Build
|
||||
will make sure that <command>b2</command> will find Boost.Build
|
||||
without any additional setup.</para>
|
||||
</listitem>
|
||||
|
||||
@@ -120,7 +120,7 @@ using gcc ;
|
||||
</para>
|
||||
|
||||
<para>If those guidelines are met, users will be able to invoke
|
||||
<command>bjam</command> without any explicit configuration.
|
||||
<command>b2/command> without any explicit configuration.
|
||||
</para>
|
||||
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Boost.Build actually consists of two parts - Boost.Jam, a build engine
|
||||
Boost.Build has two parts&emdash;a build engine
|
||||
with its own interpreted language, and Boost.Build itself, implemented in
|
||||
Boost.Jam's language. The chain of events when you type
|
||||
that language. The chain of events when you type
|
||||
<command>b2</command> on the command line is as follows:
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
@@ -1183,7 +1183,9 @@ obj main : main.cpp : <optimization>off ;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para id="bbv2.overview.targets.requirements.conditional">Sometimes, particular relationships need to be maintained
|
||||
<para id="bbv2.overview.targets.requirements.conditional">
|
||||
<indexterm><primary>requirements</primary><secondary>conditional</secondary></indexterm>
|
||||
Sometimes, particular relationships need to be maintained
|
||||
among a target's build properties. This can be achieved with
|
||||
<firstterm>conditional
|
||||
requirements</firstterm>. For example, you might want to set
|
||||
@@ -1212,6 +1214,7 @@ lib network : network.cpp
|
||||
</para>
|
||||
|
||||
<para id="bbv2.overview.targets.requirements.indirect">
|
||||
<indexterm><primary>requirements</primary><secondary>indirect</secondary></indexterm>
|
||||
A more powerful variant of conditional requirements
|
||||
is <firstterm>indirect conditional requirements</firstterm>.
|
||||
You can provide a rule that will be called with the current build properties and can compute additional properties
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
future or FAQ completely supercedes it. -->
|
||||
|
||||
<appendix id="bbv2.recipies">
|
||||
<title>Boost Build System V2 recipes</title>
|
||||
<title>Boost.Build System V2 recipes</title>
|
||||
|
||||
</appendix>
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
<section id="bbv2.reference.init">
|
||||
<title>Initialization</title>
|
||||
|
||||
<para>bjam's first job upon startup is to load the Jam code that
|
||||
implements the build system. To do this, it searches for a file
|
||||
<para>
|
||||
Immediately upon starting, the Boost.Build engine (<command>b2</command>)
|
||||
loads the Jam code that implements the build system. To do this, it searches for a file
|
||||
called <filename>boost-build.jam</filename>, first in the invocation directory, then
|
||||
in its parent and so forth up to the filesystem root, and finally
|
||||
in the directories specified by the environment variable
|
||||
@@ -741,7 +742,7 @@ path-constant DATA : data/a.txt ;
|
||||
|
||||
<para>
|
||||
<emphasis role="bold">Note:</emphasis> Due to some internal details
|
||||
in the current Boost Build implementation it is not possible to have
|
||||
in the current Boost.Build implementation it is not possible to have
|
||||
features whose valid values are all positive integer. As a
|
||||
workaround a large set of allowed values has been defined for this
|
||||
feature and, if a different one is needed, user can easily add it by
|
||||
|
||||
@@ -447,8 +447,8 @@ rule run ( sources + : args * : input-files * : requirements * : target-name ?
|
||||
<varname>args</varname> and <varname>input-files</varname> as command-line
|
||||
arguments. The <varname>args</varname> parameter is passed verbatim and
|
||||
the values of the <varname>input-files</varname> parameter are treated as
|
||||
paths relative to containing Jamfile, and are adjusted if <command>bjam
|
||||
</command> is invoked from a different directory. The
|
||||
paths relative to containing Jamfile, and are adjusted if <command>b2</command>
|
||||
is invoked from a different directory. The
|
||||
<code>run-fail</code> rule is identical to the <code>run</code> rule,
|
||||
except that it expects that the run fails.
|
||||
</para>
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef OS_NT
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(USE_EXECUNIX)
|
||||
# include <sys/types.h>
|
||||
# include <sys/wait.h>
|
||||
@@ -425,6 +429,11 @@ void load_builtins()
|
||||
char const * args [] = { "path", 0 };
|
||||
bind_builtin( "MAKEDIR", builtin_makedir, 0, args );
|
||||
}
|
||||
|
||||
{
|
||||
const char * args [] = { "path", 0 };
|
||||
bind_builtin( "READLINK", builtin_readlink, 0, args );
|
||||
}
|
||||
|
||||
/* Initialize builtin modules. */
|
||||
init_set();
|
||||
@@ -1827,6 +1836,94 @@ LIST * builtin_makedir( FRAME * frame, int flags )
|
||||
: list_new( object_copy( list_front( path ) ) );
|
||||
}
|
||||
|
||||
LIST *builtin_readlink( FRAME * frame, int flags )
|
||||
{
|
||||
const char * path = object_str( list_front( lol_get( frame->args, 0 ) ) );
|
||||
#ifdef OS_NT
|
||||
|
||||
/* This struct is declared in ntifs.h which is
|
||||
* part of the Windows Driver Kit.
|
||||
*/
|
||||
typedef struct _REPARSE_DATA_BUFFER {
|
||||
ULONG ReparseTag;
|
||||
USHORT ReparseDataLength;
|
||||
USHORT Reserved;
|
||||
union {
|
||||
struct {
|
||||
USHORT SubstituteNameOffset;
|
||||
USHORT SubstituteNameLength;
|
||||
USHORT PrintNameOffset;
|
||||
USHORT PrintNameLength;
|
||||
ULONG Flags;
|
||||
WCHAR PathBuffer[ 1 ];
|
||||
} SymbolicLinkReparseBuffer;
|
||||
struct {
|
||||
USHORT SubstituteNameOffset;
|
||||
USHORT SubstituteNameLength;
|
||||
USHORT PrintNameOffset;
|
||||
USHORT PrintNameLength;
|
||||
WCHAR PathBuffer[ 1 ];
|
||||
} MountPointReparseBuffer;
|
||||
struct {
|
||||
UCHAR DataBuffer[ 1 ];
|
||||
} GenericReparseBuffer;
|
||||
};
|
||||
} REPARSE_DATA_BUFFER;
|
||||
|
||||
HANDLE hLink = CreateFileA( path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL );
|
||||
DWORD n;
|
||||
union {
|
||||
REPARSE_DATA_BUFFER reparse;
|
||||
char data[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
||||
} buf;
|
||||
int okay = DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, &buf, sizeof(buf), &n, NULL);
|
||||
|
||||
CloseHandle( hLink );
|
||||
|
||||
if (okay && buf.reparse.ReparseTag == IO_REPARSE_TAG_SYMLINK )
|
||||
{
|
||||
int index = buf.reparse.SymbolicLinkReparseBuffer.SubstituteNameOffset / 2;
|
||||
int length = buf.reparse.SymbolicLinkReparseBuffer.SubstituteNameLength / 2;
|
||||
char cbuf[MAX_PATH + 1];
|
||||
int numchars = WideCharToMultiByte( CP_ACP, 0, buf.reparse.SymbolicLinkReparseBuffer.PathBuffer + index, length, cbuf, sizeof(cbuf), NULL, NULL );
|
||||
if( numchars >= sizeof(cbuf) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
cbuf[numchars] = '\0';
|
||||
return list_new( object_new( cbuf ) );
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
char static_buf[256];
|
||||
char * buf = static_buf;
|
||||
size_t bufsize = 256;
|
||||
LIST * result = 0;
|
||||
while (1) {
|
||||
ssize_t len = readlink( path, buf, bufsize );
|
||||
if ( len < 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if ( len < bufsize )
|
||||
{
|
||||
buf[ len ] = '\0';
|
||||
result = list_new( object_new( buf ) );
|
||||
break;
|
||||
}
|
||||
if ( buf != static_buf )
|
||||
BJAM_FREE( buf );
|
||||
bufsize *= 2;
|
||||
buf = BJAM_MALLOC( bufsize );
|
||||
}
|
||||
|
||||
if ( buf != static_buf )
|
||||
BJAM_FREE( buf );
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ LIST *builtin_pad( FRAME * frame, int flags );
|
||||
LIST *builtin_precious( FRAME * frame, int flags );
|
||||
LIST *builtin_self_path( FRAME * frame, int flags );
|
||||
LIST *builtin_makedir( FRAME * frame, int flags );
|
||||
LIST *builtin_readlink( FRAME * frame, int flags );
|
||||
|
||||
void backtrace( FRAME *frame );
|
||||
extern int last_update_now_status;
|
||||
|
||||
@@ -23,6 +23,37 @@
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
/*
|
||||
* cmdlist_append_cmd
|
||||
*/
|
||||
CMDLIST * cmdlist_append_cmd( CMDLIST * l, CMD * cmd )
|
||||
{
|
||||
CMDLIST * result = (CMDLIST *)BJAM_MALLOC( sizeof( CMDLIST ) );
|
||||
result->iscmd = 1;
|
||||
result->next = l;
|
||||
result->impl.cmd = cmd;
|
||||
return result;
|
||||
}
|
||||
|
||||
CMDLIST * cmdlist_append_target( CMDLIST * l, TARGET * t )
|
||||
{
|
||||
CMDLIST * result = (CMDLIST *)BJAM_MALLOC( sizeof( CMDLIST ) );
|
||||
result->iscmd = 0;
|
||||
result->next = l;
|
||||
result->impl.t = t;
|
||||
return result;
|
||||
}
|
||||
|
||||
void cmdlist_free( CMDLIST * l )
|
||||
{
|
||||
while ( l )
|
||||
{
|
||||
CMDLIST * tmp = l->next;
|
||||
BJAM_FREE( l );
|
||||
l = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd_new() - return a new CMD.
|
||||
*/
|
||||
@@ -37,6 +68,10 @@ CMD * cmd_new( RULE * rule, LIST * targets, LIST * sources, LIST * shell )
|
||||
cmd->shell = shell;
|
||||
cmd->next = 0;
|
||||
cmd->noop = 0;
|
||||
cmd->asynccnt = 1;
|
||||
cmd->status = 0;
|
||||
cmd->lock = NULL;
|
||||
cmd->unlock = NULL;
|
||||
|
||||
lol_init( &cmd->args );
|
||||
lol_add( &cmd->args, targets );
|
||||
@@ -62,9 +97,11 @@ CMD * cmd_new( RULE * rule, LIST * targets, LIST * sources, LIST * shell )
|
||||
|
||||
void cmd_free( CMD * cmd )
|
||||
{
|
||||
cmdlist_free( cmd->next );
|
||||
lol_free( &cmd->args );
|
||||
list_free( cmd->shell );
|
||||
string_free( cmd->buf );
|
||||
freetargets( cmd->unlock );
|
||||
BJAM_FREE( (void *)cmd );
|
||||
}
|
||||
|
||||
|
||||
@@ -46,14 +46,41 @@
|
||||
|
||||
|
||||
typedef struct _cmd CMD;
|
||||
|
||||
/*
|
||||
* A list whose elements are either TARGETS or CMDS.
|
||||
* CMDLIST is used only by CMD. A TARGET means that
|
||||
* the CMD is the last updating action required to
|
||||
* build the target. A CMD is the next CMD required
|
||||
* to build the same target. (Note that a single action
|
||||
* can update more than one target, so the CMDs form
|
||||
* a DAG, not a straight linear list.)
|
||||
*/
|
||||
typedef struct _cmdlist {
|
||||
struct _cmdlist * next;
|
||||
union {
|
||||
CMD * cmd;
|
||||
TARGET * t;
|
||||
} impl;
|
||||
char iscmd;
|
||||
} CMDLIST;
|
||||
|
||||
CMDLIST * cmdlist_append_cmd( CMDLIST *, CMD * );
|
||||
CMDLIST * cmdlist_append_target( CMDLIST *, TARGET * );
|
||||
void cmd_list_free( CMDLIST * );
|
||||
|
||||
struct _cmd
|
||||
{
|
||||
CMD * next;
|
||||
CMDLIST * next;
|
||||
RULE * rule; /* rule->actions contains shell script */
|
||||
LIST * shell; /* $(JAMSHELL) value */
|
||||
LOL args; /* LISTs for $(<), $(>) */
|
||||
string buf[ 1 ]; /* actual commands */
|
||||
int noop; /* no-op commands should be faked instead of executed */
|
||||
int asynccnt; /* number of outstanding dependencies */
|
||||
TARGETS * lock; /* semaphores that are required by this cmd. */
|
||||
TARGETS * unlock; /* semaphores that are released when this cmd finishes. */
|
||||
char status; /* the command status */
|
||||
};
|
||||
|
||||
CMD * cmd_new
|
||||
|
||||
@@ -117,56 +117,17 @@ LIST * evaluate_rule( RULE * rule, OBJECT * rulename, FRAME * frame )
|
||||
action->refs = 1;
|
||||
|
||||
/* If we have a group of targets all being built using the same action
|
||||
* then we must not allow any of them to be used as sources unless they
|
||||
* are all up to date and their action does not need to be run or their
|
||||
* action has had a chance to finish its work and build all of them
|
||||
* anew.
|
||||
*
|
||||
* Without this it might be possible, in case of a multi-process build,
|
||||
* for their action, triggered to building one of the targets, to still
|
||||
* be running when another target in the group reports as done in order
|
||||
* to avoid triggering the same action again and gets used prematurely.
|
||||
*
|
||||
* As a quick-fix to achieve this effect we make all the targets list
|
||||
* each other as 'included targets'. More precisely, we mark the first
|
||||
* listed target as including all the other targets in the list and vice
|
||||
* versa. This makes anyone depending on any of those targets implicitly
|
||||
* depend on all of them, thus making sure none of those targets can be
|
||||
* used as sources until all of them have been built. Note that direct
|
||||
* dependencies could not have been used due to the 'circular
|
||||
* dependency' issue.
|
||||
*
|
||||
* TODO: Although the current implementation solves the problem of one
|
||||
* of the targets getting used before its action completes its work, it
|
||||
* also forces the action to run whenever any of the targets in the
|
||||
* group is not up to date even though some of them might not actually
|
||||
* be used by the targets being built. We should see how we can
|
||||
* correctly recognize such cases and use that to avoid running the
|
||||
* action if possible and not rebuild targets not actually depending on
|
||||
* targets that are not up to date.
|
||||
*
|
||||
* TODO: Current solution using fake INCLUDES relations may cause
|
||||
* actions to be run when the affected targets are built by multiple
|
||||
* actions. E.g. if we have the following actions registered in the
|
||||
* order specified:
|
||||
* (I) builds targets A & B
|
||||
* (II) builds target B
|
||||
* and we want to build a target depending on target A, then both
|
||||
* actions (I) & (II) will be run, even though the second one does not
|
||||
* have any direct relationship to target A. Consider whether this is
|
||||
* desired behaviour or not. It could be that Boost Build should (or
|
||||
* possibly already does) run all actions registered for a given target
|
||||
* if any of them needs to be run in which case our INCLUDES relations
|
||||
* are not actually causing any actions to be run that would not have
|
||||
* been run without them.
|
||||
* and any of these targets is updated, then we have to consider them
|
||||
* all to be out-dated. We do this by adding a REBUILDS in both directions
|
||||
* between the first target and all the other targets.
|
||||
*/
|
||||
if ( action->targets )
|
||||
{
|
||||
TARGET * const t0 = action->targets->target;
|
||||
for ( t = action->targets->next; t; t = t->next )
|
||||
{
|
||||
target_include( t->target, t0 );
|
||||
target_include( t0, t->target );
|
||||
t->target->rebuilds = targetentry( t->target->rebuilds, t0 );
|
||||
t0->rebuilds = targetentry( t0->rebuilds, t->target );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,6 +122,19 @@ int file_collect_dir_content_( file_info_t * const d )
|
||||
ff->is_file = !ff->is_dir;
|
||||
ff->exists = 1;
|
||||
timestamp_from_filetime( &ff->time, &finfo.ftLastWriteTime );
|
||||
// Use the timestamp of the link target, not the link itself
|
||||
// (i.e. stat instead of lstat)
|
||||
if ( finfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
|
||||
{
|
||||
HANDLE hLink = CreateFileA( pathname->value, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
|
||||
BY_HANDLE_FILE_INFORMATION target_finfo[ 1 ];
|
||||
if ( hLink != INVALID_HANDLE_VALUE && GetFileInformationByHandle( hLink, target_finfo ) )
|
||||
{
|
||||
ff->is_file = target_finfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? 0 : 1;
|
||||
ff->is_dir = target_finfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0;
|
||||
timestamp_from_filetime( &ff->time, &target_finfo->ftLastWriteTime );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while ( FindNextFile( findHandle, &finfo ) );
|
||||
|
||||
@@ -161,6 +161,8 @@ int make( LIST * targets, int anyhow )
|
||||
* make0() to be updated.
|
||||
*/
|
||||
|
||||
static void force_rebuilds( TARGET * t );
|
||||
|
||||
static void update_dependants( TARGET * t )
|
||||
{
|
||||
TARGETS * q;
|
||||
@@ -190,6 +192,8 @@ static void update_dependants( TARGET * t )
|
||||
update_dependants( p );
|
||||
}
|
||||
}
|
||||
/* Make sure that rebuilds can be chained. */
|
||||
force_rebuilds( t );
|
||||
}
|
||||
|
||||
|
||||
@@ -676,7 +680,30 @@ void make0
|
||||
else
|
||||
fate = t->fate;
|
||||
|
||||
/* Step 4g: If this target needs to be built, force rebuild everything in
|
||||
/*
|
||||
* Step 4g: If this target needs to be built, make0 all targets
|
||||
* that are updated by the same actions used to update this target.
|
||||
* These have already been marked as REBUILDS, and make1 has
|
||||
* special handling for them. We just need to make sure that
|
||||
* they get make0ed.
|
||||
*/
|
||||
if ( ( fate >= T_FATE_BUILD ) && ( fate < T_FATE_BROKEN ) )
|
||||
{
|
||||
ACTIONS * a;
|
||||
TARGETS * c;
|
||||
for ( a = t->actions; a; a = a->next )
|
||||
{
|
||||
for ( c = a->action->targets; c; c = c->next )
|
||||
{
|
||||
if ( c->target->fate == T_FATE_INIT )
|
||||
{
|
||||
make0( c->target, ptime, depth + 1, counts, anyhow, rescanning );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 4h: If this target needs to be built, force rebuild everything in
|
||||
* its rebuilds list.
|
||||
*/
|
||||
if ( ( fate >= T_FATE_BUILD ) && ( fate < T_FATE_BROKEN ) )
|
||||
|
||||
@@ -63,6 +63,12 @@ static SETTINGS * make1settings ( struct module_t *, LIST * vars );
|
||||
static void make1bind ( TARGET * );
|
||||
static TARGET * make1findcycle ( TARGET * );
|
||||
static void make1breakcycle( TARGET *, TARGET * cycle_root );
|
||||
static void push_cmds( CMDLIST * cmds, int status );
|
||||
static int cmd_sem_lock( TARGET * t );
|
||||
static void cmd_sem_unlock( TARGET * t );
|
||||
|
||||
static int targets_contains( TARGETS * l, TARGET * t );
|
||||
static int targets_equal( TARGETS * l1, TARGETS * l2 );
|
||||
|
||||
/* Ugly static - it is too hard to carry it through the callbacks. */
|
||||
|
||||
@@ -372,33 +378,16 @@ static void make1b( state * const pState )
|
||||
TARGET * failed = 0;
|
||||
char const * failed_name = "dependencies";
|
||||
|
||||
pop_state( &state_stack );
|
||||
|
||||
/* If any dependencies are still outstanding, wait until they signal their
|
||||
* completion by pushing this same state for their parent targets.
|
||||
*/
|
||||
if ( --t->asynccnt )
|
||||
{
|
||||
pop_state( &state_stack );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to aquire a semaphore. If it is locked, wait until the target that
|
||||
* locked it is built and signals completition.
|
||||
*/
|
||||
#ifdef OPT_SEMAPHORE
|
||||
if ( t->semaphore && t->semaphore->asynccnt )
|
||||
{
|
||||
/* Append 't' to the list of targets waiting on semaphore. */
|
||||
t->semaphore->parents = targetentry( t->semaphore->parents, t );
|
||||
t->asynccnt++;
|
||||
|
||||
if ( DEBUG_EXECCMD )
|
||||
printf( "SEM: %s is busy, delaying launch of %s\n",
|
||||
object_str( t->semaphore->name ), object_str( t->name ) );
|
||||
pop_state( &state_stack );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now ready to build target 't', if dependencies built OK. */
|
||||
|
||||
/* Collect status from dependencies. If -n was passed then act as though all
|
||||
@@ -492,28 +481,19 @@ static void make1b( state * const pState )
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifdef OPT_SEMAPHORE
|
||||
/* If there is a semaphore, indicate that it is in use. */
|
||||
if ( t->semaphore )
|
||||
{
|
||||
++t->semaphore->asynccnt;
|
||||
if ( DEBUG_EXECCMD )
|
||||
printf( "SEM: %s now used by %s\n", object_str( t->semaphore->name
|
||||
), object_str( t->name ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Proceed to MAKE1C to begin executing the chain of commands prepared for
|
||||
* building the target. If we are not going to build the target (e.g. due to
|
||||
* dependency failures or no commands needing to be run) the chain will be
|
||||
* empty and MAKE1C processing will directly signal the target's completion.
|
||||
*/
|
||||
/* Implementation note:
|
||||
* Morfing the current state on the stack instead of popping it and
|
||||
* pushing a new one is a slight optimization with no side-effects since we
|
||||
* pushed no other states while processing this one.
|
||||
*/
|
||||
pState->curstate = T_STATE_MAKE1C;
|
||||
|
||||
if ( t->cmds == NULL || --( ( CMD * )t->cmds )->asynccnt == 0 )
|
||||
push_state( &state_stack, t, NULL, T_STATE_MAKE1C );
|
||||
else if ( DEBUG_EXECCMD )
|
||||
{
|
||||
CMD * cmd = ( CMD * )t->cmds;
|
||||
printf( "Delaying %s %s: %d targets not ready\n", object_str( cmd->rule->name ), object_str( t->boundname ), cmd->asynccnt );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -534,7 +514,7 @@ static void make1c( state const * const pState )
|
||||
TARGET * const t = pState->t;
|
||||
CMD * const cmd = (CMD *)t->cmds;
|
||||
|
||||
if ( cmd && t->status == EXEC_CMD_OK )
|
||||
if ( cmd )
|
||||
{
|
||||
/* Pop state first in case something below (e.g. exec_cmd(), exec_wait()
|
||||
* or make1c_closure()) pushes a new state. Note that we must not access
|
||||
@@ -543,6 +523,21 @@ static void make1c( state const * const pState )
|
||||
*/
|
||||
pop_state( &state_stack );
|
||||
|
||||
if ( cmd->status != EXEC_CMD_OK )
|
||||
{
|
||||
t->cmds = NULL;
|
||||
push_cmds( cmd->next, cmd->status );
|
||||
cmd_free( cmd );
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef OPT_SEMAPHORE
|
||||
if ( ! cmd_sem_lock( t ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Increment the jobs running counter. */
|
||||
++cmdsrunning;
|
||||
|
||||
@@ -575,14 +570,6 @@ static void make1c( state const * const pState )
|
||||
{
|
||||
ACTIONS * actions;
|
||||
|
||||
/* Collect status from actions, and distribute it as well. */
|
||||
for ( actions = t->actions; actions; actions = actions->next )
|
||||
if ( actions->action->status > t->status )
|
||||
t->status = actions->action->status;
|
||||
for ( actions = t->actions; actions; actions = actions->next )
|
||||
if ( t->status > actions->action->status )
|
||||
actions->action->status = t->status;
|
||||
|
||||
/* Tally success/failure for those we tried to update. */
|
||||
if ( t->progress == T_MAKE_RUNNING )
|
||||
switch ( t->status )
|
||||
@@ -677,38 +664,6 @@ static void make1c( state const * const pState )
|
||||
push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B );
|
||||
}
|
||||
|
||||
#ifdef OPT_SEMAPHORE
|
||||
/* If there is a semaphore, it is now free. */
|
||||
if ( t->semaphore )
|
||||
{
|
||||
assert( t->semaphore->asynccnt == 1 );
|
||||
--t->semaphore->asynccnt;
|
||||
|
||||
if ( DEBUG_EXECCMD )
|
||||
printf( "SEM: %s is now free\n", object_str(
|
||||
t->semaphore->name ) );
|
||||
|
||||
/* If anything is waiting, notify the next target. There is no
|
||||
* point in notifying all waiting targets, since they will be
|
||||
* notified again.
|
||||
*/
|
||||
if ( t->semaphore->parents )
|
||||
{
|
||||
TARGETS * first = t->semaphore->parents;
|
||||
t->semaphore->parents = first->next;
|
||||
if ( first->next )
|
||||
first->next->tail = first->tail;
|
||||
|
||||
if ( DEBUG_EXECCMD )
|
||||
printf( "SEM: placing %s on stack\n", object_str(
|
||||
first->target->name ) );
|
||||
push_state( &temp_stack, first->target, NULL, T_STATE_MAKE1B
|
||||
);
|
||||
BJAM_FREE( first );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Must pop state before pushing any more. */
|
||||
pop_state( &state_stack );
|
||||
|
||||
@@ -945,12 +900,57 @@ static void make1c_closure
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OPT_SEMAPHORE
|
||||
/* Release any semaphores used by this action. */
|
||||
cmd_sem_unlock( t );
|
||||
#endif
|
||||
|
||||
/* Free this command and push the MAKE1C state to execute the next one
|
||||
* scheduled for building this same target.
|
||||
*/
|
||||
t->cmds = (char *)cmd_next( cmd );
|
||||
t->cmds = NULL;
|
||||
push_cmds( cmd->next, t->status );
|
||||
cmd_free( cmd );
|
||||
push_state( &state_stack, t, NULL, T_STATE_MAKE1C );
|
||||
}
|
||||
|
||||
/* push the next MAKE1C state after a command is run. */
|
||||
static void push_cmds( CMDLIST * cmds, int status )
|
||||
{
|
||||
CMDLIST * cmd_iter;
|
||||
for( cmd_iter = cmds; cmd_iter; cmd_iter = cmd_iter->next )
|
||||
{
|
||||
if ( cmd_iter->iscmd )
|
||||
{
|
||||
CMD * next_cmd = cmd_iter->impl.cmd;
|
||||
/* Propagate the command status. */
|
||||
if ( next_cmd->status < status )
|
||||
next_cmd->status = status;
|
||||
if ( --next_cmd->asynccnt == 0 )
|
||||
{
|
||||
/* Select the first target associated with the action.
|
||||
* This is safe because sibling CMDs cannot have targets
|
||||
* in common.
|
||||
*/
|
||||
TARGET * first_target = bindtarget( list_front( lol_get( &next_cmd->args, 0 ) ) );
|
||||
first_target->cmds = (char *)next_cmd;
|
||||
push_state( &state_stack, first_target, NULL, T_STATE_MAKE1C );
|
||||
}
|
||||
else if ( DEBUG_EXECCMD )
|
||||
{
|
||||
TARGET * first_target = bindtarget( list_front( lol_get( &next_cmd->args, 0 ) ) );
|
||||
printf( "Delaying %s %s: %d targets not ready\n", object_str( next_cmd->rule->name ), object_str( first_target->boundname ), next_cmd->asynccnt );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a target that we're finished updating */
|
||||
TARGET * updated_target = cmd_iter->impl.t;
|
||||
if ( updated_target->status < status )
|
||||
updated_target->status = status;
|
||||
updated_target->cmds = NULL;
|
||||
push_state( &state_stack, updated_target, NULL, T_STATE_MAKE1C );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -995,15 +995,14 @@ static void swap_settings
|
||||
static CMD * make1cmds( TARGET * t )
|
||||
{
|
||||
CMD * cmds = 0;
|
||||
CMD * * cmds_next = &cmds;
|
||||
CMD * last_cmd;
|
||||
LIST * shell = L0;
|
||||
module_t * settings_module = 0;
|
||||
TARGET * settings_target = 0;
|
||||
ACTIONS * a0;
|
||||
int const running_flag = globs.noexec ? A_RUNNING_NOEXEC : A_RUNNING;
|
||||
|
||||
/* Step through actions. Actions may be shared with other targets or grouped
|
||||
* using RULE_TOGETHER, so actions already seen are skipped.
|
||||
/* Step through actions.
|
||||
*/
|
||||
for ( a0 = t->actions; a0; a0 = a0->next )
|
||||
{
|
||||
@@ -1014,12 +1013,37 @@ static CMD * make1cmds( TARGET * t )
|
||||
LIST * ns;
|
||||
ACTIONS * a1;
|
||||
|
||||
/* Only do rules with commands to execute. If this action has already
|
||||
* been executed, use saved status.
|
||||
/* Only do rules with commands to execute.
|
||||
*/
|
||||
if ( !actions || a0->action->running >= running_flag )
|
||||
if ( !actions )
|
||||
continue;
|
||||
|
||||
if ( a0->action->running >= running_flag )
|
||||
{
|
||||
CMD * first;
|
||||
/* If this action was skipped either because it was
|
||||
* combined with another action by RULE_TOGETHER, or
|
||||
* because all of its sources were filtered out,
|
||||
* then we don't have anything to do here.
|
||||
*/
|
||||
if ( a0->action->first_cmd == NULL )
|
||||
continue;
|
||||
/* This action has already been processed for another target.
|
||||
* Just set up the dependency graph correctly and move on.
|
||||
*/
|
||||
first = a0->action->first_cmd;
|
||||
if( cmds )
|
||||
{
|
||||
last_cmd->next = cmdlist_append_cmd( last_cmd->next, first );
|
||||
}
|
||||
else
|
||||
{
|
||||
cmds = first;
|
||||
}
|
||||
last_cmd = a0->action->last_cmd;
|
||||
continue;
|
||||
}
|
||||
|
||||
a0->action->running = running_flag;
|
||||
|
||||
/* Make LISTS of targets and sources. If `execute together` has been
|
||||
@@ -1031,7 +1055,8 @@ static CMD * make1cmds( TARGET * t )
|
||||
if ( actions->flags & RULE_TOGETHER )
|
||||
for ( a1 = a0->next; a1; a1 = a1->next )
|
||||
if ( a1->action->rule == rule &&
|
||||
a1->action->running < running_flag )
|
||||
a1->action->running < running_flag &&
|
||||
targets_equal( a0->action->targets, a1->action->targets ) )
|
||||
{
|
||||
ns = make1list( ns, a1->action->sources, actions->flags );
|
||||
a1->action->running = running_flag;
|
||||
@@ -1076,8 +1101,12 @@ static CMD * make1cmds( TARGET * t )
|
||||
int const length = list_length( ns );
|
||||
int start = 0;
|
||||
int chunk = length;
|
||||
int cmd_count = 0;
|
||||
LIST * cmd_targets = L0;
|
||||
LIST * cmd_shell = L0;
|
||||
TARGETS * semaphores = NULL;
|
||||
TARGETS * targets_iter;
|
||||
int unique_targets;
|
||||
do
|
||||
{
|
||||
CMD * cmd;
|
||||
@@ -1138,8 +1167,20 @@ static CMD * make1cmds( TARGET * t )
|
||||
if ( accept_command )
|
||||
{
|
||||
/* Chain it up. */
|
||||
*cmds_next = cmd;
|
||||
cmds_next = &cmd->next;
|
||||
if ( cmds )
|
||||
{
|
||||
last_cmd->next = cmdlist_append_cmd( last_cmd->next, cmd );
|
||||
last_cmd = cmd;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmds = last_cmd = cmd;
|
||||
}
|
||||
|
||||
if ( cmd_count++ == 0 )
|
||||
{
|
||||
a0->action->first_cmd = cmd;
|
||||
}
|
||||
|
||||
/* Mark lists we need recreated for the next command since
|
||||
* they got consumed by the cmd object.
|
||||
@@ -1160,6 +1201,39 @@ static CMD * make1cmds( TARGET * t )
|
||||
start += chunk;
|
||||
}
|
||||
while ( start < length );
|
||||
|
||||
/* Record the end of the actions cmds */
|
||||
a0->action->last_cmd = last_cmd;
|
||||
|
||||
unique_targets = 0;
|
||||
for ( targets_iter = a0->action->targets; targets_iter; targets_iter = targets_iter->next )
|
||||
{
|
||||
if ( targets_contains( targets_iter->next, targets_iter->target ) )
|
||||
continue;
|
||||
/* Add all targets produced by the action to the update list. */
|
||||
push_state( &state_stack, targets_iter->target, NULL, T_STATE_MAKE1A );
|
||||
++unique_targets;
|
||||
}
|
||||
/* We need to wait until all the targets agree that
|
||||
* it's okay to run this action.
|
||||
*/
|
||||
( ( CMD * )a0->action->first_cmd )->asynccnt = unique_targets;
|
||||
|
||||
#if OPT_SEMAPHORE
|
||||
/* Collect semaphores */
|
||||
for ( targets_iter = a0->action->targets; targets_iter; targets_iter = targets_iter->next )
|
||||
{
|
||||
TARGET * sem = targets_iter->target->semaphore;
|
||||
if ( sem )
|
||||
{
|
||||
TARGETS * semiter;
|
||||
if ( ! targets_contains( semaphores, sem ) )
|
||||
semaphores = targetentry( semaphores, sem );
|
||||
}
|
||||
}
|
||||
( ( CMD * )a0->action->first_cmd )->lock = semaphores;
|
||||
( ( CMD * )a0->action->last_cmd )->unlock = semaphores;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* These were always copied when used. */
|
||||
@@ -1171,6 +1245,11 @@ static CMD * make1cmds( TARGET * t )
|
||||
freesettings( boundvars );
|
||||
}
|
||||
|
||||
if ( cmds )
|
||||
{
|
||||
last_cmd->next = cmdlist_append_target( last_cmd->next, t );
|
||||
}
|
||||
|
||||
swap_settings( &settings_module, &settings_target, 0, 0 );
|
||||
return cmds;
|
||||
}
|
||||
@@ -1281,3 +1360,101 @@ static void make1bind( TARGET * t )
|
||||
t->binding = timestamp_empty( &t->time ) ? T_BIND_MISSING : T_BIND_EXISTS;
|
||||
popsettings( root_module(), t->settings );
|
||||
}
|
||||
|
||||
|
||||
static int targets_contains( TARGETS * l, TARGET * t )
|
||||
{
|
||||
for ( ; l; l = l->next )
|
||||
{
|
||||
if ( t == l->target )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int targets_equal( TARGETS * l1, TARGETS * l2 )
|
||||
{
|
||||
for ( ; l1 && l2; l1 = l1->next, l2 = l2->next )
|
||||
{
|
||||
if ( l1->target != l2->target )
|
||||
return 0;
|
||||
}
|
||||
return !l1 && !l2;
|
||||
}
|
||||
|
||||
|
||||
#ifdef OPT_SEMAPHORE
|
||||
|
||||
static int cmd_sem_lock( TARGET * t )
|
||||
{
|
||||
CMD * cmd = (CMD *)t->cmds;
|
||||
TARGETS * iter;
|
||||
/* Check whether all the semaphores required for updating
|
||||
* this target are free.
|
||||
*/
|
||||
for ( iter = cmd->lock; iter; iter = iter->next )
|
||||
{
|
||||
if ( iter->target->asynccnt > 0 )
|
||||
{
|
||||
if ( DEBUG_EXECCMD )
|
||||
printf( "SEM: %s is busy, delaying launch of %s\n",
|
||||
object_str( iter->target->name ), object_str( t->name ) );
|
||||
iter->target->parents = targetentry( iter->target->parents, t );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Lock the semaphores. */
|
||||
for ( iter = cmd->lock; iter; iter = iter->next )
|
||||
{
|
||||
++iter->target->asynccnt;
|
||||
if ( DEBUG_EXECCMD )
|
||||
printf( "SEM: %s now used by %s\n", object_str( iter->target->name
|
||||
), object_str( t->name ) );
|
||||
}
|
||||
/* A cmd only needs to be locked around its execution.
|
||||
* clearing cmd->lock here makes it safe to call cmd_sem_lock
|
||||
* twice.
|
||||
*/
|
||||
cmd->lock = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void cmd_sem_unlock( TARGET * t )
|
||||
{
|
||||
CMD * cmd = ( CMD * )t->cmds;
|
||||
TARGETS * iter;
|
||||
/* Release the semaphores. */
|
||||
for ( iter = cmd->unlock; iter; iter = iter->next )
|
||||
{
|
||||
if ( DEBUG_EXECCMD )
|
||||
printf( "SEM: %s is now free\n", object_str(
|
||||
iter->target->name ) );
|
||||
--iter->target->asynccnt;
|
||||
assert( iter->target->asynccnt <= 0 );
|
||||
}
|
||||
for ( iter = cmd->unlock; iter; iter = iter->next )
|
||||
{
|
||||
/* Find a waiting target that's ready */
|
||||
while ( iter->target->parents )
|
||||
{
|
||||
TARGETS * first = iter->target->parents;
|
||||
TARGET * t1 = first->target;
|
||||
|
||||
/* Pop the first waiting CMD */
|
||||
if ( first->next )
|
||||
first->next->tail = first->tail;
|
||||
iter->target->parents = first->next;
|
||||
BJAM_FREE( first );
|
||||
|
||||
if ( cmd_sem_lock( t1 ) )
|
||||
{
|
||||
push_state( &state_stack, t1, NULL, T_STATE_MAKE1C );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
/* Keep JAMVERSYM in sync with VERSION. */
|
||||
/* It can be accessed as $(JAMVERSION) in the Jamfile. */
|
||||
|
||||
#define VERSION_MAJOR 2011
|
||||
#define VERSION_MAJOR 2013
|
||||
#define VERSION_MINOR 12
|
||||
#define VERSION_PATCH 1
|
||||
#define VERSION_MAJOR_SYM "2011"
|
||||
#define VERSION_MINOR_SYM "12"
|
||||
#define VERSION_PATCH_SYM "01"
|
||||
#define VERSION "2011.12.1"
|
||||
#define JAMVERSYM "JAMVERSION=2011.12"
|
||||
#define VERSION_PATCH 0
|
||||
#define VERSION_MAJOR_SYM "2013"
|
||||
#define VERSION_MINOR_SYM "05"
|
||||
#define VERSION_PATCH_SYM "00"
|
||||
#define VERSION "2013.05"
|
||||
#define JAMVERSYM "JAMVERSION=2013.05"
|
||||
|
||||
@@ -92,8 +92,13 @@ struct _action
|
||||
#define A_INIT 0
|
||||
#define A_RUNNING_NOEXEC 1
|
||||
#define A_RUNNING 2
|
||||
char status; /* see TARGET status */
|
||||
int refs;
|
||||
|
||||
/* WARNING: These variables are used to pass state required by make1cmds and
|
||||
* are not valid anywhere else.
|
||||
*/
|
||||
void * first_cmd; /* Pointer to the first CMD created by this action */
|
||||
void * last_cmd; /* Pointer to the last CMD created by this action */
|
||||
};
|
||||
|
||||
/* SETTINGS - variables to set when executing a TARGET's ACTIONS. */
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "object.h"
|
||||
|
||||
#ifdef OS_NT
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
24
v2/test/builtin_readlink.py
Executable file
24
v2/test/builtin_readlink.py
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2012 Steven Watanabe
|
||||
# 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)
|
||||
|
||||
import BoostBuild
|
||||
import os
|
||||
|
||||
t = BoostBuild.Tester(pass_toolset=0)
|
||||
|
||||
t.write("link-target", "")
|
||||
os.symlink("link-target", "link")
|
||||
|
||||
t.write("file.jam", """
|
||||
ECHO [ READLINK link ] ;
|
||||
EXIT [ READLINK link-target ] : 0 ;
|
||||
""")
|
||||
|
||||
t.run_build_system(["-ffile.jam"], stdout="""link-target
|
||||
|
||||
""")
|
||||
|
||||
t.cleanup()
|
||||
202
v2/test/core_multifile_actions.py
Executable file
202
v2/test/core_multifile_actions.py
Executable file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2013 Steven Watanabe
|
||||
# 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)
|
||||
|
||||
# Tests that actions that produce multiple targets are handled
|
||||
# correctly. The rules are as follows:
|
||||
#
|
||||
# - If any action that updates a target is run, then the target
|
||||
# is considered to be out-of-date and all of its updating actions
|
||||
# are run in order.
|
||||
# - A target is considered updated when all of its updating actions
|
||||
# have completed successfully.
|
||||
# - If any updating action for a target fails, then the remaining
|
||||
# actions are skipped and the target is marked as failed.
|
||||
#
|
||||
# Note that this is a more thorough test case for the same
|
||||
# problem that core_parallel_multifile_actions_N.py checks for.
|
||||
|
||||
import BoostBuild
|
||||
|
||||
t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
|
||||
|
||||
t.write("file.jam", """
|
||||
actions update
|
||||
{
|
||||
echo updating $(<)
|
||||
}
|
||||
|
||||
update x1 x2 ;
|
||||
update x2 x3 ;
|
||||
""")
|
||||
|
||||
# Updating x1 should force x2 to update as well.
|
||||
t.run_build_system(["-ffile.jam", "x1"], stdout="""\
|
||||
...found 3 targets...
|
||||
...updating 3 targets...
|
||||
update x1
|
||||
updating x1 x2
|
||||
update x2
|
||||
updating x2 x3
|
||||
...updated 3 targets...
|
||||
""")
|
||||
|
||||
# If x1 is up-to-date, we don't need to update x2,
|
||||
# even though x2 is missing.
|
||||
t.write("x1", "")
|
||||
t.run_build_system(["-ffile.jam", "x1"], stdout="""\
|
||||
...found 1 target...
|
||||
""")
|
||||
|
||||
# Building x3 should update x1 and x2, even though
|
||||
# x1 would be considered up-to-date, taken alone.
|
||||
t.run_build_system(["-ffile.jam", "x3"], stdout="""\
|
||||
...found 3 targets...
|
||||
...updating 2 targets...
|
||||
update x1
|
||||
updating x1 x2
|
||||
update x2
|
||||
updating x2 x3
|
||||
...updated 3 targets...
|
||||
""")
|
||||
|
||||
# Updating x2 should succeed, but x3 should be skipped
|
||||
t.rm("x1")
|
||||
t.write("file.jam", """\
|
||||
actions update
|
||||
{
|
||||
echo updating $(<)
|
||||
}
|
||||
actions fail
|
||||
{
|
||||
echo failed $(<)
|
||||
exit 1
|
||||
}
|
||||
|
||||
update x1 x2 ;
|
||||
fail x1 ;
|
||||
update x1 x3 ;
|
||||
update x2 ;
|
||||
update x3 ;
|
||||
""")
|
||||
|
||||
t.run_build_system(["-ffile.jam", "x3"], status=1, stdout="""\
|
||||
...found 3 targets...
|
||||
...updating 3 targets...
|
||||
update x1
|
||||
updating x1 x2
|
||||
fail x1
|
||||
failed x1
|
||||
|
||||
echo failed x1
|
||||
exit 1
|
||||
|
||||
...failed fail x1...
|
||||
update x2
|
||||
updating x2
|
||||
...failed updating 2 targets...
|
||||
...updated 1 target...
|
||||
""")
|
||||
|
||||
# Make sure that dependencies of targets that are
|
||||
# updated as a result of a multifile action are
|
||||
# processed correctly.
|
||||
t.rm("x1")
|
||||
t.write("file.jam", """\
|
||||
actions update
|
||||
{
|
||||
echo updating $(<)
|
||||
}
|
||||
|
||||
update x1 ;
|
||||
update x2 ;
|
||||
DEPENDS x2 : x1 ;
|
||||
update x2 x3 ;
|
||||
""")
|
||||
t.run_build_system(["-ffile.jam", "x3"], stdout="""\
|
||||
...found 3 targets...
|
||||
...updating 3 targets...
|
||||
update x1
|
||||
updating x1
|
||||
update x2
|
||||
updating x2
|
||||
update x2
|
||||
updating x2 x3
|
||||
...updated 3 targets...
|
||||
""")
|
||||
|
||||
# JAM_SEMAPHORE rules:
|
||||
#
|
||||
# - if two updating actions have targets that share a semaphore,
|
||||
# these actions cannot be run in parallel.
|
||||
#
|
||||
t.write("file.jam", """\
|
||||
actions update
|
||||
{
|
||||
echo updating $(<)
|
||||
}
|
||||
|
||||
targets = x1 x2 ;
|
||||
JAM_SEMAPHORE on $(targets) = <s>update_sem ;
|
||||
update x1 x2 ;
|
||||
""")
|
||||
t.run_build_system(["-ffile.jam", "x1"], stdout="""\
|
||||
...found 2 targets...
|
||||
...updating 2 targets...
|
||||
update x1
|
||||
updating x1 x2
|
||||
...updated 2 targets...
|
||||
""")
|
||||
|
||||
# A target can appear multiple times in an action
|
||||
t.write("file.jam", """\
|
||||
actions update
|
||||
{
|
||||
echo updating $(<)
|
||||
}
|
||||
|
||||
update x1 x1 ;
|
||||
""")
|
||||
t.run_build_system(["-ffile.jam", "x1"], stdout="""\
|
||||
...found 1 target...
|
||||
...updating 1 target...
|
||||
update x1
|
||||
updating x1 x1
|
||||
...updated 1 target...
|
||||
""")
|
||||
|
||||
# Together actions should check that all the targets are the same
|
||||
# before combining.
|
||||
t.write("file.jam", """\
|
||||
actions together update
|
||||
{
|
||||
echo updating $(<) : $(>)
|
||||
}
|
||||
|
||||
update x1 x2 : s1 ;
|
||||
update x1 x2 : s2 ;
|
||||
|
||||
update x3 : s3 ;
|
||||
update x3 x4 : s4 ;
|
||||
update x4 x3 : s5 ;
|
||||
DEPENDS all : x1 x2 x3 x4 ;
|
||||
""")
|
||||
t.run_build_system(["-ffile.jam"], stdout="""\
|
||||
...found 5 targets...
|
||||
...updating 4 targets...
|
||||
update x1
|
||||
updating x1 x2 : s1 s2
|
||||
update x3
|
||||
updating x3 : s3
|
||||
update x3
|
||||
updating x3 x4 : s4
|
||||
update x4
|
||||
updating x4 x3 : s5
|
||||
...updated 4 targets...
|
||||
""")
|
||||
|
||||
|
||||
|
||||
t.cleanup()
|
||||
119
v2/test/libjpeg.py
Executable file
119
v2/test/libjpeg.py
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) 2013 Steven Watanabe
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import BoostBuild
|
||||
import MockToolset
|
||||
|
||||
t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0)
|
||||
|
||||
MockToolset.create(t)
|
||||
|
||||
# Build from source
|
||||
t.write("libjpeg/jpeg.h", 'libjpeg')
|
||||
t.write("libjpeg/jpeg.c", 'jpeg')
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libjpeg : : <source>$(here)/libjpeg ;
|
||||
alias libjpeg : /libjpeg//libjpeg : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, '''
|
||||
source_file('jpeg.c', 'jpeg')
|
||||
action('-c -x c -I./libjpeg -o $jpeg.o $jpeg.c')
|
||||
action('--dll $jpeg.o -o $jpeg.so')
|
||||
action('--archive $jpeg.o -o $jpeg.a')
|
||||
''')
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/standalone/libjpeg/mock/debug/jpeg.dll')
|
||||
t.expect_addition('bin/standalone/libjpeg/mock/debug/link-static/jpeg.lib')
|
||||
|
||||
t.rm('libjpeg')
|
||||
|
||||
# Generic definitions that aren't configuration specific
|
||||
common_stuff = '''
|
||||
source_file('test.cpp', 'test.cpp')
|
||||
source_file('main.cpp', 'int main() {}')
|
||||
source_file('jpeg.h.cpp', '#include <jpeg.h>')
|
||||
action('-c -x c++ $main.cpp -o $main.o')
|
||||
'''
|
||||
t.write('test.cpp', 'test.cpp')
|
||||
|
||||
# Default initialization - static library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libjpeg ;
|
||||
exe test : test.cpp /libjpeg//libjpeg : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o --static-lib=jpeg -o $config.exe')
|
||||
action('-c -x c++ $jpeg.h.cpp -o $jpeg.h.o')
|
||||
action('-c -x c++ $test.cpp -o $test.o')
|
||||
action('$test.o --static-lib=jpeg -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
# Default initialization - shared library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libjpeg ;
|
||||
exe test : test.cpp /libjpeg//libjpeg : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o --shared-lib=jpeg -o $config.exe')
|
||||
action('-c -x c++ $jpeg.h.cpp -o $jpeg.h.o')
|
||||
action('-c -x c++ $test.cpp -o $test.o')
|
||||
action('$test.o --shared-lib=jpeg -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
# Initialization in explicit location - static library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libjpeg : : <name>mylibjpeg <include>$(here)/libjpeg <search>$(here)/libjpeg ;
|
||||
exe test : test.cpp /libjpeg//libjpeg : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
t.write('libjpeg/jpeg.h', 'libjpeg')
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o -L./libjpeg --static-lib=mylibjpeg -o $config.exe')
|
||||
action('-c -x c++ $test.cpp -I./libjpeg -o $test.o')
|
||||
action('$test.o -L./libjpeg --static-lib=mylibjpeg -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
# Initialization in explicit location - shared library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libjpeg : : <name>mylibjpeg <include>$(here)/libjpeg <search>$(here)/libjpeg ;
|
||||
exe test : test.cpp /libjpeg//libjpeg : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o -L./libjpeg --shared-lib=mylibjpeg -o $config.exe')
|
||||
action('-c -x c++ $test.cpp -I./libjpeg -o $test.o')
|
||||
action('$test.o -L./libjpeg --shared-lib=mylibjpeg -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
t.cleanup()
|
||||
119
v2/test/libpng.py
Executable file
119
v2/test/libpng.py
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) 2013 Steven Watanabe
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import BoostBuild
|
||||
import MockToolset
|
||||
|
||||
t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0)
|
||||
|
||||
MockToolset.create(t)
|
||||
|
||||
# Build from source
|
||||
t.write("libpng/png.h", 'libpng')
|
||||
t.write("libpng/png.c", 'png')
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libpng : : <source>$(here)/libpng ;
|
||||
alias libpng : /libpng//libpng : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, '''
|
||||
source_file('png.c', 'png')
|
||||
action('-c -x c -I./libpng -o $png.o $png.c')
|
||||
action('--dll $png.o -o $png.so')
|
||||
action('--archive $png.o -o $png.a')
|
||||
''')
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/standalone/libpng/mock/debug/png.dll')
|
||||
t.expect_addition('bin/standalone/libpng/mock/debug/link-static/png.lib')
|
||||
|
||||
t.rm('libpng')
|
||||
|
||||
# Generic definitions that aren't configuration specific
|
||||
common_stuff = '''
|
||||
source_file('test.cpp', 'test.cpp')
|
||||
source_file('main.cpp', 'int main() {}')
|
||||
source_file('png.h.cpp', '#include <png.h>')
|
||||
action('-c -x c++ $main.cpp -o $main.o')
|
||||
'''
|
||||
t.write('test.cpp', 'test.cpp')
|
||||
|
||||
# Default initialization - static library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libpng ;
|
||||
exe test : test.cpp /libpng//libpng : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o --static-lib=png -o $config.exe')
|
||||
action('-c -x c++ $png.h.cpp -o $png.h.o')
|
||||
action('-c -x c++ $test.cpp -o $test.o')
|
||||
action('$test.o --static-lib=png -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
# Default initialization - shared library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libpng ;
|
||||
exe test : test.cpp /libpng//libpng : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o --shared-lib=png -o $config.exe')
|
||||
action('-c -x c++ $png.h.cpp -o $png.h.o')
|
||||
action('-c -x c++ $test.cpp -o $test.o')
|
||||
action('$test.o --shared-lib=png -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
# Initialization in explicit location - static library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libpng : : <name>mylibpng <include>$(here)/libpng <search>$(here)/libpng ;
|
||||
exe test : test.cpp /libpng//libpng : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
t.write('libpng/png.h', 'libpng')
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o -L./libpng --static-lib=mylibpng -o $config.exe')
|
||||
action('-c -x c++ $test.cpp -I./libpng -o $test.o')
|
||||
action('$test.o -L./libpng --static-lib=mylibpng -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
# Initialization in explicit location - shared library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libpng : : <name>mylibpng <include>$(here)/libpng <search>$(here)/libpng ;
|
||||
exe test : test.cpp /libpng//libpng : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o -L./libpng --shared-lib=mylibpng -o $config.exe')
|
||||
action('-c -x c++ $test.cpp -I./libpng -o $test.o')
|
||||
action('$test.o -L./libpng --shared-lib=mylibpng -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
t.cleanup()
|
||||
119
v2/test/libtiff.py
Executable file
119
v2/test/libtiff.py
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) 2013 Steven Watanabe
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import BoostBuild
|
||||
import MockToolset
|
||||
|
||||
t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0)
|
||||
|
||||
MockToolset.create(t)
|
||||
|
||||
# Build from source
|
||||
t.write("libtiff/tiff.h", 'libtiff')
|
||||
t.write("libtiff/tiff.c", 'tiff')
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libtiff : : <source>$(here)/libtiff ;
|
||||
alias libtiff : /libtiff//libtiff : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, '''
|
||||
source_file('tiff.c', 'tiff')
|
||||
action('-c -x c -I./libtiff -o $tiff.o $tiff.c')
|
||||
action('--dll $tiff.o -o $tiff.so')
|
||||
action('--archive $tiff.o -o $tiff.a')
|
||||
''')
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/standalone/libtiff/mock/debug/tiff.dll')
|
||||
t.expect_addition('bin/standalone/libtiff/mock/debug/link-static/tiff.lib')
|
||||
|
||||
t.rm('libtiff')
|
||||
|
||||
# Generic definitions that aren't configuration specific
|
||||
common_stuff = '''
|
||||
source_file('test.cpp', 'test.cpp')
|
||||
source_file('main.cpp', 'int main() {}')
|
||||
source_file('tiff.h.cpp', '#include <tiff.h>')
|
||||
action('-c -x c++ $main.cpp -o $main.o')
|
||||
'''
|
||||
t.write('test.cpp', 'test.cpp')
|
||||
|
||||
# Default initialization - static library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libtiff ;
|
||||
exe test : test.cpp /libtiff//libtiff : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o --static-lib=tiff -o $config.exe')
|
||||
action('-c -x c++ $tiff.h.cpp -o $tiff.h.o')
|
||||
action('-c -x c++ $test.cpp -o $test.o')
|
||||
action('$test.o --static-lib=tiff -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
# Default initialization - shared library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libtiff ;
|
||||
exe test : test.cpp /libtiff//libtiff : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o --shared-lib=tiff -o $config.exe')
|
||||
action('-c -x c++ $tiff.h.cpp -o $tiff.h.o')
|
||||
action('-c -x c++ $test.cpp -o $test.o')
|
||||
action('$test.o --shared-lib=tiff -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
# Initialization in explicit location - static library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libtiff : : <name>mylibtiff <include>$(here)/libtiff <search>$(here)/libtiff ;
|
||||
exe test : test.cpp /libtiff//libtiff : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
t.write('libtiff/tiff.h', 'libtiff')
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o -L./libtiff --static-lib=mylibtiff -o $config.exe')
|
||||
action('-c -x c++ $test.cpp -I./libtiff -o $test.o')
|
||||
action('$test.o -L./libtiff --static-lib=mylibtiff -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
# Initialization in explicit location - shared library
|
||||
t.rm('bin')
|
||||
t.write("Jamroot.jam", """
|
||||
path-constant here : . ;
|
||||
using libtiff : : <name>mylibtiff <include>$(here)/libtiff <search>$(here)/libtiff ;
|
||||
exe test : test.cpp /libtiff//libtiff : : <link>static <link>shared ;
|
||||
""")
|
||||
|
||||
MockToolset.set_expected(t, common_stuff + '''
|
||||
action('$main.o -L./libtiff --shared-lib=mylibtiff -o $config.exe')
|
||||
action('-c -x c++ $test.cpp -I./libtiff -o $test.o')
|
||||
action('$test.o -L./libtiff --shared-lib=mylibtiff -o $test')
|
||||
''')
|
||||
t.run_build_system()
|
||||
t.expect_addition('bin/mock/debug/test.exe')
|
||||
t.expect_addition('bin/mock/debug/link-static/test.exe')
|
||||
|
||||
t.cleanup()
|
||||
154
v2/test/link.py
Executable file
154
v2/test/link.py
Executable file
@@ -0,0 +1,154 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2004 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)
|
||||
|
||||
# Tests the link-directory rule used to create the
|
||||
# common boost/ directory in the new git layout.
|
||||
|
||||
import BoostBuild
|
||||
|
||||
def ignore_config(t):
|
||||
"""These files are created by the configuration logic in link.jam
|
||||
They may or may not exist, depending on the system."""
|
||||
t.ignore("bin/test-hardlink")
|
||||
t.ignore("bin/test-hardlink-source")
|
||||
t.ignore("bin/test-symlink")
|
||||
t.ignore("bin/test-symlink-source")
|
||||
|
||||
def test_basic():
|
||||
"""Test creation of a single link"""
|
||||
t = BoostBuild.Tester()
|
||||
t.write("jamroot.jam", """\
|
||||
import link ;
|
||||
link-directory dir1-link : src/dir1/include : <location>. ;
|
||||
""")
|
||||
|
||||
t.write("src/dir1/include/file1.h", "file1")
|
||||
|
||||
t.run_build_system()
|
||||
|
||||
t.expect_addition("include/file1.h")
|
||||
t.expect_content("include/file1.h", "file1")
|
||||
ignore_config(t)
|
||||
t.expect_nothing_more()
|
||||
t.cleanup()
|
||||
|
||||
def test_merge_two():
|
||||
"""Test merging two directories"""
|
||||
t = BoostBuild.Tester()
|
||||
t.write("jamroot.jam", """\
|
||||
import link ;
|
||||
link-directory dir1-link : src/dir1/include : <location>. ;
|
||||
link-directory dir2-link : src/dir2/include : <location>. ;
|
||||
""")
|
||||
|
||||
t.write("src/dir1/include/file1.h", "file1")
|
||||
t.write("src/dir2/include/file2.h", "file2")
|
||||
|
||||
t.run_build_system()
|
||||
|
||||
t.expect_addition("include/file1.h")
|
||||
t.expect_content("include/file1.h", "file1")
|
||||
t.expect_addition("include/file2.h")
|
||||
t.expect_content("include/file2.h", "file2")
|
||||
ignore_config(t)
|
||||
t.expect_nothing_more()
|
||||
t.cleanup()
|
||||
|
||||
def test_merge_existing():
|
||||
"""Test adding a link when a different symlink already exists"""
|
||||
t = BoostBuild.Tester()
|
||||
t.write("jamroot.jam", """\
|
||||
import link ;
|
||||
link-directory dir1-link : src/dir1/include : <location>. ;
|
||||
link-directory dir2-link : src/dir2/include : <location>. ;
|
||||
""")
|
||||
|
||||
t.write("src/dir1/include/file1.h", "file1")
|
||||
t.write("src/dir2/include/file2.h", "file2")
|
||||
|
||||
t.run_build_system(["dir1-link"])
|
||||
|
||||
t.expect_addition("include/file1.h")
|
||||
t.expect_content("include/file1.h", "file1")
|
||||
ignore_config(t)
|
||||
t.expect_nothing_more()
|
||||
|
||||
t.run_build_system(["dir2-link"])
|
||||
|
||||
t.expect_addition("include/file2.h")
|
||||
t.expect_content("include/file2.h", "file2")
|
||||
# If include is a symlink to src/dir1/include, then
|
||||
# we have to delete it and add a directory.
|
||||
t.ignore_removal("include/file1.h")
|
||||
ignore_config(t)
|
||||
t.expect_nothing_more()
|
||||
|
||||
t.cleanup()
|
||||
|
||||
def test_merge_recursive():
|
||||
"Test merging several directories including common prefixes"
|
||||
t = BoostBuild.Tester()
|
||||
t.write("jamroot.jam", """\
|
||||
import link ;
|
||||
link-directory dir1-link : src/dir1/include : <location>. ;
|
||||
link-directory dir2-link : src/dir2/include : <location>. ;
|
||||
link-directory dir3-link : src/dir3/include : <location>. ;
|
||||
""")
|
||||
|
||||
t.write("src/dir1/include/file1.h", "file1")
|
||||
t.write("src/dir2/include/file2.h", "file2")
|
||||
t.write("src/dir2/include/nested/file3.h", "file3")
|
||||
t.write("src/dir3/include/nested/file4.h", "file4")
|
||||
|
||||
t.run_build_system()
|
||||
|
||||
t.expect_addition("include/file1.h")
|
||||
t.expect_content("include/file1.h", "file1")
|
||||
t.expect_addition("include/file2.h")
|
||||
t.expect_content("include/file2.h", "file2")
|
||||
t.expect_addition("include/nested/file3.h")
|
||||
t.expect_content("include/nested/file3.h", "file3")
|
||||
t.expect_addition("include/nested/file4.h")
|
||||
t.expect_content("include/nested/file4.h", "file4")
|
||||
ignore_config(t)
|
||||
t.expect_nothing_more()
|
||||
|
||||
t.cleanup()
|
||||
|
||||
def test_include_scan():
|
||||
"""Make sure that the #include scanner finds the headers"""
|
||||
t = BoostBuild.Tester()
|
||||
t.write("jamroot.jam", """\
|
||||
import link ;
|
||||
link-directory dir1-link : src/dir1/include : <location>. ;
|
||||
link-directory dir2-link : src/dir2/include : <location>. ;
|
||||
obj test : test.cpp :
|
||||
<include>include
|
||||
<implicit-dependency>dir1-link
|
||||
<implicit-dependency>dir2-link ;
|
||||
""")
|
||||
|
||||
t.write("src/dir1/include/file1.h", "#include <file2.h>\n")
|
||||
t.write("src/dir2/include/file2.h", "int f();\n")
|
||||
t.write("test.cpp", """\
|
||||
#include <file1.h>
|
||||
int main() { f(); }
|
||||
""");
|
||||
|
||||
t.run_build_system(["test"])
|
||||
|
||||
t.expect_addition("bin/$toolset/debug/test.obj")
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_nothing_more()
|
||||
|
||||
t.cleanup()
|
||||
|
||||
test_basic()
|
||||
test_merge_two()
|
||||
test_merge_existing()
|
||||
test_merge_recursive()
|
||||
test_include_scan()
|
||||
@@ -44,7 +44,7 @@ if [ qt5.initialized ]
|
||||
[ link qtdeclarative.cpp /qt5//QtDeclarative ]
|
||||
|
||||
# QtQuick version2
|
||||
[ run qtquick.cpp /qt5//QtQuick : : $(CWD)/qtquick.qml ]
|
||||
[ run qtquick.cpp /qt5//QtQuick : -platform offscreen : $(CWD)/qtquick.qml ]
|
||||
|
||||
# Help systems.
|
||||
[ link qthelp.cpp /qt5//QtHelp ]
|
||||
|
||||
53
v2/test/source_order.py
Executable file
53
v2/test/source_order.py
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2013 Steven Watanabe
|
||||
# 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)
|
||||
|
||||
# Tests that action sources are not reordered
|
||||
|
||||
import BoostBuild
|
||||
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("check-order.jam", """\
|
||||
import type ;
|
||||
import generators ;
|
||||
|
||||
type.register ORDER_TEST : order-test ;
|
||||
|
||||
SPACE = " " ;
|
||||
nl = "\n" ;
|
||||
actions check-order
|
||||
{
|
||||
echo$(SPACE)$(>[1])$(SPACE)>$(<[1])
|
||||
echo$(SPACE)$(>[2-])$(SPACE)>>$(<[1])$(nl)
|
||||
}
|
||||
|
||||
generators.register-composing check-order.check-order : C : ORDER_TEST ;
|
||||
""")
|
||||
|
||||
# The aliases are necessary for this test, since
|
||||
# the targets were sorted by virtual target
|
||||
# id, not by file name.
|
||||
t.write("jamroot.jam", """\
|
||||
import check-order ;
|
||||
alias file1 : file1.c ;
|
||||
alias file2 : file2.c ;
|
||||
alias file3 : file3.c ;
|
||||
order-test check : file2 file1 file3 ;
|
||||
""")
|
||||
|
||||
t.write("file1.c", "")
|
||||
t.write("file2.c", "")
|
||||
t.write("file3.c", "")
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition("bin/$toolset/debug/check.order-test")
|
||||
t.expect_content("bin/$toolset/debug/check.order-test", """\
|
||||
file2.c
|
||||
file1.c
|
||||
file3.c
|
||||
""", True)
|
||||
|
||||
t.cleanup()
|
||||
@@ -182,6 +182,7 @@ tests = ["absolute_sources",
|
||||
"core_actions_quietly",
|
||||
"core_at_file",
|
||||
"core_bindrule",
|
||||
"core_multifile_actions",
|
||||
"core_nt_cmd_line",
|
||||
"core_option_d2",
|
||||
"core_option_l",
|
||||
@@ -220,6 +221,7 @@ tests = ["absolute_sources",
|
||||
"lib_source_property",
|
||||
"library_chain",
|
||||
"library_property",
|
||||
"link",
|
||||
"load_order",
|
||||
"loop",
|
||||
"make_rule",
|
||||
@@ -251,6 +253,7 @@ tests = ["absolute_sources",
|
||||
"skipping",
|
||||
"sort_rule",
|
||||
"source_locations",
|
||||
"source_order",
|
||||
"space_in_path",
|
||||
"stage",
|
||||
"standalone",
|
||||
|
||||
@@ -178,6 +178,7 @@ rule print-error ( location message * )
|
||||
|
||||
rule make-error ( message * )
|
||||
{
|
||||
import errors ;
|
||||
return [ errors.nearest-user-location ] $(message) ;
|
||||
}
|
||||
|
||||
@@ -204,7 +205,6 @@ rule check-docbook-xsl-dir ( )
|
||||
{
|
||||
if ! [ path.glob $(.docbook-xsl-dir) : common/common.xsl ]
|
||||
{
|
||||
import errors ;
|
||||
.error-message = [ make-error BoostBook: could not find docbook XSL stylesheets
|
||||
in: [ path.native $(.docbook-xsl-dir) ] ] ;
|
||||
}
|
||||
@@ -223,7 +223,6 @@ rule check-docbook-dtd-dir ( )
|
||||
{
|
||||
if ! [ path.glob $(.docbook-dtd-dir) : docbookx.dtd ]
|
||||
{
|
||||
import errors ;
|
||||
.error-message = [ make-error BoostBook: could not find docbook DTD in: [
|
||||
path.native $(.docbook-dtd-dir) ] ] ;
|
||||
}
|
||||
@@ -278,7 +277,6 @@ rule check-boostbook-dir ( boostbook-dir ? )
|
||||
{
|
||||
if $(boostbook-dir) && ! [ path.glob $(boostbook-dir) : xsl ]
|
||||
{
|
||||
import errors ;
|
||||
.error-message = [ make-error BoostBook: could not find boostbook in: [ path.native
|
||||
$(boostbook-dir) ] ] ;
|
||||
}
|
||||
|
||||
@@ -23,10 +23,9 @@ import indirect ;
|
||||
import property ;
|
||||
import property-set ;
|
||||
|
||||
header = jconfig.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h jpeglib.h
|
||||
jversion.h ;
|
||||
header = jpeglib.h ;
|
||||
|
||||
names = libjpeg ;
|
||||
names = jpeg ;
|
||||
|
||||
sources = jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c
|
||||
jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c
|
||||
@@ -166,7 +165,7 @@ rule init (
|
||||
}
|
||||
else if $(source-path) && ! $(no-build-from-source)
|
||||
{
|
||||
build-name ?= z ;
|
||||
build-name ?= jpeg ;
|
||||
library-id = [ CALC $(library-id) + 1 ] ;
|
||||
tag = [ MATCH ^@?(.*)$ : $(tag) ] ;
|
||||
if $(tag) && ! [ MATCH ^([^%]*)%([^%]+)$ : $(tag) ]
|
||||
@@ -24,7 +24,7 @@ import property ;
|
||||
import property-set ;
|
||||
|
||||
header = png.h ;
|
||||
names = libpng ;
|
||||
names = png ;
|
||||
|
||||
sources = png.c pngerror.c pngget.c pngmem.c pngpread.c pngread.c pngrio.c pngrtran.c pngrutil.c
|
||||
pngset.c pngtrans.c pngwio.c pngwrite.c pngwtran.c pngwutil.c ;
|
||||
@@ -124,7 +124,7 @@ rule init (
|
||||
condition = [ property-set.create [ $(condition).base ] ] ;
|
||||
|
||||
local no-build-from-source ;
|
||||
# Ignore environmental ZLIB_SOURCE if this initialization
|
||||
# Ignore environmental LIBPNG_SOURCE if this initialization
|
||||
# requested to search for a specific pre-built library.
|
||||
if $(library-path) || $(include-path) || $(library-name)
|
||||
{
|
||||
@@ -140,7 +140,7 @@ rule init (
|
||||
}
|
||||
}
|
||||
|
||||
source-path ?= [ modules.peek : ZLIB_SOURCE ] ;
|
||||
source-path ?= [ modules.peek : LIBPNG_SOURCE ] ;
|
||||
|
||||
if $(.configured.$(condition))
|
||||
{
|
||||
@@ -159,7 +159,7 @@ rule init (
|
||||
}
|
||||
else if $(source-path) && ! $(no-build-from-source)
|
||||
{
|
||||
build-name ?= z ;
|
||||
build-name ?= png ;
|
||||
library-id = [ CALC $(library-id) + 1 ] ;
|
||||
tag = [ MATCH ^@?(.*)$ : $(tag) ] ;
|
||||
if $(tag) && ! [ MATCH ^([^%]*)%([^%]+)$ : $(tag) ]
|
||||
@@ -193,7 +193,7 @@ rule init (
|
||||
<include>$(source-path)
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
|
||||
<link>shared:<define>ZLIB_DLL
|
||||
<link>shared:<define>LIBPNG_DLL
|
||||
:
|
||||
: <include>$(source-path) ] ;
|
||||
}
|
||||
@@ -23,9 +23,8 @@ import indirect ;
|
||||
import property ;
|
||||
import property-set ;
|
||||
|
||||
header = tiff.h tiffio.hxx ;
|
||||
|
||||
names = libtiff ;
|
||||
header = tiff.h ;
|
||||
names = tiff ;
|
||||
|
||||
sources = tif_aux.c tif_close.c tif_codec.c tif_color.c tif_compress.c tif_dir.c tif_dirinfo.c
|
||||
tif_dirread.c tif_dirwrite.c tif_dumpmode.c tif_error.c tif_extension.c tif_fax3.c tif_fax3sm.c
|
||||
@@ -163,7 +162,7 @@ rule init (
|
||||
}
|
||||
else if $(source-path) && ! $(no-build-from-source)
|
||||
{
|
||||
build-name ?= z ;
|
||||
build-name ?= tiff ;
|
||||
library-id = [ CALC $(library-id) + 1 ] ;
|
||||
tag = [ MATCH ^@?(.*)$ : $(tag) ] ;
|
||||
if $(tag) && ! [ MATCH ^([^%]*)%([^%]+)$ : $(tag) ]
|
||||
433
v2/tools/link.jam
Normal file
433
v2/tools/link.jam
Normal file
@@ -0,0 +1,433 @@
|
||||
# Copyright 2012 Steven Watanabe
|
||||
# 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)
|
||||
|
||||
import os ;
|
||||
import targets ;
|
||||
import project ;
|
||||
import "class" : new ;
|
||||
import virtual-target ;
|
||||
import configure ;
|
||||
import path ;
|
||||
import property ;
|
||||
import property-set ;
|
||||
import common ;
|
||||
|
||||
rule get-root-project ( project )
|
||||
{
|
||||
# Find the root project.
|
||||
local root-project = $(project) ;
|
||||
root-project = [ $(root-project).project-module ] ;
|
||||
while
|
||||
[ project.attribute $(root-project) parent-module ] &&
|
||||
[ project.attribute $(root-project) parent-module ] != user-config &&
|
||||
[ project.attribute $(root-project) parent-module ] != project-config
|
||||
{
|
||||
root-project = [ project.attribute $(root-project) parent-module ] ;
|
||||
}
|
||||
return $(root-project) ;
|
||||
}
|
||||
|
||||
TOUCH = [ common.file-touch-command ] ;
|
||||
|
||||
actions touch {
|
||||
$(TOUCH) "$(<)"
|
||||
}
|
||||
|
||||
rule can-symlink ( project : ps )
|
||||
{
|
||||
if ! $(.can-symlink)
|
||||
{
|
||||
local root-project = [ get-root-project $(project) ] ;
|
||||
|
||||
local source-target = [ new file-target test-symlink-source : :
|
||||
$(project) : [ new action : link.touch ] ] ;
|
||||
local target = [ new file-target test-symlink : :
|
||||
$(project) : [ new action $(source-target) : link.mklink ] ] ;
|
||||
|
||||
if [ configure.try-build $(target) : $(ps) : "symlinks supported" ]
|
||||
{
|
||||
.can-symlink = true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
.can-symlink = false ;
|
||||
}
|
||||
}
|
||||
if $(.can-symlink) = true
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rule can-hardlink ( project : ps )
|
||||
{
|
||||
if ! $(.can-hardlink)
|
||||
{
|
||||
local root-project = [ get-root-project $(project) ] ;
|
||||
|
||||
local source-target = [ new file-target test-hardlink-source : :
|
||||
$(project) : [ new action : link.touch ] ] ;
|
||||
local target = [ new file-target test-hardlink : :
|
||||
$(project) : [ new action $(source-target) : link.hardlink ] ] ;
|
||||
|
||||
if [ configure.try-build $(target) : $(ps) : "hardlinks supported" ]
|
||||
{
|
||||
.can-hardlink = true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
.can-hardlink = false ;
|
||||
}
|
||||
}
|
||||
if $(.can-hardlink) = true
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
|
||||
class file-or-directory-reference : basic-target
|
||||
{
|
||||
import virtual-target ;
|
||||
import property-set ;
|
||||
import path ;
|
||||
|
||||
rule construct ( name : source-targets * : property-set )
|
||||
{
|
||||
return [ property-set.empty ] [ virtual-target.from-file $(self.name) :
|
||||
[ location ] : $(self.project) ] ;
|
||||
}
|
||||
|
||||
# Returns true if the referred file really exists.
|
||||
rule exists ( )
|
||||
{
|
||||
location ;
|
||||
return $(self.file-path) ;
|
||||
}
|
||||
|
||||
# Returns the location of target. Needed by 'testing.jam'.
|
||||
rule location ( )
|
||||
{
|
||||
if ! $(self.file-location)
|
||||
{
|
||||
local source-location = [ $(self.project).get source-location ] ;
|
||||
for local src-dir in $(source-location)
|
||||
{
|
||||
if ! $(self.file-location)
|
||||
{
|
||||
local location = [ path.root $(self.name) $(src-dir) ] ;
|
||||
if [ path.exists [ path.native $(location) ] ]
|
||||
{
|
||||
self.file-location = $(src-dir) ;
|
||||
self.file-path = $(location) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $(self.file-location) ;
|
||||
}
|
||||
}
|
||||
|
||||
class symlink-target-class : basic-target
|
||||
{
|
||||
import path ;
|
||||
import virtual-target ;
|
||||
import link ;
|
||||
import os ;
|
||||
import type ;
|
||||
rule construct ( name : source-target : property-set )
|
||||
{
|
||||
local location = [ path.join
|
||||
[ $(source-target).path ] [ $(source-target).name ] ] ;
|
||||
local files = [ path.glob-tree $(location) : * ] ;
|
||||
local targets ;
|
||||
|
||||
link.can-symlink $(self.project) : $(property-set) ;
|
||||
link.can-hardlink $(self.project) : $(property-set) ;
|
||||
|
||||
if [ $(property-set).get <location> ]
|
||||
{
|
||||
property-set = [ property-set.create
|
||||
[ property.select <location> : [ $(property-set).raw ] ] ] ;
|
||||
}
|
||||
else
|
||||
{
|
||||
local path,relative-to-build-dir = [ $(property-set).target-path ] ;
|
||||
local path = $(path,relative-to-build-dir[1]) ;
|
||||
local relative-to-build-dir = $(path,relative-to-build-dir[2]) ;
|
||||
|
||||
if $(relative-to-build-dir)
|
||||
{
|
||||
path = [ path.join [ $(self.project).build-dir ] $(path) ] ;
|
||||
}
|
||||
|
||||
property-set = [ property-set.create <location>$(path) ] ;
|
||||
}
|
||||
|
||||
local a = [ new non-scanning-action $(source-target) :
|
||||
link.do-link-recursively : $(property-set) ] ;
|
||||
|
||||
local t = [ new notfile-target $(name)
|
||||
: $(self.project) : $(a) ] ;
|
||||
|
||||
return [ property-set.empty ] [ virtual-target.register $(t) ] ;
|
||||
}
|
||||
}
|
||||
|
||||
rule do-file-link
|
||||
{
|
||||
local target = [ path.native [ path.relative-to [ path.pwd ] $(<) ] ] ;
|
||||
local source = [ path.native [ path.relative-to [ path.pwd ] $(>) ] ] ;
|
||||
LOCATE on $(target) = . ;
|
||||
DEPENDS $(.current-target) : $(target) ;
|
||||
if $(.can-hardlink) = true
|
||||
{
|
||||
DEPENDS $(target) : $(source) ;
|
||||
link.hardlink $(target) : $(source) ;
|
||||
}
|
||||
else if $(.can-symlink) = true
|
||||
{
|
||||
link.mklink $(target) : $(source) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEPENDS $(target) : $(source) ;
|
||||
common.copy $(target) : $(source) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule do-link
|
||||
{
|
||||
local target = [ path.native [ path.relative-to [ path.pwd ] $(<) ] ] ;
|
||||
local source = [ path.native [ path.relative-to [ path.pwd ] $(>) ] ] ;
|
||||
local relative = [ path.native [ path.relative-to [ path.parent $(<) ] $(>) ] ] ;
|
||||
if ! [ on $(target) return $(MKLINK_OR_DIR) ]
|
||||
{
|
||||
LOCATE on $(target) = . ;
|
||||
DEPENDS $(.current-target) : $(target) ;
|
||||
mklink-or-dir $(target) : $(source) ;
|
||||
}
|
||||
if [ os.name ] = NT
|
||||
{
|
||||
MKLINK_OR_DIR on $(target) = mklink /D \"$(target)\" \"$(relative)\" ;
|
||||
}
|
||||
else
|
||||
{
|
||||
MKLINK_OR_DIR on $(target) = ln -s $(relative) $(target) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule do-split
|
||||
{
|
||||
local target = [ path.native [ path.relative-to [ path.pwd ] $(<) ] ] ;
|
||||
if ! [ on $(target) return $(MKLINK_OR_DIR) ]
|
||||
{
|
||||
LOCATE on $(target) = . ;
|
||||
DEPENDS $(.current-target) : $(target) ;
|
||||
common.mkdir $(target) ;
|
||||
}
|
||||
MKLINK_OR_DIR on $(target) = mkdir \"$(target)\" ;
|
||||
}
|
||||
|
||||
rule do-rm
|
||||
{
|
||||
local target = [ path.native [ path.relative-to [ path.pwd ] $(<) ] ] ;
|
||||
ALWAYS $(target) ;
|
||||
RM on $(target) = rmdir ;
|
||||
link.rm $(target) ;
|
||||
}
|
||||
|
||||
rule mklink-or-dir
|
||||
{
|
||||
NOUPDATE $(<) ;
|
||||
}
|
||||
|
||||
actions mklink-or-dir
|
||||
{
|
||||
$(MKLINK_OR_DIR)
|
||||
}
|
||||
|
||||
rule link-entries ( target : files * : split ? )
|
||||
{
|
||||
for local s in $(files)
|
||||
{
|
||||
local t = [ path.join $(target) [ path.basename $(s) ] ] ;
|
||||
if ! $(.known-dirs.$(t))
|
||||
{
|
||||
local t = [ path.native [ path.relative-to [ path.pwd ] $(t) ] ] ;
|
||||
local s = [ path.native [ path.relative-to [ path.pwd ] $(target) ] ] ;
|
||||
LOCATE on $(t) = . ;
|
||||
DEPENDS $(t) : $(s) ;
|
||||
NOUPDATE $(s) ;
|
||||
}
|
||||
if $(split)
|
||||
{
|
||||
link-recursively $(t) : $(s) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
link-entries $(t) : [ path.glob $(s) : * ] ;
|
||||
}
|
||||
}
|
||||
if ! $(.known-dirs.$(target))
|
||||
{
|
||||
.known-dirs.$(target) += $(files) ;
|
||||
.known-dirs.base.$(target) = $(.current-target) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule link-recursively ( target : source : no-recurse ? )
|
||||
{
|
||||
local split ;
|
||||
if [ CHECK_IF_FILE [ path.native $(source) ] ]
|
||||
{
|
||||
do-file-link $(target) : $(source) ;
|
||||
}
|
||||
else if $(.known-dirs.$(target)) && ! $(no-recurse)
|
||||
{
|
||||
split = true ;
|
||||
if ! $(.split-dirs.$(target))
|
||||
{
|
||||
local .current-target = $(.known-dirs.base.$(target)) ;
|
||||
for local s in $(.known-dirs.$(target))
|
||||
{
|
||||
local t = [ path.join $(target) [ path.basename $(s) ] ] ;
|
||||
link-recursively $(t) : $(s) : flat ;
|
||||
}
|
||||
if [ READLINK [ path.native $(target) ] ]
|
||||
{
|
||||
do-rm $(target) ;
|
||||
}
|
||||
do-split $(target) ;
|
||||
.split-dirs.$(target) = true ;
|
||||
}
|
||||
}
|
||||
else if [ path.exists [ path.native $(target) ] ]
|
||||
{
|
||||
local link-target = [ READLINK [ path.native $(target) ] ] ;
|
||||
if $(link-target)
|
||||
{
|
||||
local full-path =
|
||||
[ path.root [ path.make $(link-target) ] [ path.parent $(target) ] ] ;
|
||||
if $(full-path) != $(source)
|
||||
{
|
||||
do-rm $(target) ;
|
||||
do-split $(target) ;
|
||||
split = true ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do-split $(target) ;
|
||||
split = true ;
|
||||
}
|
||||
}
|
||||
else if $(.can-symlink) = false
|
||||
{
|
||||
if [ READLINK [ path.native $(target) ] ]
|
||||
{
|
||||
do-rm $(target) ;
|
||||
}
|
||||
do-split $(target) ;
|
||||
split = true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
do-link $(target) : $(source) ;
|
||||
}
|
||||
|
||||
if ! $(no-recurse)
|
||||
{
|
||||
link-entries $(target) : [ path.glob $(source) : * ] : $(split) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule do-link-recursively ( target : source : properties * )
|
||||
{
|
||||
local target-path = [ property.select <location> : $(properties) ] ;
|
||||
local source-path = [ on $(source) return $(LOCATE) ] [ on $(source) return $(SEARCH) ] ;
|
||||
|
||||
local absolute-target = [ path.root
|
||||
[ path.join [ path.make $(target-path[1]:G=) ]
|
||||
[ path.basename [ path.make $(source:G=) ] ] ]
|
||||
[ path.pwd ] ] ;
|
||||
|
||||
local absolute-source = [ path.root
|
||||
[ path.root [ path.make $(source:G=) ]
|
||||
[ path.make $(source-path[1]) ] ]
|
||||
[ path.pwd ] ] ;
|
||||
|
||||
local .current-target = $(target) ;
|
||||
|
||||
link-recursively $(absolute-target) : $(absolute-source) ;
|
||||
}
|
||||
|
||||
rule mklink
|
||||
{
|
||||
local target-path = [ on $(<) return $(LOCATE) ] [ on $(<) return $(SEARCH) ] . ;
|
||||
local source-path = [ on $(>) return $(LOCATE) ] [ on $(>) return $(SEARCH) ] . ;
|
||||
local relative-path = [ path.relative-to
|
||||
[ path.parent [ path.join [ path.root [ path.make $(target-path[1]) ] [ path.pwd ] ] [ path.make $(<:G=) ] ] ]
|
||||
[ path.join [ path.root [ path.make $(source-path[1]) ] [ path.pwd ] ] [ path.make $(>:G=) ] ] ] ;
|
||||
|
||||
PATH_TO_SOURCE on $(<) = [ path.native $(relative-path) ] ;
|
||||
NOUPDATE $(<) ;
|
||||
}
|
||||
|
||||
if [ os.name ] = NT
|
||||
{
|
||||
|
||||
actions mklink
|
||||
{
|
||||
if exist "$(<)" del "$(<)"
|
||||
mklink "$(<)" "$(PATH_TO_SOURCE)"
|
||||
}
|
||||
|
||||
actions hardlink
|
||||
{
|
||||
if exist "$(<)" del "$(<)"
|
||||
mklink /H "$(<)" "$(>)"
|
||||
}
|
||||
|
||||
actions rm
|
||||
{
|
||||
rmdir "$(<)"
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
actions mklink
|
||||
{
|
||||
ln -f -s "$(PATH_TO_SOURCE)" "$(<)"
|
||||
}
|
||||
|
||||
actions hardlink
|
||||
{
|
||||
ln -f "$(>)" "$(<)"
|
||||
}
|
||||
|
||||
actions rm
|
||||
{
|
||||
rm "$(<)"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rule link-directory ( name : sources : requirements * : default-build * : usage-requirements * )
|
||||
{
|
||||
local project = [ project.current ] ;
|
||||
sources = [ new file-or-directory-reference $(sources) : $(project) ] ;
|
||||
targets.main-target-alternative $(sources) ;
|
||||
return [ targets.main-target-alternative
|
||||
[ new symlink-target-class $(name) : $(project)
|
||||
: [ targets.main-target-sources $(sources) : $(name) : no-renaming ]
|
||||
: [ targets.main-target-requirements $(requirements) : $(project) ]
|
||||
: [ targets.main-target-default-build : $(project) ]
|
||||
: [ targets.main-target-usage-requirements $(usage-requirements) :
|
||||
$(project) ] ] ] ;
|
||||
}
|
||||
|
||||
IMPORT $(__name__) : link-directory : : link-directory ;
|
||||
@@ -314,7 +314,7 @@ rule init ( mpicxx ? : options * : mpirun-with-options * )
|
||||
|
||||
# Prepend COMPILER as the executable name, to match the format of
|
||||
# other compilation commands.
|
||||
compile_flags = "COMPILER $(compile_flags)" ;
|
||||
compile_flags = "COMPILER $(compile_flags) -DOMPI_SKIP_MPICXX " ;
|
||||
link_flags = "COMPILER $(link_flags)" ;
|
||||
}
|
||||
# Look for LAM-MPI's -showme
|
||||
|
||||
@@ -55,7 +55,7 @@ type.register PDB : pdb ;
|
||||
# using msvc : 6.5 : cl.exe ;
|
||||
# using msvc : 7.0 : Y:/foo/bar/cl.exe ;
|
||||
#
|
||||
# The version parameter may be ommited:
|
||||
# The version parameter may be omitted:
|
||||
#
|
||||
# using msvc : : Z:/foo/bar/cl.exe ;
|
||||
#
|
||||
@@ -901,9 +901,9 @@ local rule configure-really ( version ? : options * )
|
||||
|
||||
setup-$(c) = [ feature.get-values <setup-$(c)> : $(options) ] ;
|
||||
|
||||
if ! $(setup-$(c))-is-not-empty
|
||||
if ! $(setup-$(c))-is-defined
|
||||
{
|
||||
if $(global-setup)-is-not-empty
|
||||
if $(global-setup)-is-defined
|
||||
{
|
||||
setup-$(c) = $(global-setup) ;
|
||||
|
||||
@@ -916,7 +916,8 @@ local rule configure-really ( version ? : options * )
|
||||
}
|
||||
else
|
||||
{
|
||||
setup-$(c) = [ locate-default-setup $(command) : $(parent) : $(default-setup-$(c)) ] ;
|
||||
setup-$(c) = [ locate-default-setup $(command) :
|
||||
$(parent) : $(default-setup-$(c)) ] ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1381,7 +1382,8 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
|
||||
merom-xe kentsfield kentsfield-xe penryn wolfdale
|
||||
yorksfield nehalem sandy-bridge ivy-bridge haswell ;
|
||||
.cpu-type-amd64 = k8 opteron athlon64 athlon-fx k8-sse3 opteron-sse3
|
||||
athlon64-sse3 amdfam10 barcelona bdver1 bdver2 bdver3 btver1 btver2 ;
|
||||
athlon64-sse3 amdfam10 barcelona bdver1 bdver2 bdver3
|
||||
btver1 btver2 ;
|
||||
.cpu-type-g7 = pentium4 pentium4m athlon athlon-tbird athlon-4 athlon-xp
|
||||
athlon-mp $(.cpu-type-em64t) $(.cpu-type-amd64) ;
|
||||
.cpu-type-itanium = itanium itanium1 merced ;
|
||||
|
||||
@@ -71,7 +71,7 @@ type.register('PDB',['pdb'])
|
||||
# using msvc : 6.5 : cl.exe ;
|
||||
# using msvc : 7.0 : Y:/foo/bar/cl.exe ;
|
||||
#
|
||||
# The version parameter may be ommited:
|
||||
# The version parameter may be omitted:
|
||||
#
|
||||
# using msvc : : Z:/foo/bar/cl.exe ;
|
||||
#
|
||||
|
||||
@@ -1234,7 +1234,7 @@ rule capture-output ( target : sources * : properties * )
|
||||
# Oddly, host-os is not in properties, so grab the default value.
|
||||
local host-os = [ feature.defaults host-os ] ;
|
||||
host-os = $(host-os:G=) ;
|
||||
if $(target-os) != $(host-os)
|
||||
if $(target-os) != $(host-os) && $(target-os) in windows cygwin && $(host-os) in windows cygwin
|
||||
{
|
||||
PYTHONPATH = [ sequence.transform $(host-os)-to-$(target-os)-path :
|
||||
$(PYTHONPATH) ] ;
|
||||
|
||||
@@ -680,7 +680,7 @@ flags qt5.moc DEFINES <define> ;
|
||||
#
|
||||
actions moc
|
||||
{
|
||||
$(.BINPREFIX[-1])/moc -f $(>) -o $(<) @"@($(<).rsp:E=-D$(DEFINES)$(.nl) -I$(INCLUDES:T)$(.nl))"
|
||||
$(.BINPREFIX[-1])/moc $(>) -o $(<) @"@($(<).rsp:E=-D$(DEFINES)$(.nl) -I$(INCLUDES:T)$(.nl))"
|
||||
}
|
||||
|
||||
# When moccing files for include only, we don't need -f, otherwise the generated
|
||||
|
||||
Reference in New Issue
Block a user