The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Makefile::Parser - A Simple Parser for Makefiles

SYNOPSIS

  use Makefile::Parser;

  $parser = Makefile::Parser->new;

  # Equivalent to ->parse('Makefile');
  $parser->parse or
      die Makefile::Parser->error;

  # Get last value assigned to the specified variable 'CC':
  print $parser->var('CC');

  # Get all the variable names defined in the Makefile:
  @vars = $parser->vars;
  print join(' ', sort @vars);

  @roots = $parser->roots; # Get all the "root targets"
  print $roots[0]->name;

  @tars = $parser->targets;  # Get all the targets
  $tar = join("\n", $tars[0]->commands);

  # Get the default target, say, the first target defined in Makefile:
  $tar = $parser->target;

  $tar = $parser->target('install');
  # Get the name of the target, say, 'install' here:
  print $tar->name;

  # Get the dependencies for the target 'install':
  @depends = $tar->depends;

  # Access the shell command used to build the current target.
  @cmds = $tar->commands;

  # Parse another file using the same Parser object:
  $parser->parse('Makefile.old') or
    die Makefile::Parser->error;

  # Get the target who is specified by variable EXE_FILE
  $tar = $parser->target($parser->var('EXE_FILE'));

DESCRIPTION

This is a parser for Makefiles. At this very early stage, the parser only supports a limited set of features, so it may not recognize some advanced features provided by certain make tools like GNU make. Its initial purpose is to provide basic support for another module named Makefile::GraphViz, which is aimed to render the building process specified by a Makefile using the amazing GraphViz library. The Make module is not satisfactory for this purpose, so I decided to build one of my own.

IMPORTANT! This stuff is highly experimental and is currently at ALPHA stage, so production use is strongly discouraged. Anyway, I have the plan to improve this stuff unfailingly.

SYNTAX SUPPORTED

The ultimate goal of this parser is to support all the syntax of Win32 NMAKE and GNU MAKE. But currently just a subset of features are implemented:

Variable Definition
    MIN_T_FILES = $(PAT_COVER_FILES) t\optest.t t\my_perl.exe.t t\types.cod.t \
        t\catln.t t\exe2hex.t t\hex2bin.t t\bin2hex.t t\bin2asm.t t\ndisasmi.t \
        t\Idu.t t\pat_tree.t t\state_mac.t t\Idu-Util.t t\cidu.t \
        t\opname.t t\error.t t\operand.t t\01disasm.t t\02disasm.t t\03disasm.t \
        t\disasm_cover.t t\ndisasm.t
    T_FILES = t\main.cod.t t\bin2hex.exe.t t\hex2bin.exe.t $(MIN_T_FILES)
    DIRFILESEP = ^\

"Simply expanded" variables' definition sytax in GUN make is also supported:

    FOO := blah blah blah

which is considered invalid in Win32 NMake. "Recursively expanded" variables are currently treated as "simply expanded" variables.

Variable redefinition can be handled as well:

    CC = cl

    %.obj : %.c
        $(CC) /nologo /c $<
    
    CC = gcc

    %.o : %.c
        $(CC) -c $<

Variable expansion sytax

    ${abc}

is accepted, whereas Win32 NMake will complain about it.

Currently, environment variables defined in the command-line are not imported.

I have no idea what default value should be assigned to built-in variables like $(MAKE) and $(CC). Currently they will be left untouched if they're not set explicitly in the Makefile.

Due to the current implementation, expansion of unrecognized built-in varaibles and variables not previously defined by Makefile will NOT be performed. This behavior is different from any practial make tools, but is reasonable at this early stage of this parser.

Explicit Rules
    $(CIDU_DLL) : C\idu.obj C\idu.def
        link /dll /nologo /debug /out:$@ /def:C\idu.def C\idu.obj

    $(CIDU_LIB) : $(CIDU_DLL)

    C\idu.obj : C\idu.c C\idu.h
        cd C
        cl /nologo /c /I . idu.c
        cd ..

    smoke : all pat_cover t\pat_cover.t \
            t/pat_cover.ast.ast
        perl util\run-smoke.pl . smoke.html
        perl txt2html.pl t\*.t t\*.ast

    clean:
        copy t\pat_cover.ast.ast.html ..\ /Y 
        $(RM_F) encoding.html encoding.pod state_mac.xml encoding.ast \
            pat_tree.ast state_mac.ast \
            main.cod pat_cover.pod pat_cover.html types.cod \
            hex2bin.exe hex2bin.obj

Specital variable $@ will be expanded using its value in the context.

Implicit Rules
Pattern Rules
    %.obj : %.asm
        masm /t $<;

    %.exe : %.obj
        link /BATCH /NOLOGO $<;

The special varaibles $< and $* will be expanded according to the context.

Old-Fashioned Suffix Rules

Currently only double-suffix rules are supported:

    .SUFFIXES: .obj .asm .exe

    .asm.obj :
        masm /t $<

    .obj.exe :
        link /nologo $<

At this moment, .SUFFIXES is a no-op. So any suffix-like things will be treated as suffixes, excluding the following example:

    .c.o: foo.h
            $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

In suffix rules, no prerequisites are allowed according to most make tools.

Specital variable $@ will be expanded using its value in the context.

For the list of features which will be added very soon, take a look at the "TODO" section.

The Makefile::Parser Class

This class provides the main interface to the Makefile parser.

METHODS

$class->new()

It's the constructor for the Parser class. You may provide the path of your Makefile as the argument which . It is worth mentioning that the constructor will not call ->parse method internally, so please remember calling ->parse after you construct the parser object.

$obj->parse(Makefile-name)

This method parse the specified Makefile (default to 'Makefile').

When an error occurs during the parsing procedure, ->parse will return undef. Otherwise, a reference to Parser object itself is returned. It is recommended to check the return value every time you call this method. The detailed error info can be obtained by calling the ->error method.

$obj->error

It returns the error info set by the most recent failing operation, such as a parsing failure.

$obj->var($variable_name)

The var method returns the value of the given variable. Since the value of variables can be reset multiple times in the Makefile, so what you get is always the last value set to the variable. It's worth noting that variable reassignment can be handled appropriately during parsing since the whole parsing process is a one-pass operation compared to the multiple-pass strategy used by the CPAN module Make.

$obj->vars

This will return all the variables defined in the Makefile. The order may be quite different from the order they appear in the Makefile.

$obj->target($target_name)

This method returns a Makefile::Target object with the name specified. It will returns undef if the rules for the given target is not described in the Makefile. It is worth noting that only targets with a definition body will be considered as a target here.

When $target_name is omitted, this method will return the default target, say, the first target defined in Makefile, to the user. This can be handy if you try to build a make tool on top of this module.

It is important not to send something like "$(MY_LIB)" as the target name. Only raw values are acceptable. If you really want to do something like this, please use the following code:

    my $tar = $parser->target($parser->var('MY_LIB'));

but this code will break if you have reassigned values to variable MY_LIB in your Makefile.

$obj->targets

This returns all the targets in Makefile. The order can be completely different from the order they appear in Makefile. So the following code will not work if you want to get the default target (the first target):

    @tars = $parser->targets;
    print $tars[0];

Please use the following syntax instead:

    print $parser->target;

The type of the returned list is an array of Makefile::Target objects.

$obj->roots

The ->roots method returns the "root targets" in Makefile. The targets which there're no other targets depends on are called the root targets. For example, install, uninstall, and veryclean are all root targets in the Makefile generated by the ExtUtils::MakeMaker module. On the other hand, clean and test are not, which may be somewhat counterintuitive. That's because there're some other targets depend on clean, test, or both.

The type of the returned list is an array of Makefile::Target objects.

PACKAGE VARIABLES

$Makefile::Parser::Strict

When this variable is set to true, the parser will sense syntax errors and semantic errors in the Makefile. Default off.

$Makefile::Parser::Debug

When this variable is set to true, the parser will enter Debug Mode. This variable is not supposed to be used directly by the user.

INTERNAL METHODS

post_parse

Iterate the Makefile AST to apply implicit rules in the following form:

    %.o : %.c
        $(CC) -c $<
solve_imp($depend)

Solve implicit rules as many as possible using one target name that appears in other target's dependency list.

The Makefile::Target Class

This class overloads the "" operator so its instances can be automatically converted to strings using their names.

METHODS

$class->new($target_name, $colon_type)

This is the constructor for class Makefile::Target. The first argument is the target name which can't be a Makefile variable, the second one is a single colon or a double colon which is used by the rule definition in Makefile.

This method is usually called internally by the Makefile::Parser class. It doesn't make much sense to me if the user has a need to call it manually.

$obj->name

It will return the name of the current Target object.

$obj->depends

You can get the list dependencies for the current target. If no dependencies are specified in the Makefile for the target, an empty array will be returned.

$obj->commands

This method returns a list of shell commands used to build the current target. If no shell commands is given in the Makefile, an empty array will be returned.

EXPORT

None by default.

CODE COVERAGE

I use Devel::Cover to test the code coverage of my tests, below is the Devel::Cover report on this module's test suite for version 0.11:

    ---------------------------- ------ ------ ------ ------ ------ ------ ------
    File                           stmt   bran   cond    sub    pod   time  total
    ---------------------------- ------ ------ ------ ------ ------ ------ ------
    blib/lib/Makefile/Parser.pm    96.7   91.9   80.0   91.3  100.0  100.0   93.4
    Total                          96.7   91.9   80.0   91.3  100.0  100.0   93.4
    ---------------------------- ------ ------ ------ ------ ------ ------ ------

REPOSITORY

For the very latest version of this module, check out the source from https://svn.openfoundry.org/makefileparser (Subversion). There is anonymous access to all.

TODO

The following syntax will be implemented at the first priority:

Serious support for "Recursively expanded" variables in GUN make
Provide a make tool named ``plmake'' that uses Makefile::Parser

This stuff can be served as a good integrated test.

Import environment variables

A quick example on Win32:

    C:\> set RM_F=perl -MExtUtils::Command -e rm_f
    C:\> nmake clean
Comments that span multiple lines via trailing backslash
Lines that don't contain just comments
Literal "#" escaped by a leading backslash
The include directive
Look for 'GNUmakefile' and 'makefile' automatically
MAKEFILES Variable
MAKEFILE_LIST Variable
.VARIABLES Variable

BUGS

Please feel free to report bugs or send your wish-list to http://rt.cpan.org/NoAuth/Bugs.html?Dist=Makefile-Parser.

SEE ALSO

Makefile::GraphViz.

AUTHOR

Agent Zhang, <agent2002@126.com>

COPYRIGHT AND LICENSE

Copyright (c) 2005 Agent Zhang.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.