Diane Holt | 1 Jan 2002 22:33
Picon
Favicon

Re: Multiple Jambase files

Is it just the compiling that needs to be done using 'xcc', or do you need
to use that for the link as well?  If the former, it's pretty
straightforward to do what you want -- just add a switch in the case for
.c in the Object rule (in Jambase) to use the Cc rule/actions for .c files
under tools and an Xcc rule/actions (defined in your Jamrules) for all
others.

If you also need to use 'xcc' to do links, then you'll need to add more
stuff (obviously :) -- but it should still be doable.

Diane

--- Darrin Smart <darrin <at> suresoftware.com> wrote:
> 
> Sorry, substitute Jamrules for Jambase in the text below.
> 
>   - Darrin
> 
> On Saturday, December 22, 2001, at 05:19  PM, Darrin Smart wrote:
> 
> > Hi All,
> >
> > I've just started using Jam in an attempt to replace a very large 
> > set of recursive makefiles.
> >
> > Our project contains lots of deeply nested directories, basically 
> > in two branches. One branch is called "tools" and is a bunch of 
> > development tools built on the local machine. The other is called 
> > "src" which is cross-compiled using some of the programs in tools 
> > and some system-installed programs as well.
(Continue reading)

David Abrahams | 2 Jan 2002 17:48
Favicon
Gravatar

Re: Changes in my Jam guest branch

----- Original Message -----
From: "Craig McPheeters" <cmcpheeters <at> aw.sgi.com>

> > What is "the space and newline expansion trick?"
> > If I can use it to get around the line length limitation, it would be
> > great. Currently I am resorting to response files, but that's not
> > universally applicable.
>
> It works when there are other ways to get arguments in to a command, such
> as response files.  rc.exe doesn't allow them, so its harder to work with.
> The space/newline trick is in the archives, I should reply to an earlier
> message in the jamming mail list, I'm still sorta on holiday.  The trick
> is:
>
> SPACE = " " ;
> NEWLINE = "
> ";
>
> and then in an action block, if you have a bunch of files you want linked
> for example:
>
>      <at> echo off
>     set tmpfile="$(<).tmp"
>     if exist %tmpfile% $(RM) %tmpfile%
>     $(TOUCH) %tmpfile%
>     echo$(SPACE)$(>)>>%tmpfile%$(NEWLINE)
> ...
>     $(LINK) ...  <at> %tmpfile% ...
>
> That can create a really huge .bat file, but its ok, as each of the lines
(Continue reading)

Sawhney, Davinder | 2 Jan 2002 21:16

help - unsubscribe

Please unsubscribe

Davinder

-----Original Message-----
From: jamming-request <at> perforce.com [mailto:jamming-request <at> perforce.com]
Sent: Wednesday, January 02, 2002 3:05 PM
To: jamming <at> perforce.com
Subject: jamming digest, Vol 1 #292 - 2 msgs

Send jamming mailing list submissions to
	jamming <at> perforce.com

To subscribe or unsubscribe via the World Wide Web, visit
	http://maillist.perforce.com/mailman/listinfo/jamming
or, via email, send a message with subject or body 'help' to
	jamming-request <at> perforce.com

You can reach the person managing the list at
	jamming-admin <at> perforce.com

When replying, please edit your Subject line so it is more specific
than "Re: Contents of jamming digest..."

Today's Topics:

   1. Re: Multiple Jambase files (Diane Holt)
   2. Re: Changes in my Jam guest branch (David Abrahams)

--__--__--
(Continue reading)

BROSSIER Florent | 3 Jan 2002 13:46
Picon

Dependency with files with the same name in different directory

Let suppose I have the following files and directories.

- At root:

Jamrules
                        HDRS = $(TOPDIR)$(SLASH)Other ;

Jamfile
                         SubDir TOPDIR ;
                         SubInclude TOPDIR Test ;



- In the directory Other

foo.hpp
                          #error


- in the directory Test

Jamfile
                         SubDir TOPDIR Test ;
                         Main Test.exe : main.cpp ;

main.cpp
                          #include "foo.hpp"
                          int  main(int argc, char** argv)  { return 0; }


foo.hpp
                          // Empty



Now the problem:

When I start Jam. The compilation is ok. (Test/foo.hpp was included!)

If I modifie Test/foo.hpp and start Jam again nothing is done.

If I modifie Other/foo.hpp and start Jam again the executable is rebuild.


Is it a bug of Jam?
What can I do to solve this problem?

It seems that the problem comes from the HDRS variable which is used by Jam to scan for include files.
The current path is not included in the HDRS variable but is automatically added in the list of include path for the compilation before any others.


Thanks for your help.

Florent BROSSIER.

PS: I use Jam version 2.3 with no modifications.

Matt Armstrong | 3 Jan 2002 17:38

Re: Dependency with files with the same name in different directory

"BROSSIER Florent" <F.BROSSIER <at> csee-transport.fr> writes:

> Now the problem:
>
> When I start Jam. The compilation is ok. (Test/foo.hpp was included!)
>
> If I modifie Test/foo.hpp and start Jam again nothing is done.
>
> If I modifie Other/foo.hpp and start Jam again the executable is rebuild.
>
> Is it a bug of Jam?

Yes, I think there is a bug in Jambase here.

The Object rule in Jambase sets HDRS on targets to:

    $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS)

But it sets HDRSEARCH to:

    $(HDRS) $(SUBDIRHDRS) $(SEARCH_SOURCE) $(STDHDRS)

I think the bug is that the two do not specify the same order.  So the
compiler will search with one order, and Jam another.

HDRSEARCH should probably be:

    $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) $(STDHDRS)

> What can I do to solve this problem?

If you change the Object rule in Jambase to set HDRSEARCH the same way
it sets HDRS, Jam finds the correct foo.hpp file.  (put the Object
rule at the end of this message in your Jambase).

But please take notice: placing a header file with the same name
multiple times is also dangerous.  In this case, you should use
something called "header grist".  The safest way to do this is to put
this after every time you call SubDir:

    HDRGRIST = $(SOURCE_GRIST) ;

This way, each sub directory can find a different foo.hpp.  Without
this change, Jam will find one foo.hpp and stop there.  You will also
want to put this rule in your Jamrules:

rule FGristSourceFiles
{
    return [ FGristFiles $(<) ] ;
}

> It seems that the problem comes from the HDRS variable which is used
> by Jam to scan for include files.  The current path is not included
> in the HDRS variable but is automatically added in the list of
> include path for the compilation before any others.
>
> Thanks for your help.
>
> Florent BROSSIER.
>
> PS: I use Jam version 2.3 with no modifications.

rule Object
{
	local h ;

	# locate object and search for source, if wanted

	Clean clean : $(<) ;

	MakeLocate $(<) : $(LOCATE_TARGET) ;
	SEARCH on $(>) = $(SEARCH_SOURCE) ;

	# Save HDRS for -I$(HDRS) on compile.
	# We shouldn't need -I$(SEARCH_SOURCE) as cc can find headers
	# in the .c file's directory, but generated .c files (from
	# yacc, lex, etc) are located in $(LOCATE_TARGET), possibly
	# different from $(SEARCH_SOURCE).

	HDRS on $(<) = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;

	# handle #includes for source: Jam scans for headers with
	# the regexp pattern $(HDRSCAN) and then invokes $(HDRRULE)
	# with the scanned file as the target and the found headers
	# as the sources.  HDRSEARCH is the value of SEARCH used for
	# the found header files.  Finally, if jam must deal with 
	# header files of the same name in different directories,
	# they can be distinguished with HDRGRIST.

	# $(h) is where cc first looks for #include "foo.h" files.
	# If the source file is in a distant directory, look there.
	# Else, look in "" (the current directory).

	if $(SEARCH_SOURCE)
	{
	    h = $(SEARCH_SOURCE) ;
	}
	else
	{
	    h = "" ;
	}

	HDRRULE on $(>) = HdrRule ;
	HDRSCAN on $(>) = $(HDRPATTERN) ;
	#HDRSEARCH on $(>) = $(HDRS) $(SUBDIRHDRS) $(h) $(STDHDRS) ;
	HDRSEARCH on $(>) = $(h) $(HDRS) $(SUBDIRHDRS) $(STDHDRS) ;
	HDRGRIST on $(>) = $(HDRGRIST) ;

	# if source is not .c, generate .c with specific rule

	switch $(>:S)
	{
	    case .asm : As $(<) : $(>) ;
	    case .c :	Cc $(<) : $(>) ;
	    case .C :	C++ $(<) : $(>) ;
	    case .cc :	C++ $(<) : $(>) ;
	    case .cpp : C++ $(<) : $(>) ;
	    case .f :	Fortran $(<) : $(>) ;
	    case .l :	Cc $(<) : $(<:S=.c) ;
			Lex $(<:S=.c) : $(>) ;
	    case .s :	As $(<) : $(>) ;
	    case .y :	Cc $(<) : $(<:S=.c) ;
			Yacc $(<:S=.c) : $(>) ;
	    case * :	UserObject $(<) : $(>) ;
	}
}

--

-- 
matt

Matt Armstrong | 3 Jan 2002 20:01

Improved Header Scan Cache for Jam

I just submitted code to //guest/matt_armstrong/jam/hdrscan_cache that
implements a header scan cache for Jam.

This code is an incremental improvement over Craig McPheeters'
original version in //guest/craig_mcpheeters/jam/src/.  I've talked
with Craig and he plans to roll most or all of my changes into his
version.

I have even higher hopes -- I'd like it to make it into stock jam.
Rationale:

    - A header scan cache can improve things when HDRGRIST is in use.
      For example, with stock Jam if you always set HDRGRIST to
      $(SOURCE_GRIST), standard headers such as /usr/include/stdio.h
      will now get scanned once for each SubDir.  With the header scan
      cache, common headers will be scanned only once.

      This makes it practical to always use HDRGRIST.  This means that
      the stock Jambase can support multiple header files of the same
      name.  I think this rectifies a frequently encountered weakness
      in Jam.

      It is important to point out that you get this benefit
      regardless of whether the cache is saved to disk.

    - The header scan cache is persistent across runs of Jam only if
      the user wants it (controlled via the HCACHEFILE variable).  So
      by default Jam will not sprinkle cache files all of the source
      tree, and it is possible to use LOCATE to put the persistent
      copy of the cache in, e.g., a build output directory.

      Storing the header cache on disk can bring real benefits.  On
      the medium sized project I use jam for, it seems to speed jam
      startup (time to first build action) by a factor of 6.  People
      are happy to wait 15 seconds instead of 90.

      It is important to point out that about half of this speedup
      occurs even if the cache is not persistent, since our project
      makes heavy use of HDRGRIST to correctly find all the header
      files in the project.

    - The cache is implemented in such a way that it can never change
      the semantics of what Jam does.  The call to a target's HDRRULE
      will be identical with or without the cache code.

Here is the text of the README.header_scan_cache that is part of the
submit.

	This change implements a header scan cache in a form that
	(cross fingers) can be incorporated into the stock version of
	Jam.

	This code is taken from //guest/craig_mcpheeters/jam/src/ on
	the Perforce public depot.  Many thanks to Craig McPheeters
	for making his code available.  It is delimited by the
	OPT_HEADER_CACHE_EXT #define within the code.
	
	Jam has a facility to scan source files for other files they
	might include.  This code implements a cache of these scans,
	so the entire source tree need not be scanned each time jam is
	run.  This brings the following benefits:
	
	    - If a file would otherwise be scanned multiple times in a
	      single jam run (because the same file is represented by
	      multiple targets, perhaps each with a different grist),
	      it will now be scanned only once.  In this way, things
	      are faster even if the cache file is not present when
	      Jam is run.
	
	    - If a cache entry is present in the cache file when Jam
	      starts, and the file has not changed since the last time
	      it was scanned, Jam will not bother to re-scan it.  This
	      markedly increaces Jam startup times for large projects.
	
	This code has improvements over Craig McPheeters' original
	version.  I've described all of these changes to Craig and he
	intends to incorporate them back into his version.  The
	changes are:
	
	    - The actual name of the cache file is controlled by the
	      HCACHEFILE Jam variable.  If HCACHEFILE is left unset
	      (the default), reading and writing of a cache file is
	      not performed.  The cache is always used internally
	      regardless of HCACHEFILE, which helps when HDRGRIST
	      causes the same file to be scanned multiple times.
	
	      Setting LOCATE and SEARCH on the the HCACHEFILE works as
	      well, so you can place anywhere on disk you like or even
	      search for it in several directories.  You may also set
	      it in your environment to share it amongst all your
	      projects.
	
	    - The .jamdeps file is in a new format that allows binary
	      data to be in any of the fields, in particular the file
	      names.  The original code would break if a file name
	      contained the ' <at> ' or '\n' characters.  The format is
	      also versioned, allowing upgrades to automatically
	      ignore old .jamdeps files.  The format remains human
	      readable.  In addition, care has been taken to not add
	      the entry into the header cache until the entire record
	      has been successfully read from the file.
	
	    - The cache stores the value of HDRPATTERN with each cache
	      entry, and it is compared along with the file's date to
	      determine if there is a cache hit.  If the HDRPATTERN
	      does not match, it is treated as a cache miss.  This
	      allows HDRPATTERN to change without worrying about stale
	      cache entries.  It also allows the same file to be
	      scanned multiple times with different HDRPATTERN values.
	
	    - Each cache entry is given an "age" which is the maximum
	      number of times a given header cache entry can go unused
	      before it is purged from the cache.  This helps clean up
	      old entries in the .jamdeps file when files move around
	      or are removed from your project.
	
	      You control the maximum age with the HCACHEMAXAGE
	      variable.  If set to 0, no cache aging is performed.
	      Otherwise it is the number of times a jam must be run
	      before an unused cache entry is purged.  The default for
	      HCACHEMAXAGE if left unset is 100.
	
	    - Jambase itself is changed.
	
	      SubDir now always sets HDRGRIST to $(SOURCE_GRIST) so
	      header scanning can deal with multiple header files of
	      the same name in different directories.  With the header
	      cache, this does no longer incurs a performance penalty
	      -- a given file will still only be scanned once.
	
	      The FGristSourceFiles rule is now just an alias for
	      FGristFiles.  Header files do not necessarily have
	      global visibility, and the header cache eliminates any
	      performance penalty this might otherwise incur.
	
	Because of all these improvements, the following claims can be
	made about this header cache implementation that can not be
	made about Craig McPheeters' original version.
	
	    - The semantics of a Jam run will never be different
	      because of the header cache (the HDRPATTERN check
	      ensures this).
	
	    - It will never be necessary to delete .jamdeps to fix
	      obscure jam problems or purge old entries.

--

-- 
matt

rmg | 3 Jan 2002 20:57
Favicon

Jam release plan

Matt Armstrong wrote (WRT Improved Header Scan Cache for Jam):
> I have even higher hopes -- I'd like it to make it into stock jam.

Hi Matt and all Jammers at large.

I thought that this might be a good opening for me to let people where
we're at with work on a new release of Jam. (Even though I'll defer
talking about header scanning just now).

I hope to soon have (I'm aiming at next week, really!) an update to
//public/jam/... comprising the changes to Jam made internally at
Perforce since the 2.3 release.  This will likely be a single change
integrated into //public/jam, from a branch in //guest/richard_geiger/
where the individual changes from the Perforce internal version will
be imported. These changes will *not* be packaged into a new release
at this point... But you'll be thence be able to do integrations of
these changes from //public/jam/... into your //guest/.../jam/...
branches as desired, per the plan I outline here:

Christopher and I have done a triage to consider most other Jam
changes I'm aware of for inclusion in the new release (presumably this
will be Jam 2.4). Christopher reserves the right to be the final
arbiter on these decisions. In some cases, we'll take contributed
changes "as is"; in others, Christopher likes the intent of the
change, but wants to consider alternate implementations; in others, we
may decline to pick up the change altogether, at least for now.

I'll be contacting individual contributors of the changes we've
decided to take "wholesale". I'm hoping that, in most cases, these
individuals will be able to help by integrating the changes from
//public/jam/ into their own branches, which should make it easiest
for me to then integrate the individual features we want for Jam 2.4
into the //public/jam mainline.

Of course, anybody with a //guest Jam branch will be welcome and
encouraged to also integrate these changes.

At some point - hopefully before too many more weeks pass by - we'll
have a //public/jam/ that is ready to be packaged as Jam 2.4.

Beyond that, we can start a planning process for Jam 2.5, in hopes
that with a notch more of planning and coordination on my part, we can
do the best job of improving Jam, both for the "stock" and "custom"
versions.

Feedback always welcome!

Thanks,

 - Richard Geiger
   Open Source Engineer at Perforce

PS - I'm subscribed to "jamming", so it's not necessary or useful to
cc the "opensource <at> perforce.com" address to your postings to the
list.

Craig McPheeters | 3 Jan 2002 22:07
Picon

Re: Changes in my Jam guest branch

> > SPACE = " " ;
> > NEWLINE = "
> > ";
> >
> > and then in an action block, if you have a bunch of files you want linked
> > for example:
> >
> >      <at> echo off
> >     set tmpfile="$(<).tmp"
> >     if exist %tmpfile% $(RM) %tmpfile%
> >     $(TOUCH) %tmpfile%
> >     echo$(SPACE)$(>)>>%tmpfile%$(NEWLINE)
> > ...
> >     $(LINK) ...  <at> %tmpfile% ...
> >
> > That can create a really huge .bat file, but its ok, as each of the lines
> is
> > short.  The echo line expands into one line for each $(>) file.
> 
> Looking at this nefarious technique again, I see that it has certain
> advantages over what I've been doing. For one thing, in my scheme, if the
> link fails the response file is never removed. If I've forgotten a library,
> the response file is wrong and needs to be rebuilt, but according to the
> dates, it appears to be up-to-date. The downside of your scheme is that it's

Its not really my scheme, its something I picked up from the jam archives.
I sure like it though.

Also note that its a general technique.  It can be used to create response
files as well as many other types of action blocks.  Once you start using
the newline expansion trick, you'll find other uses for it.

> difficult to factor out the common logic for creating the response files
> from my many toolset definitions, but I don't think that's serious enough to
> avoid using it. In fact, I expect that it won't be an issue in an upcoming
> revision of the build system.
> 
> A question: why the explicit $(TOUCH)? Won't the redirected echo update the

The touch may not be required.  I know with some Unix shells, if you do:
  echo hi >> foo
and 'foo' doesn't exist, the '>>' fails as there is no file to append to.
Adding a touch there ensures the file exists, and that was its only intent.

Cheers,
 Craig.

> modification date? And why does the mod. date matter, anyway? The response
> file never appears in the dependency graph.
> 
> -Dave
> 
> 
> 

Matt Armstrong | 4 Jan 2002 01:37

Expressing "lazy always update" intermediate files

Let's say file c depends on b which depends on a

    a -> b -> c

File b is an intermediate file that, for various reasons, is best not
marked TEMPORARY (to make it concrete, it is a script that some jam
actions create, and sometimes people like to re-run b to create c
without running jam).

When I run jam, I want b to always be re-built, but only in the cases
where c is being built.

The dependency graph for b is complex (it depends on some of the
jamfiles in the project, the contents of various environment
variables, etc.) so it is simpler for it to always be rebuilt.
However, if I mark it with ALWAYS, then c is always rebuilt as well.

--

-- 
matt

Craig McPheeters | 4 Jan 2002 03:50
Picon

Re: Expressing "lazy always update" intermediate files

> From: "Matt Armstrong" <matt+jamming.7904ac <at> lickey.com>
> Subject: [jamming] Expressing "lazy always update" intermediate files
> Date: Thu, 03 Jan 2002 17:37:49 -0700
> 
> Let's say file c depends on b which depends on a
> 
>     a -> b -> c
> 
> File b is an intermediate file that, for various reasons, is best not
> marked TEMPORARY (to make it concrete, it is a script that some jam
> actions create, and sometimes people like to re-run b to create c
> without running jam).
> 
> When I run jam, I want b to always be re-built, but only in the cases
> where c is being built.
> 
> The dependency graph for b is complex (it depends on some of the
> jamfiles in the project, the contents of various environment
> variables, etc.) so it is simpler for it to always be rebuilt.
> However, if I mark it with ALWAYS, then c is always rebuilt as well.

(A depends on B = A -> B.  I use dependency arrows, not data flow.)

One approach to try is to introduce a new node or two.  Can you create a
new node, which has all the dependencies that 'c' normally would have, but
isn't actually a file?

Something like:

    <real>c -> b -> c -> a

with:
  NOTFILE c ;

or perhaps make the earlier 'c' a gristed NOTFILE node, and the eventual
'c' ungristed.  Its hard to know without knowing the details, and I don't
really want to know the details :-)

A different approach is to leave the original order, but assign two actions
with the b and c nodes.  The actions are processed in the order they are
called.  This is something like how a yacc action can produce two files, a
.c and a .h.  The graph for that is:
   yacc.c -> yacc.h -> <stuff>
If the .c doesn't depend on the .h, a multi-job build may try to use one 
of the files if a different job is processing the other.  Jam can't
scan the .c for headers until after its created.  (this is why the yacc
rule has the .c file include the .h explicitly.)

Assuming you want the script to be created by a separate action, I'll call
two rules.  If one action can create the script and the c file, only call
myCreateFile and have the action do both.

Something like:

--

rule myCreateScript 
{
    DEPENDS $(<[2]) : $(<[1]) ;
}

actions myCreateScript
{
    rm -f $(<[1])
    echo echo a new script > $(<[1])
    chmod 0755 $(<[1])
}

rule myCreateFile
{
    DEPENDS $(<[2]) : $(<[1]) ;
    DEPENDS $(<) : $(>) ;
}

actions myCreateFile 
{
    rm -f $(<[2])
    $(<[1]) > $(<[2])
}

myCreateScript b c ;
myCreateFile   b c : a ;

DEPENDS all : c ;
DEPENDS c : d ;

--

I think that works.  Of course the syntax can be improved, depending on
which of the nodes names can be automatically generated.  Call a higher
level rule which creates names and calls lower level rules, etc.

Cheers,
 Craig.

> -- 
> matt
> _______________________________________________
> jamming mailing list  -  jamming <at> perforce.com
> http://maillist.perforce.com/mailman/listinfo/jamming
> 


Gmane