In between attempting to get the new assembler up and running (currently dealing with XS issues), Robert Spiers and I have come up with a new make mechanism.
The syntax may change, and the build mechanism has a ways to go (It's simply running one step at a time in order, no parallelism or multiple processes), but the basic idea so far seems sound. Our replacement for the somewhat non-portable make mechanism relies entirely on perl, and so far, no external modules are required. The current version makes allowances for Win32 issues, but has not been tested on Win32 yet. Make.pl is a simple perl script that builds a dependency graph and satisfies a single target recursively. The Makefile it seeks to emulate follows: --cut here-- foo.o: foo.c cc -c foo.c bar.o: bar.c cc -c bar.c foo: foo.o bar.o cc -o foo foo.o bar.o --cut here-- This, of course, builds the binary 'foo' from the source files 'foo.c' and 'bar.c'. So far, with the exception of the need to explicitly declare a target, it's a one-to-one translation of the makefile. The perl translation of the Makefile above follows (with comments): --cut here-- # Create a compile target for 'foo.o'. "Compile targets" are actually objects # that can be queried to determine if they've been completed or not, and asked # how they want to be built. # Although the compile target is named 'CC' this, of course, doesn't mean that # 'cc' is used. The compiler name and arguments are determined based on the # current platform. my $foo_o = CC( # The 'Object()' syntax here simply takes into account the fact that # platforms such as Win32 require different extensions than UNIX. # The target is currently declared explicitly, but given the fact that we # already have the input file name, it would be easy to determine the # output file name should we want to declare 'output' explicitly. output => Object( input => 'foo' ), # The input is given an explicit file extension to accommodate for the fact # that the user may want to submit a .C file or .ch file to the compiler. # Should we not need that flexibility, the extension can be removed. input => 'foo.c', # foo.o: foo.c # Dependencies are either file names or objects, and as we'll see later on # can be arrays of these as well. dependsOn => 'foo.c', # cc -c foo.c ); my $bar_o = CC( output => Object( input => 'bar' ), input => 'bar.c', # bar.o: bar.c dependsOn => 'bar.c', # cc -c bar.c ); # The link statement is also platform-sensitive, and introduces another # platform-dependent directive, 'Executable'. This, of course, accounts for # the difference between Win32's '.exe' and UNIX's '' extension for file # names. In due course, the file name here should be stated without extension # of any kind. my $foo_exe = Link( output => Executable( input => 'foo' ), # Any directive can take an anonymous array of inputs, and they'll be # handled in the order declared. The Object declaration returns the same # name every time, so we could concievably cache these in scalars as well, # but to be pedantic I'm declaring them each time. input => [ Object(input=>'foo'), Object(input=>'bar') ], # foo: foo.o bar.o # And this can be dependent upon one or more files as well, # Take special note here that we're depending upon two *objects*, not files. # When time comes to determine if the link target needs to be done, the # script looks through these dependencies to see if 'foo.o' needs to be # rebuilt as well as comparing timestamps with 'foo.exe' to see if the link # needs to be rebuilt. dependsOn => [$foo_o, $bar_o], # cc -o foo foo.o bar.o ); # This is simply a directive that explicitly declares that 'foo' is a target. # Here, 'foo' is not an executable but a target name, that will be looked up # when 'make.pl foo' is run. $depends->{foo} = Target( input => 'foo', dependsOn => $foo_exe, ); --cut here-- This project is currently very much in an alpha state, but on my system it does handle the very limited set of dependencies you see here very well. Deleting files and rerunning make.pl does the right thing, as well as touch'ing files. I haven't expanded the makefile beyond what you see here yet, although once I'm certain of the foundation the number of available directives will grow, as will such incidentals as documentation and more error detection. Unlike the UNIX make tool, this application executes the required actions in linear order in a single process, letting each action complete before the next one is allowed to begin. In other words, no parallelism and no determining of which actions can be allowed to proceed in parallel without worries of race conditions. I'll commit this later in the week once I make two major alterations to the structure. The code as it stands builds the list of actions to be taken in parallel with checking the graph to determine whether a particular action needs to be taken or not. This needs to be decoupled so that a sane algorithm for determining which tasks can run in parallel can be accomplished. Also, support for multiple make targets such as: --cut here-- foo bar: foo.c bar.c --cut here-- doesn't exist yet. This probably needs to either be addressed or worked around in some fashion, and I admittedly haven't given this matter much thought. Also I'm not quite fond of how the back end looks, but I'm willing to expose the sort-of-OO-guts to let someone else write it as it -should- be done, but I feel that the important logic is there. It also needs a few more simple directives, such as 'Perl', 'Header', and 'Delete'. The latter may require some additional logic for directories, which brings me to the last item. Directory standards vary wildly across OSen, and this needs to be compensated for in some fashion. One approach I'm considering (and probably will do) is creating a 'FilePath' directive, something along the lines of C<$encoding_USascii = FilePath(relative=>[qw(encoding usascii.c)]);> and letting lower-level functions handle the task of converting the array to a usable path on the appropriate platform. C<FilePath(absolute=>[])> would do the obvious thing, although we might have to fall back to using UNIX path syntax for relative paths such as '../foo/bar.c'. I will make sure that 'make.pl' contains a translated copy of the current top-level Makefile.in before release. After the initial release of the new make.pl, running it will likely EAT YOUR HARD DRIVE. Now that I've sufficiently scared you, I'll reassure you that I'll comment out the nasty bits that actually run the dependencies and enable some debugging so you can watch how make.pl would have actually destroyed your filesystem had I let it run amok. Seriously though, with the probable exception of a few things that I won't be able to easily translate to the new system, it shouldn't do anything out of the ordinary. I hope. In any case, uncomment and run at your own peril. -- Jeff <[EMAIL PROTECTED]>