Module Writing for autodep
Copyright (c) 1997-98 By Kriang Lerdsuwanakij
email: lerdsuwa@scf.usc.edu
home page: http://www-scf.usc.edu/~lerdsuwa/util/

Introduction
============
	This document guide you about writing modules for autodep.  This 
requires a fairly good Perl knowledge, especially in nested structure, package
and object.  Modules extend autodep capability to handle target types besides 
the built-in such as `C', `C++'.  In fact, built-in types are also
implemented this way.  


Target Map Files
================
	Target map files are used to map between target types and modules 
that handle them.  The built-in map is called `targetmap' and is located in 
`/usr/local/share/autodep/modules' unless you overrided the default prefix 
(`/usr/local/') using configure script during installation.

	autodep will also search for map files `ad.targetmap' in current 
directory and directory given in the command line using -B option.  You can 
add new types by writing your own `ad.targetmap'.

	Both `targetmap' and `ad.targetmap' share the same structure and 
syntax.  Here is an example of built-in `targetmap'

#
# targetmap for autodep built-in types
#

C		StdC.pm
C++		StdC.pm
Cobj		StdC.pm
C++obj		StdC.pm

	For each row of data not counting blank lines and lines starting with
comments, there are two fields.  The first fields is the target type and the 
second is the filename to be invoked for the corresponding type.  Both
fields cannot contain any white spaces as autodep used them to separate
fields.  As in `ad.rule', comments (using `#') and line continuation (using 
backslash-new line) works in this file.  Filename must ends with `.pm'.

	Rules for naming target types
	-----------------------------
	- No spaces allowed inside the type name, quoting does not work.
	- It must consists of `a' to `z', `A' to `Z', `0' to `9', `_', `+'
	  `-' and `.'.  Although other symbols may work in this version, they 
	  are not guaranteed for future version.
	- Names starting with double underscores such as `__type' are 
	  reserved for internal uses.
	- Avoid using names with only lower/upper case difference (such as
	  having both `mytype' and `MyType').
	- Avoid using the same name as commands for `ad.rule' with possibly 
	  case difference such as `OUTPUT', `prepend', `CurDir', etc.
	- The sequence of loading map files is
		1. `targetmap' in `/usr/local/share/autodep/modules'
		2. `ad.targetmap' in directory specified in -B option
		3. `ad.targetmap' in current directory
	  Remapping the same target type to a different module is allowed.
	  If you want to map `C' targets to `MyC.pm' instead of `StdC.pm'.  
	  You can put the line

		C	MyC.pm

	  anywhere in ad.targetmap's.  Appending the line in `targetmap' or 
	  modifing `targetmap' directly also works but it is discouraged for 
	  projects you intend to distribute.

	Rules for selecting module filenames
	------------------------------------
	- Names starting with `Std' (such as `StdC' above) are reserved. 
	  Only modules distributing together with the official autodep package
	  are allowed such names.
	- Paths allowed to locate modules.  They cannot be used to 
	  distinguish modules with the same name but stored in different 
	  directories.  So having both `MyModule' and `../MyModule' (either 
	  in the same target map files or in different files) does not work 
	  as you might expect.


Module Structure
================

	For each module,  there are 5 required subroutines, `interface', 
`queryoption', `processoption', `new' and `output'.

	`interface' and `queryoption' are called for each module to query 
interface between autodep and modules.  This also make various options
available for use in ad.rule.

	`processoption' is called when an option handled by modules is
found in ad.rule.

	The rest, `new' and `output' subroutines handle the work of Makefile 
generation.

	Parameters supplied to these subroutines and return value autodep 
expects are given as follows:

	interface
	---------
	No parameters are supplied.  It should return the list contains
two elements.  The first element is the version of protocal the module used
to communicate with autodep which must be 2.  The second element is the
string containing the minimum version of autodep required to use this
module (which must be "1.1.0").

	queryoption
	-----------
	No parameters are supplied.  It should return the list containing
options that can be processed by this module.  These options are made 
available for use in ad.rule.  Option names are case-insensitive.

	processoption
	-------------
	Parameters supplied are module name, option name and a list of 
options given.  This subroutine is called for each option encountered in 
ad.rule that previously returned from queryoption.  The option name may 
come with mix cases, hence it should test option name case-insensitively.

Note:	Currently, autodep has no mechanism to detect possible conflicts
	when two or more modules lists the same option name.  processoption
	is not guaranteed to be called when this happens.

	new
	---
	Two parameters are supplied.  The first is module name, the 
second is a reference to structure holding all information about the 
target (see $::shCurTarget in the next section).   new must return a reference 
blessed object.  What your module should do here is to process the target and 
update various variables to be written to Makefile such as `adOBJS'.  It
must set $::shCurTarget{output} to a meaning full value for using with
pipes.  It must also add list of files to be generated (if applicable) so 
that autodep can detect conflicts.  You cannot output rules to Makefile in 
this step.

	output
	------
	Two parameters are supplied.  The first is the reference returned 
by your `new' subroutine.  The second parameter is the reference to output 
file handle.  This is the time for the module to write all rule to Makefile.  
It should return 1 to indicate success.  

	Example
	-------
	Suppose that ad.rule contains 3 targets as below:

		TARGET	target1	C++
			...		# files skipped
		TARGET	target2 C++
			...		# files skipped
		TARGET	N/A	man3	# install man pages
			...		# man pages skipped

Then autodep performs the following steps to generate Makefile:

	 1. `interface' and `queryoption' subroutine is called for each
	    target type.
	 2. ad.rule is read and parsed.  Any options unrecognized by
	    autodep are check against the list of option returned from
	    `queryoption'.  Their corresponding modules' `processoption'
	    are called.
	 3. `new' subroutine in the module handling C++ is called.  Target 
	    information contains all source file and `target1', the output 
	    file.  The module used by autodep is deduced from target map
	    files discussed in the previous section.
	 4. `new' subroutine in the module handling C++ is called.  Target 
	    information contains all source file and output file `target2'.
	 5. `new' subroutine in the module handling `man3' is called.  Target 
	    information contains all source file and output file `N/A'.
	 6. autodep checks the list of files to be generated.  If there are 
	    duplicate entries, it will abort with errors.
	 7. Content of prepend files are copied to Makefile.
	 8. All autodep variables such as `adOBJS' are written to Makefile.
	 9. All autodep macros such as `adBeginSubdir' are written to 
	    Makefile.
	10. Default target (usually `all') and `adMakeSubdir' target are 
	    written.
	11. `output' subroutine corresponding to `target1' is called.  It  
	    should write all rules related to `target1' to Makefile.
	12. `output' subroutine corresponding to `target2' is called.  It 
	    should write all rules related to `target2' to Makefile.
	13. `output' subroutine corresponding to `target3' is called.  It
	    should write all rules related to `target3' to Makefile.
	14. Content of append files are copied to Makefile.

	Module Self Test
	----------------
	Every module should verify that it is indeed invoked by autodep.  
This can be done by the following command:

	package myModule;		# Place your module filename here...
	$pkgName = "myModule";		# Place your module filename here...
	die "$pkgName: this module must only be called by autodep\n" 
			if ($::shProgName !~ /^autodep/);

at the beginning of the module.  The `package' command is required with 
the correct filename (with path name removed).  The module should also end
with

	1;

to indicate module is successfully loaded when the module is used.

Here is the summary of the structure of a module:

#----------------- BEGIN EXAMPLE ------------------
# Your module...
package myModule;		# Place your module filename here...
$pkgName = "myModule";		# Place your module filename here...
die "$pkgName: this module must only be called by autodep\n" 
		if ($::shProgName !~ /^autodep/);

# Some variables that can be shared among all targets for this module
# ...

# Required subroutines
sub interface {
	return (2, "1.1.0");
}

sub queryoption {
	return ();			# This module does not introduce
					# extra options
}

sub processoption {
	return;				# No options to process
}

sub new {
	my @parm = @_;			# Call by value
	my $class = shift @parm;	# Get the module name
	my $parm = shift @parm;		# Get the target info
				# $parm now contains a structure
				# described by $::shCurTarget in the next
				# section
	my $self = {};		# Data that will contain all information
				# specific to this target
	# Do some computation, check for errors, and fill data in $self
	# ...

	return bless $self, $class;	# Build an object for this target
}

sub output {
	my @parm = @_;			# Call by value
	my $self = shift @parm;		# The same data built by new
	my $handle = shift @parm;	# Output file handle

	# Output rules to Makefile using
	#   print $handle ...

	return 1;		# Success
}

# Some routines used internally by new, output, etc.
# ...

1;
#----------------- END EXAMPLE ------------------


Built-in Variables
==================

	Following are variables guaranteed to be exist and properly handled 
by autodep.  They begin with `sh' (means they are shared by autodep and 
among modules).

	Variables with (R) indicates that you should only read the content 
of those variables while the ones with (R/W) means that you can also 
modify them.  You can change them only in your `new' subroutine.  Changing
them in `output' is too late since the value of parameters have already been 
used by autodep.


	$::shProgName  (R)
	-------------
	This variable holds autodep program name.  It should start with
`autodep'


	$::shVersion  (R)
	------------
	This variable holds autodep version number.


	@::shTarget  (R)
	-----------
	This variable holds all information for all target.  @::shTarget is 
a list.  The i^th element of it is a reference to hash containing all
information for the i^th target.

		@::shTarget = ( $target1, $target2, ... )

	For each $targetX, it has the following structure:

		$targetX = { name       => exec_name,
		             type       => target_type,
		             line       => line,
		             source     => [ $source1, $source2, ... ],
		                              ... ],
		             output     => [], (to be filled by module)
		             output2    => [], (to be filled by module)
		             param      => [ $param1, $param2, ... ],
		             isPipe     => 0 or 1,
		             pipeFrom   => $targetFrom (defined only if 
		                                        isPipe equals 1)
		           }

	where $sourceX (X = 1, 2, ...) has the form

		$sourceX = { name   => source_name,
		             line   => source_line,
		             param  => source_param,
		             depend => source_depend,
		             output => source_output }

	Both $targetX and $sourceX are REFERENCES to hashes.

	[ Note: The above structure only applies to target types that 
	        do not start with `__'.  For reserved type names, only 
	        the field `type' is guaranteed to exist.               ]

	- Details:
		All fields except `output', `output2' in $targetX and
	`output' in $sourceX are filled automatically by autodep.  Unless
	otherwise stated, these fields are already filled when the `new'
	subroutine is called.

		$targetX Fields Filled by autodep:
		---------------------------------

		name		Contains the name of the target.
		type		Contains the type of the target.
		line		The line number the target is specified
				in ad.rule.  Useful for error messages.
		source		An array containing $sourceX structure.
		param		Parameters passed to the target.
		isPipe		Is 1 if this target is piped from another
				target.
		pipeFrom	Contains the $sourceX structure that pipe
				to this target.

		$targetX Fields to be Filled by autodep:
		---------------------------------------

		output		Contains array of files created as output.
				Intermediate files may or may not appear here.
		output2		Contains array of $outputX structure with
				information of files created as output.
				Intermediate files may or may not appear here.

		You can choose whether you will write data to `output' (for
		protocol version 1) or `output2' (for protocol version 2).
		autodep will prefer `output2' to `output' when the former is
		filled.  If you need coordination between targets from
		different modules, `output2' provides the ability to
		achieve this.
		
			`output' or `output2' is used in pipes.  Elements
		of `output' will be copied to the `name' field of the
		$sourceX structure of the destination target.  `output2'
		can further fill `depend' and `param' fields.

		$sourceX Fields Filled by autodep:
		---------------------------------

		name		Contains the name of a source.
		line		Line number that this source appear in
				ad.rule.  Useful for error messages.
		param		Parameters used to build target from this
				source.  You can decide what it means and
				how it effects the generated rules.
		depend		It is empty during `new', but filled when 
				module's `output' subroutine is called.  You 
				should include data from this field in the
				dependency list for rules building from
				this source.

		$sourceX Fields to be Filled by autodep:
		---------------------------------------

		output		Contain a structure exactly the same as the
				`output2' field of $targetX.  You can, 
				although it is not necessary to, have two 
				fields share the same area of memory by 
				referencing the same hash.

	- Examples

	Suppose following commands are found in ad.rule:

		TARGET	testrun	C++ 			# Line 14 of ad.rule
			main.cc				# Line 15
			func.cc	-O3			# Line 16

	Then the following structure will be created:

	$::shTarget = (
		{ name       => 'testrun',
		  type       => 'C++',
		  line       => 14,
		  source     => [ { name  => 'main.cc'
		                    line  => 15,
		                    param => [] },
		                  { name  => 'func.cc',
		                    line  => 16,
		                    param => [-O3] } ],
		  output     => [],	( To be filled by C++ module which
		                          is [ 'testrun' ], the executable 
		                          file created. )
		  output2    => [],	( To be filled by C++ module which
		                          is [ 'testrun' ], the executable 
		                          file created. )
		  param      => [],
		  isPipe     => 0
		}
	)

	A pipe example:

		TARGET	testrun	C++ | TYPE install /usr/bin 0755   # Line 14
			main.cc					   # Line 15
			func.cc	-O3				   # Line 16

	Then the following structure will be created:

	$::shTarget = (
		{ name       => 'testrun',
		  type       => 'C++',
		  line       => 14,
		  source     => [ { name   => 'main.cc'
		                    line   => 15,
		                    param  => [],
		                    depend => [],
		                    output => { name  => 'main.o',
		                                param  => [],
		                                depend => [] } },
		                  { name   => 'func.cc',
		                    line   => 16,
		                    param  => [-O3],
		                    depend => [],
		                    output => { name  => 'func.o',
		                                param  => [],
		                                depend => [] } } ],
		  output     => [ 'testrun' ], ( C++ module filled this
		                                 data. )
		  output2    => [ { name   => 'testrun'
		                    depend => [],
		                    param  => [] }],    ( C++ module filled this
		                                          data. )
		  param      => [],
		  isPipe     => 0
		},

		{ name       => '/usr/bin',
		  type       => 'install',
		  line       => 14,
                  source     => [ { name  => 'testrun',     ( Taken from 
		                                              output of the 
		                                              target )
		                    line  => 14   ( Same as the `line' field )
		                    param => [],
		                    depend => [],
		                    output => {} } ],
	          output     => [],            ( To be filled by `install'
		                                 module. )
	          output2    => [],            ( To be filled by `install'
		                                 module. )
		  param      => [ '0755' ],
		  isPipe     => 1,
		  pipeFrom   => $::shTarget[0]
		}
	)


	Code example:

		scalar(@::shTarget)	# Number of targets

		$::shTarget[0]		# Reference to target structure for 
					# the first target

		%{$::shTarget[0]}	# A hash containing structure

		$::shTarget[0]->{type}
	or simply,
		$::shTarget[0]{type}	# Type of the first target
	(The -> between [...] and {...} can be omitted.)

		$::shTarget[0]{source}	# Reference to source structure for 
					# the first target

		@{ $::shTarget[0]{source} }	# List that is refered by
						# $::shTarget[0]{source}

		$::shTarget[0]{source}[0]{name}		# The filename
							# of the first 
							# source file
							# (with lots of
							# unnecessary ->
							# omitted)

	Modules that are intended to serve as basic building blocks (such
as Cobj) should not access @shTarget.


	$::shCurTarget  (R/W)
	--------------
	This is the parameter passed to `new' as the second parameter.  For
the i^th target, $::shCurTarget equals $::shTarget[i].  You should only
write to $::shCurTarget{output}.

	Code example:
		$::shCurTarget		# Reference to current target info
		$::shCurTarget->{line}	# Line number (Can't omit -> here.)

	Modules that are intended to serve as basic building blocks (such
as Cobj) should not access $shCurTarget directly.  Use the parameter that
is passed to `new' instead.


	@::shGeneratedFile  (R/W)
	------------------
	This is a simple list containing filenames that are to be created 
when `make' is run.  It is used for autodep to determine whether there is 
any conflict between targets.  For example, if your module are creating 
rules for `mylib.so' you should use 

		push @::shGeneratedFile,"mylib.so";

in `new'.  When other target, trying to create "mylib.so" as well, also use 
the above command, autodep detects that "mylib.so" appears twice in 
@::shGeneratedFile and report error.


	%::shMacro  (R/W)
	----------
	This is a simple hash containing all macro to be placed in Makefile.
For example, if you want to have macro 

	manLoop = test -z "$(allMAN)" ||   \
	          for d in "$(allMAN)"; do \
	            installman $d          \
	          done

you can use the following commands

$::shMacro{manLoop}  = "test -z \"\$(allMAN)\" ||   \n";
$::shMacro{manLoop} .= "for d in \"\$(allMAN)\"; do \n";
$::shMacro{manLoop} .= "  installman \$d          \n";
$::shMacro{manLoop} .= "done";

	Note that only "\n" is used to separate lines.  The backslash "\\" is 
automatically added before "\n" by autodep to avoid possible mistakes.


	%::shVariable  (R/W)
	-------------
	It contains all variable.  For example, if you want to add `myfile.o' 
to `adOBJS', use

		$::shVariable{adOBJS} .= " myfile.o";

Unlike %::shMacro, %::shVariable do not handle "\n".  All entry must be 
separated by a space.  autodep can properly wrap content of variable to 
several lines automatically if it does not fit in one line.  Spaces at the 
beginning of variable value are automatically removed.


	%::shParameter  (R/W)
	--------------
	It contains all value of commands in ad.rule (except TARGET and TYPE 
which can be queried from @::shTarget).  Parameters from options provided 
by `queryoption' are also recorded there.

		%::shParameter = { EXCLUDE       => [ ... ],
		                   CURDIR        => [ ... ],
		                   SUBDIR        => [ ... ],
		                   DEFTARGET     => def_target,
		                   DEFTARGETLIST => def_target_list,
		                   OUTPUT        => output_file,
		                   PREPEND       => [ ... ],
		                   APPEND        => [ ... ],
				   DEBUG         => [ ... ]
		                 }

	Code example:

		$::shParameter{OUTPUT}		# Output file name
		@{ $::shParameter{SUBDIR} }	# List of subdirectories
		${ $::shParameter{SUBDIR} }[0]	# The first subdirectory


	%::shTargetModule  (R)
	-----------------
	Its contains relationship between each target type and its 
corresponding module.

		%::shTargetModule = ( type1 => $module1,
		                      type2 => $module2,
		                      ... )

	Each $module contains

		$moduleX = { mapname => name_of_target_map_file,
		             mappath => path_to_target_map_file,
		             module =>  module_file_name,
		             namespace => module_name_space,
		             protocol => protocol_version }


	@::shModuleOptionList  (R)
	---------------------
	Its contains a list of options returned from `queryoptions'.


	@::shModuleOption  (R)
	-----------------
	Its is a hash mapping options found in @::shModuleOptionList to
their corresponding module file.


	@::shTargetObject  (R)
	-----------------
	Its contains a list of objects that are obtained from the `new'
subroutine.  You should use ::addtarget subroutine rather to add new targets
rather than modifying this directly.


Built-in Subroutines
====================

	::isinlist(ITEM,LIST)
	---------------------
	Check if the ITEM appears in the LIST.

	Return 0 if it cannot find the item
	       otherwise the return code is encoded as POS+1

	where POS is the position of the first occurance of ITEM in the
	LIST (the first item has POS=0).

	Example:
		@list = ('a','b');
		print ::isinlist('a',@list)," ";
		print ::isinlist('b',@list)," ";
		print ::isinlist('c',@list),"\n";
	should print `1 2 0' on the screen.


	::copystruct(ITEM)
	------------------
	Duplicate and return a structure that is exactly the same as ITEM.
The returned structure is completely independent of the source, i.e.,
references of the new structure no longer point to the same area of memory 
as the original one.

	Example:
		my $self = ::copystruct($::shCurTarget);


	::printstruct(ITEM)
	-------------------
	Print the structure ITEM.  Does not return a value.  It is useful
for debugging purpose.

	Example:
		::printstruct($::shCurTarget);


	::runtargetsub(TARGETTYPE,SUB[,PARAM])
	--------------------------------------
	Run subroutine SUB in the module that handle target type TARGETTYPE
with parameters PARAM.  Returns value returned by the subroutine.


	::indentstring(STR1,STR2,N)
	---------------------------
	Join STR1 and STR2 and properly wrap it into several lines if it 
does not fit the screen.  Backslashes and enters are inserted between lines.
N indicates the number of tabs used to indent each line.  Additional spaces
(equals the length of STR1) are also used to indent wrapped line.  STR2 
is assumed to contain no control characters (carriage return, tab, etc.).  
All preceding and trailing spaces in STR2 are removed before processing.

	Return: Formatted string.

	Examples:

		$str1 = "outfile : ";
		$str2 = "infile1 infile2 infile3 infile4 infile5 infile6 ";
		$str2 .= "infile7 infile8 infile9 infile10 infile11 infile12 ";

	Then the code

		print ::indentstring($str1,$str2,0);

	produces the following output to the screen.

outfile : infile1 infile2 infile3 infile4 infile5 infile6 infile7 infile8 \
          infile9 infile10 infile11 infile12

	The code

		print ::indentstring($str1,$str2,1);

	produces the following output.

	outfile : infile1 infile2 infile3 infile4 infile5 infile6 infile7 \
	          infile8 infile9 infile10 infile11 infile12


	::pushunique(LIST,ITEM1[,ITEM2[...]])
	-------------------------------------
	Push specified items to LIST if they are not already in the list.
Does not return a value.


	::appendunique(STR,ITEM1[,ITEM2[...]])
	--------------------------------------
	Append specified items to the string STR if they are not already in 
the string.  Items are separated by spaces.  Does not return a value.


	::adddepend(OUTPUT,DEPEND)
	--------------------------
	Make sure that DEPEND rule is invoked before OUTPUT rule by make.
autodep will search the `output' field of the $sourceX for OUTPUT and, if
found, add DEPEND to the `depend' field of that $sourceX.  All dependencies
add by this subroutine are processed when every target's `new' subroutine is
called.


	::addtarget(TARGETSTRUCT)
	-------------------------
	Add a new target created by module rather than from ad.rule.
TARGETSTRUCT is a reference to a hash.  Its structure is exactly the same as
$targetX in @::shTarget.


Temporary Files
===============

	Temporary files should be named with the form `.autodep.temp.*'
and reside in the current directory.  They are automatically removed by 
autodep when it finishes.


Interface Version Summary
=========================
	The following list summarize the value returned by `interface' 
subroutines expected by various autodep versions:

None		For autodep 0.9.0 and 0.11.0, modules are not fully
		implemented.

(1, "1.0.0")	Supported by autodep 1.0.0, 1.1.0.

(2, "1.1.0")	Add output2 field in $targetX, depend and output fields in
		$sourceX.
		Add adddepend(), addtarget() function.
		Add module subroutine queryoption() and processoption().
		Supported by autodep 1.1.0.
