How to quickly navigate an unfamiliar makefile

Written by: Electric Bee
3 min read

The other day, I was working with an unfamiliar build and I needed to get familiar with it in a hurry. In this case, I was dealing with a makefile generated by the Perl utility h2xs , but the trick I'll show you here works any time you need to find your way around a new build system, whether it's something you just downloaded or an internal project you just transferred to. What I wanted to do was add a few object files to the link command. Here's the build log, with the link command highlighted:

gcc -c -I. -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -g -DVERSION="0.01" -DXS_VERSION="0.01" -fPIC "-I/usr/lib/perl/5.10/CORE" mylib.c
rm -f blib/arch/auto/mylib/mylib.so
gcc -shared -O2 -g -L/usr/local/lib mylib.o -o blib/arch/auto/mylib/mylib.so

chmod 755 blib/arch/auto/mylib/mylib.so

Should be easy, right? I just needed to find that command in the makefile and make my changes. Wrong. Read on to see how annotation helped solve this problem.The thing is, the command I'm looking for doesn't appear anywhere in the makefile. All of the rules look like this:

$(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c

There's not a single useful literal string in sight, so grep is right out. And it's not like you could just start reading the makefile top-to-bottom to figure out which variables contribute to the command line that produces the output that you see in the log. The makefile is nearly a thousand lines long with literally hundreds of variable definitions:

# This Makefile is for the mylib extension to perl.
#
# It was generated automatically by MakeMaker version
# 6.42 (Revision: 41145) from the contents of
# Makefile.PL. Don't edit this file, edit Makefile.PL instead.
#
# ANY CHANGES MADE HERE WILL BE LOST!
#
# MakeMaker ARGV: ()
#
# MakeMaker Parameters:

# ABSTRACT_FROM => q
# AUTHOR => q
# DEFINE => q
# INC => q
# LIBS => ]
# NAME => q
# PREREQ_PM => { }
# VERSION_FROM => q

# --- MakeMaker post_initialize section:

# --- MakeMaker const_config section:

# These definitions are from config.sh (via /usr/lib/perl/5.10/Config.pm)

# They may have been overridden via Makefile.PL or on the command line
AR = ar
CC = gcc
CCCDLFLAGS = -fPIC
CCDLFLAGS = -Wl,-E
DLEXT = so
DLSRC = dl_dlopen.xs
EXE_EXT =
FULL_AR = /usr/bin/ar
LD = gcc
LDDLFLAGS = -shared -O2 -g -L/usr/local/lib
LDFLAGS = -L/usr/local/lib
LIBC = /lib/libc-2.9.so
LIB_EXT = .a
OBJ_EXT = .o
OSNAME = linux
OSVERS = 2.6.24-23-server
RANLIB = :
SITELIBEXP = /usr/local/share/perl/5.10.0
SITEARCHEXP = /usr/local/lib/perl/5.10.0
SO = so
VENDORARCHEXP = /usr/lib/perl5
VENDORLIBEXP = /usr/share/perl5

# --- MakeMaker constants section:
AR_STATIC_ARGS = cr
DIRFILESEP = /
DFSEP = $(DIRFILESEP)
NAME = mylib
NAME_SYM = mylib
VERSION = 0.01
VERSION_MACRO = VERSION
VERSION_SYM = 0_01
DEFINE_VERSION = -D$(VERSION_MACRO)="$(VERSION)"
XS_VERSION = 0.01
XS_VERSION_MACRO = XS_VERSION
XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)="$(XS_VERSION)"
INST_ARCHLIB = blib/arch
INST_SCRIPT = blib/script
INST_BIN = blib/bin
INST_LIB = blib/lib
INST_MAN1DIR = blib/man1
INST_MAN3DIR = blib/man3
MAN1EXT = 1p
MAN3EXT = 3pm
INSTALLDIRS = site
DESTDIR =
PREFIX = /usr
PERLPREFIX = $(PREFIX)
SITEPREFIX = $(PREFIX)/local
VENDORPREFIX = $(PREFIX)
INSTALLPRIVLIB = $(PERLPREFIX)/share/perl/5.10
DESTINSTALLPRIVLIB = $(DESTDIR)$(INSTALLPRIVLIB)
INSTALLSITELIB = $(SITEPREFIX)/share/perl/5.10.0
DESTINSTALLSITELIB = $(DESTDIR)$(INSTALLSITELIB)
INSTALLVENDORLIB = $(VENDORPREFIX)/share/perl5
DESTINSTALLVENDORLIB = $(DESTDIR)$(INSTALLVENDORLIB)
INSTALLARCHLIB = $(PERLPREFIX)/lib/perl/5.10
DESTINSTALLARCHLIB = $(DESTDIR)$(INSTALLARCHLIB)
INSTALLSITEARCH = $(SITEPREFIX)/lib/perl/5.10.0
DESTINSTALLSITEARCH = $(DESTDIR)$(INSTALLSITEARCH)
INSTALLVENDORARCH = $(VENDORPREFIX)/lib/perl5
DESTINSTALLVENDORARCH = $(DESTDIR)$(INSTALLVENDORARCH)
INSTALLBIN = $(PERLPREFIX)/bin
DESTINSTALLBIN = $(DESTDIR)$(INSTALLBIN)
INSTALLSITEBIN = $(SITEPREFIX)/bin
DESTINSTALLSITEBIN = $(DESTDIR)$(INSTALLSITEBIN)
INSTALLVENDORBIN = $(VENDORPREFIX)/bin
DESTINSTALLVENDORBIN = $(DESTDIR)$(INSTALLVENDORBIN)
INSTALLSCRIPT = $(PERLPREFIX)/bin
DESTINSTALLSCRIPT = $(DESTDIR)$(INSTALLSCRIPT)
INSTALLSITESCRIPT = $(SITEPREFIX)/bin
DESTINSTALLSITESCRIPT = $(DESTDIR)$(INSTALLSITESCRIPT)
INSTALLVENDORSCRIPT = $(VENDORPREFIX)/bin
DESTINSTALLVENDORSCRIPT = $(DESTDIR)$(INSTALLVENDORSCRIPT)
INSTALLMAN1DIR = $(PERLPREFIX)/share/man/man1
DESTINSTALLMAN1DIR = $(DESTDIR)$(INSTALLMAN1DIR)
INSTALLSITEMAN1DIR = $(SITEPREFIX)/man/man1
DESTINSTALLSITEMAN1DIR = $(DESTDIR)$(INSTALLSITEMAN1DIR)
INSTALLVENDORMAN1DIR = $(VENDORPREFIX)/share/man/man1
DESTINSTALLVENDORMAN1DIR = $(DESTDIR)$(INSTALLVENDORMAN1DIR)
INSTALLMAN3DIR = $(PERLPREFIX)/share/man/man3
DESTINSTALLMAN3DIR = $(DESTDIR)$(INSTALLMAN3DIR)
INSTALLSITEMAN3DIR = $(SITEPREFIX)/man/man3
DESTINSTALLSITEMAN3DIR = $(DESTDIR)$(INSTALLSITEMAN3DIR)
INSTALLVENDORMAN3DIR = $(VENDORPREFIX)/share/man/man3
DESTINSTALLVENDORMAN3DIR = $(DESTDIR)$(INSTALLVENDORMAN3DIR)
PERL_LIB = /usr/share/perl/5.10
PERL_ARCHLIB = /usr/lib/perl/5.10
LIBPERL_A = libperl.a
FIRST_MAKEFILE = Makefile
MAKEFILE_OLD = Makefile.old
MAKE_APERL_FILE = Makefile.aperl
PERLMAINCC = $(CC)
PERL_INC = /usr/lib/perl/5.10/CORE
PERL = /usr/bin/perl
FULLPERL = /usr/bin/perl
ABSPERL = $(PERL)
PERLRUN = $(PERL)
FULLPERLRUN = $(FULLPERL)
ABSPERLRUN = $(ABSPERL)
PERLRUNINST = $(PERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"
FULLPERLRUNINST = $(FULLPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"
ABSPERLRUNINST = $(ABSPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"
PERL_CORE = 0
PERM_RW = 644
PERM_RWX = 755

MAKEMAKER = /usr/share/perl/5.10/ExtUtils/MakeMaker.pm
MM_VERSION = 6.42
MM_REVISION = 41145

# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle).
# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle)
# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar)
# DLBASE = Basename part of dynamic library. May be just equal BASEEXT.
MAKE = make
FULLEXT = mylib
BASEEXT = mylib
PARENT_NAME =
DLBASE = $(BASEEXT)
VERSION_FROM = lib/mylib.pm
INC = -I.
DEFINE =
OBJECT = $(BASEEXT)$(OBJ_EXT)
LDFROM = $(OBJECT)
LINKTYPE = dynamic
BOOTDEP =

# Handy lists of source code files:
XS_FILES = mylib.xs
C_FILES = mylib.c
O_FILES = mylib.o
H_FILES = ppport.h
MAN1PODS =
MAN3PODS = lib/mylib.pm

# Where is the Config information that we are using/depend on
CONFIGDEP = $(PERL_ARCHLIB)$(DFSEP)Config.pm $(PERL_INC)$(DFSEP)config.h

# Where to build things
INST_LIBDIR = $(INST_LIB)
INST_ARCHLIBDIR = $(INST_ARCHLIB)

INST_AUTODIR = $(INST_LIB)/auto/$(FULLEXT)
INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT)

INST_STATIC = $(INST_ARCHAUTODIR)/$(BASEEXT)$(LIB_EXT)
INST_DYNAMIC = $(INST_ARCHAUTODIR)/$(DLBASE).$(DLEXT)
INST_BOOT = $(INST_ARCHAUTODIR)/$(BASEEXT).bs

# Extra linker info
EXPORT_LIST =
PERL_ARCHIVE =
PERL_ARCHIVE_AFTER =

TO_INST_PM = lib/mylib.pm

PM_TO_BLIB = lib/mylib.pm 
 blib/lib/mylib.pm

# --- MakeMaker platform_constants section:
MM_Unix_VERSION = 6.42
PERL_MALLOC_DEF = -DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc -Dfree=Perl_mfree -Drealloc=Perl_realloc -Dcalloc=Perl_calloc

# --- MakeMaker tool_autosplit section:
# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto
AUTOSPLITFILE = $(ABSPERLRUN) -e 'use AutoSplit; autosplit($$ARGV, $$ARGV, 0, 1, 1)' --

# --- MakeMaker tool_xsubpp section:

XSUBPPDIR = /usr/share/perl/5.10/ExtUtils
XSUBPP = $(XSUBPPDIR)$(DFSEP)xsubpp
XSUBPPRUN = $(PERLRUN) $(XSUBPP)
XSPROTOARG =
XSUBPPDEPS = /usr/share/perl/5.10/ExtUtils/typemap typemap $(XSUBPP)
XSUBPPARGS = -typemap /usr/share/perl/5.10/ExtUtils/typemap -typemap typemap
XSUBPP_EXTRA_ARGS =

# --- MakeMaker tools_other section:
SHELL = /bin/sh
CHMOD = chmod
CP = cp
MV = mv
NOOP = $(SHELL) -c true
NOECHO = @
RM_F = rm -f
RM_RF = rm -rf
TEST_F = test -f
TOUCH = touch
UMASK_NULL = umask 0
DEV_NULL = > /dev/null 2>&1
MKPATH = $(ABSPERLRUN) "-MExtUtils::Command" -e mkpath
EQUALIZE_TIMESTAMP = $(ABSPERLRUN) "-MExtUtils::Command" -e eqtime
ECHO = echo
ECHO_N = echo -n
UNINST = 0
VERBINST = 0
MOD_INSTALL = $(ABSPERLRUN) -MExtUtils::Install -e 'install({@ARGV}, '''$(VERBINST)''', 0, '''$(UNINST)''');' --
DOC_INSTALL = $(ABSPERLRUN) "-MExtUtils::Command::MM" -e perllocal_install
UNINSTALL = $(ABSPERLRUN) "-MExtUtils::Command::MM" -e uninstall
WARN_IF_OLD_PACKLIST = $(ABSPERLRUN) "-MExtUtils::Command::MM" -e warn_if_old_packlist
MACROSTART =
MACROEND =
USEMAKEFILE = -f
FIXIN = $(PERLRUN) "-MExtUtils::MY" -e "MY->fixin(shift)"

# --- MakeMaker makemakerdflt section:
makemakerdflt : all
 $(NOECHO) $(NOOP)

# --- MakeMaker dist section:
TAR = tar
TARFLAGS = cvf
ZIP = zip
ZIPFLAGS = -r
COMPRESS = gzip --best
SUFFIX = .gz
SHAR = shar
PREOP = $(NOECHO) $(NOOP)
POSTOP = $(NOECHO) $(NOOP)
TO_UNIX = $(NOECHO) $(NOOP)
CI = ci -u
RCS_LABEL = rcs -Nv$(VERSION_SYM): -q
DIST_CP = best
DIST_DEFAULT = tardist
DISTNAME = mylib
DISTVNAME = mylib-0.01

# --- MakeMaker macro section:

# --- MakeMaker depend section:

# --- MakeMaker cflags section:

CCFLAGS = -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
OPTIMIZE = -O2 -g
PERLTYPE =
MPOLLUTE =

# --- MakeMaker const_loadlibs section:

# mylib might depend on some other libraries:
# See ExtUtils::Liblist for details
#

# --- MakeMaker const_cccmd section:
CCCMD = $(CC) -c $(PASTHRU_INC) $(INC) 
 $(CCFLAGS) $(OPTIMIZE) 
 $(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) 
 $(XS_DEFINE_VERSION)

# --- MakeMaker post_constants section:

# --- MakeMaker pasthru section:

PASTHRU = LIBPERL_A="$(LIBPERL_A)"
 LINKTYPE="$(LINKTYPE)"
 OPTIMIZE="$(OPTIMIZE)"
 PREFIX="$(PREFIX)"
 PASTHRU_DEFINE="$(PASTHRU_DEFINE)"
 PASTHRU_INC="$(PASTHRU_INC)"

# --- MakeMaker special_targets section:
.SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT)

.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir

# --- MakeMaker c_o section:

.c.i:
 cc -E -c $(PASTHRU_INC) $(INC) 
 $(CCFLAGS) $(OPTIMIZE) 
 $(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) 
 $(XS_DEFINE_VERSION) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c > $*.i

.c.s:
 $(CCCMD) -S $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c

.c$(OBJ_EXT):
 $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c

.cpp$(OBJ_EXT):
 $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cpp

.cxx$(OBJ_EXT):
 $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cxx

.cc$(OBJ_EXT):
 $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cc

.C$(OBJ_EXT):
 $(CCCMD) $*.C

# --- MakeMaker xs_c section:

.xs.c:
 $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.c

# --- MakeMaker xs_o section:

.xs$(OBJ_EXT):
 $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.c
 $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c

# --- MakeMaker top_targets section:
all :: pure_all manifypods
 $(NOECHO) $(NOOP)

pure_all :: config pm_to_blib subdirs linkext
 $(NOECHO) $(NOOP)

subdirs :: $(MYEXTLIB)
 $(NOECHO) $(NOOP)

config :: $(FIRST_MAKEFILE) blibdirs
 $(NOECHO) $(NOOP)

$(O_FILES): $(H_FILES)

help :
 perldoc ExtUtils::MakeMaker

# --- MakeMaker blibdirs section:
blibdirs : $(INST_LIBDIR)$(DFSEP).exists $(INST_ARCHLIB)$(DFSEP).exists $(INST_AUTODIR)$(DFSEP).exists $(INST_ARCHAUTODIR)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists $(INST_SCRIPT)$(DFSEP).exists $(INST_MAN1DIR)$(DFSEP).exists $(INST_MAN3DIR)$(DFSEP).exists
 $(NOECHO) $(NOOP)

# Backwards compat with 6.18 through 6.25
blibdirs.ts : blibdirs
 $(NOECHO) $(NOOP)

$(INST_LIBDIR)$(DFSEP).exists :: Makefile.PL
 $(NOECHO) $(MKPATH) $(INST_LIBDIR)
 $(NOECHO) $(CHMOD) 755 $(INST_LIBDIR)
 $(NOECHO) $(TOUCH) $(INST_LIBDIR)$(DFSEP).exists

$(INST_ARCHLIB)$(DFSEP).exists :: Makefile.PL
 $(NOECHO) $(MKPATH) $(INST_ARCHLIB)
 $(NOECHO) $(CHMOD) 755 $(INST_ARCHLIB)
 $(NOECHO) $(TOUCH) $(INST_ARCHLIB)$(DFSEP).exists

$(INST_AUTODIR)$(DFSEP).exists :: Makefile.PL
 $(NOECHO) $(MKPATH) $(INST_AUTODIR)
 $(NOECHO) $(CHMOD) 755 $(INST_AUTODIR)
 $(NOECHO) $(TOUCH) $(INST_AUTODIR)$(DFSEP).exists

$(INST_ARCHAUTODIR)$(DFSEP).exists :: Makefile.PL
 $(NOECHO) $(MKPATH) $(INST_ARCHAUTODIR)
 $(NOECHO) $(CHMOD) 755 $(INST_ARCHAUTODIR)
 $(NOECHO) $(TOUCH) $(INST_ARCHAUTODIR)$(DFSEP).exists

$(INST_BIN)$(DFSEP).exists :: Makefile.PL
 $(NOECHO) $(MKPATH) $(INST_BIN)
 $(NOECHO) $(CHMOD) 755 $(INST_BIN)
 $(NOECHO) $(TOUCH) $(INST_BIN)$(DFSEP).exists

$(INST_SCRIPT)$(DFSEP).exists :: Makefile.PL
 $(NOECHO) $(MKPATH) $(INST_SCRIPT)
 $(NOECHO) $(CHMOD) 755 $(INST_SCRIPT)
 $(NOECHO) $(TOUCH) $(INST_SCRIPT)$(DFSEP).exists

$(INST_MAN1DIR)$(DFSEP).exists :: Makefile.PL
 $(NOECHO) $(MKPATH) $(INST_MAN1DIR)
 $(NOECHO) $(CHMOD) 755 $(INST_MAN1DIR)
 $(NOECHO) $(TOUCH) $(INST_MAN1DIR)$(DFSEP).exists

$(INST_MAN3DIR)$(DFSEP).exists :: Makefile.PL
 $(NOECHO) $(MKPATH) $(INST_MAN3DIR)
 $(NOECHO) $(CHMOD) 755 $(INST_MAN3DIR)
 $(NOECHO) $(TOUCH) $(INST_MAN3DIR)$(DFSEP).exists

# --- MakeMaker linkext section:

linkext :: $(LINKTYPE)
 $(NOECHO) $(NOOP)

# --- MakeMaker dlsyms section:

# --- MakeMaker dynamic section:

dynamic :: $(FIRST_MAKEFILE) $(INST_DYNAMIC) $(INST_BOOT)
 $(NOECHO) $(NOOP)

# --- MakeMaker dynamic_bs section:
BOOTSTRAP = $(BASEEXT).bs

# As Mkbootstrap might not write a file (if none is required)
# we use touch to prevent make continually trying to remake it.
# The DynaLoader only reads a non-empty file.
$(BOOTSTRAP) : $(FIRST_MAKEFILE) $(BOOTDEP) $(INST_ARCHAUTODIR)$(DFSEP).exists
 $(NOECHO) $(ECHO) "Running Mkbootstrap for $(NAME) ($(BSLOADLIBS))"
 $(NOECHO) $(PERLRUN) 
 "-MExtUtils::Mkbootstrap" 
 -e "Mkbootstrap('$(BASEEXT)','$(BSLOADLIBS)');"
 $(NOECHO) $(TOUCH) $@
 $(CHMOD) $(PERM_RW) $@

$(INST_BOOT) : $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists
 $(NOECHO) $(RM_RF) $@
 - $(CP) $(BOOTSTRAP) $@
 $(CHMOD) $(PERM_RW) $@

# --- MakeMaker dynamic_lib section:

# This section creates the dynamically loadable $(INST_DYNAMIC)
# from $(OBJECT) and possibly $(MYEXTLIB).
ARMAYBE = :
OTHERLDFLAGS =
INST_DYNAMIC_DEP =
INST_DYNAMIC_FIX =

$(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVE) $(PERL_ARCHIVE_AFTER) $(INST_DYNAMIC_DEP)
 $(RM_F) $@
 $(LD) $(LDDLFLAGS) $(LDFROM) $(OTHERLDFLAGS) -o $@ $(MYEXTLIB) 
 $(PERL_ARCHIVE) $(LDLOADLIBS) $(PERL_ARCHIVE_AFTER) $(EXPORT_LIST) 
 $(INST_DYNAMIC_FIX)
 $(CHMOD) $(PERM_RWX) $@

# --- MakeMaker static section:

## $(INST_PM) has been moved to the all: target.
## It remains here for awhile to allow for old usage: "make static"
static :: $(FIRST_MAKEFILE) $(INST_STATIC)
 $(NOECHO) $(NOOP)

# --- MakeMaker static_lib section:

$(INST_STATIC) : $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists
 $(RM_RF) $@
 $(FULL_AR) $(AR_STATIC_ARGS) $@ $(OBJECT) && $(RANLIB) $@
 $(CHMOD) $(PERM_RWX) $@
 $(NOECHO) $(ECHO) "$(EXTRALIBS)" > $(INST_ARCHAUTODIR)/extralibs.ld

# --- MakeMaker manifypods section:

POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--"
POD2MAN = $(POD2MAN_EXE)

manifypods : pure_all 
 lib/mylib.pm
 $(NOECHO) $(POD2MAN) --section=$(MAN3EXT) --perm_rw=$(PERM_RW) 
 lib/mylib.pm $(INST_MAN3DIR)/mylib.$(MAN3EXT)

# --- MakeMaker processPL section:

# --- MakeMaker installbin section:

# --- MakeMaker subdirs section:

# none

# --- MakeMaker clean_subdirs section:
clean_subdirs :
 $(NOECHO) $(NOOP)

# --- MakeMaker clean section:

# Delete temporary files but do not touch installed files. We don't delete
# the Makefile here so a later make realclean still has a makefile to use.

clean :: clean_subdirs
 - $(RM_F) 
 *$(LIB_EXT) core 
 core. $(INST_ARCHAUTODIR)/extralibs.all 
 core. $(BASEEXT).bso 
 pm_to_blib.ts core. 
 $(BASEEXT).x $(BOOTSTRAP) 
 perl$(EXE_EXT) tmon.out 
 *$(OBJ_EXT) pm_to_blib 
 $(INST_ARCHAUTODIR)/extralibs.ld blibdirs.ts 
 core. mylib.c 
 *perl.core core.*perl.*.? 
 $(MAKE_APERL_FILE) $(BASEEXT).def 
 perl core. 
 mon.out lib$(BASEEXT).def 
 perlmain.c perl.exe 
 so_locations $(BASEEXT).exp
 - $(RM_RF) 
 blib
 - $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL)

# --- MakeMaker realclean_subdirs section:
realclean_subdirs :
 $(NOECHO) $(NOOP)

# --- MakeMaker realclean section:
# Delete temporary files (via clean) and also delete dist files
realclean purge :: clean realclean_subdirs
 - $(RM_F) 
 $(OBJECT) $(MAKEFILE_OLD) 
 $(FIRST_MAKEFILE)
 - $(RM_RF) 
 $(DISTVNAME)

# --- MakeMaker metafile section:
metafile : create_distdir
 $(NOECHO) $(ECHO) Generating META.yml
 $(NOECHO) $(ECHO) '--- #YAML:1.0' > META_new.yml
 $(NOECHO) $(ECHO) 'name: mylib' >> META_new.yml
 $(NOECHO) $(ECHO) 'version: 0.01' >> META_new.yml
 $(NOECHO) $(ECHO) 'abstract: Perl extension for blah blah blah' >> META_new.yml
 $(NOECHO) $(ECHO) 'license: ~' >> META_new.yml
 $(NOECHO) $(ECHO) 'author: ' >> META_new.yml
 $(NOECHO) $(ECHO) ' - Eric Melski ' >> META_new.yml
 $(NOECHO) $(ECHO) 'generated_by: ExtUtils::MakeMaker version 6.42' >> META_new.yml
 $(NOECHO) $(ECHO) 'distribution_type: module' >> META_new.yml
 $(NOECHO) $(ECHO) 'requires: ' >> META_new.yml
 $(NOECHO) $(ECHO) 'meta-spec:' >> META_new.yml
 $(NOECHO) $(ECHO) ' url: http://module-build.sourceforge.net/META-spec-v1.3.html' >> META_new.yml
 $(NOECHO) $(ECHO) ' version: 1.3' >> META_new.yml
 -$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml

# --- MakeMaker signature section:
signature :
 cpansign -s

# --- MakeMaker dist_basics section:
distclean :: realclean distcheck
 $(NOECHO) $(NOOP)

distcheck :
 $(PERLRUN) "-MExtUtils::Manifest=fullcheck" -e fullcheck

skipcheck :
 $(PERLRUN) "-MExtUtils::Manifest=skipcheck" -e skipcheck

manifest :
 $(PERLRUN) "-MExtUtils::Manifest=mkmanifest" -e mkmanifest

veryclean : realclean
 $(RM_F) *~ */*~ *.orig */*.orig *.bak */*.bak *.old */*.old

# --- MakeMaker dist_core section:

dist : $(DIST_DEFAULT) $(FIRST_MAKEFILE)
 $(NOECHO) $(ABSPERLRUN) -l -e 'print '''Warning: Makefile possibly out of date with $(VERSION_FROM)'''' 
 -e ' if -e '''$(VERSION_FROM)''' and -M '''$(VERSION_FROM)''' $(DISTVNAME).tar$(SUFFIX)_uu

$(DISTVNAME).tar$(SUFFIX) : distdir
 $(PREOP)
 $(TO_UNIX)
 $(TAR) $(TARFLAGS) $(DISTVNAME).tar $(DISTVNAME)
 $(RM_RF) $(DISTVNAME)
 $(COMPRESS) $(DISTVNAME).tar
 $(POSTOP)

zipdist : $(DISTVNAME).zip
 $(NOECHO) $(NOOP)

$(DISTVNAME).zip : distdir
 $(PREOP)
 $(ZIP) $(ZIPFLAGS) $(DISTVNAME).zip $(DISTVNAME)
 $(RM_RF) $(DISTVNAME)
 $(POSTOP)

shdist : distdir
 $(PREOP)
 $(SHAR) $(DISTVNAME) > $(DISTVNAME).shar
 $(RM_RF) $(DISTVNAME)
 $(POSTOP)

# --- MakeMaker distdir section:
create_distdir :
 $(RM_RF) $(DISTVNAME)
 $(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" 
 -e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');"

distdir : create_distdir distmeta
 $(NOECHO) $(NOOP)

# --- MakeMaker dist_test section:
disttest : distdir
 cd $(DISTVNAME) && $(ABSPERLRUN) Makefile.PL
 cd $(DISTVNAME) && $(MAKE) $(PASTHRU)
 cd $(DISTVNAME) && $(MAKE) test $(PASTHRU)

# --- MakeMaker dist_ci section:

ci :
 $(PERLRUN) "-MExtUtils::Manifest=maniread" 
 -e "@all = keys { maniread() };" 
 -e "print(qq{Executing $(CI) @alln}); system(qq{$(CI) @all});" 
 -e "print(qq{Executing $(RCS_LABEL) ...n}); system(qq{$(RCS_LABEL) @all});"

# --- MakeMaker distmeta section:
distmeta : create_distdir metafile
 $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{META.yml} => q{Module meta-data (added by MakeMaker)}}) } ' 
 -e ' or print "Could not add META.yml to MANIFEST: $${'''@'''}n"' --

# --- MakeMaker distsignature section:
distsignature : create_distdir
 $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) } ' 
 -e ' or print "Could not add SIGNATURE to MANIFEST: $${'''@'''}n"' --
 $(NOECHO) cd $(DISTVNAME) && $(TOUCH) SIGNATURE
 cd $(DISTVNAME) && cpansign -s

# --- MakeMaker install section:

install :: pure_install doc_install
 $(NOECHO) $(NOOP)

install_perl :: pure_perl_install doc_perl_install
 $(NOECHO) $(NOOP)

install_site :: pure_site_install doc_site_install
 $(NOECHO) $(NOOP)

install_vendor :: pure_vendor_install doc_vendor_install
 $(NOECHO) $(NOOP)

pure_install :: pure_$(INSTALLDIRS)_install
 $(NOECHO) $(NOOP)

doc_install :: doc_$(INSTALLDIRS)_install
 $(NOECHO) $(NOOP)

pure__install : pure_site_install
 $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site

doc__install : doc_site_install
 $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site

pure_perl_install :: all
 $(NOECHO) umask 022; $(MOD_INSTALL) 
 $(INST_LIB) $(DESTINSTALLPRIVLIB) 
 $(INST_ARCHLIB) $(DESTINSTALLARCHLIB) 
 $(INST_BIN) $(DESTINSTALLBIN) 
 $(INST_SCRIPT) $(DESTINSTALLSCRIPT) 
 $(INST_MAN1DIR) $(DESTINSTALLMAN1DIR) 
 $(INST_MAN3DIR) $(DESTINSTALLMAN3DIR)
 $(NOECHO) $(WARN_IF_OLD_PACKLIST) 
 $(SITEARCHEXP)/auto/$(FULLEXT)

pure_site_install :: all
 $(NOECHO) umask 02; $(MOD_INSTALL) 
 read $(SITEARCHEXP)/auto/$(FULLEXT)/.packlist 
 write $(DESTINSTALLSITEARCH)/auto/$(FULLEXT)/.packlist 
 $(INST_LIB) $(DESTINSTALLSITELIB) 
 $(INST_ARCHLIB) $(DESTINSTALLSITEARCH) 
 $(INST_BIN) $(DESTINSTALLSITEBIN) 
 $(INST_SCRIPT) $(DESTINSTALLSITESCRIPT) 
 $(INST_MAN1DIR) $(DESTINSTALLSITEMAN1DIR) 
 $(INST_MAN3DIR) $(DESTINSTALLSITEMAN3DIR)
 $(NOECHO) $(WARN_IF_OLD_PACKLIST) 
 $(PERL_ARCHLIB)/auto/$(FULLEXT)

pure_vendor_install :: all
 $(NOECHO) umask 022; $(MOD_INSTALL) 
 $(INST_LIB) $(DESTINSTALLVENDORLIB) 
 $(INST_ARCHLIB) $(DESTINSTALLVENDORARCH) 
 $(INST_BIN) $(DESTINSTALLVENDORBIN) 
 $(INST_SCRIPT) $(DESTINSTALLVENDORSCRIPT) 
 $(INST_MAN1DIR) $(DESTINSTALLVENDORMAN1DIR) 
 $(INST_MAN3DIR) $(DESTINSTALLVENDORMAN3DIR)

doc_perl_install :: all

doc_site_install :: all
 $(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLSITEARCH)/perllocal.pod
 -$(NOECHO) umask 02; $(MKPATH) $(DESTINSTALLSITEARCH)
 -$(NOECHO) umask 02; $(DOC_INSTALL) 
 "Module" "$(NAME)" 
 "installed into" "$(INSTALLSITELIB)" 
 LINKTYPE "$(LINKTYPE)" 
 VERSION "$(VERSION)" 
 EXE_FILES "$(EXE_FILES)" 
 >> $(DESTINSTALLSITEARCH)/perllocal.pod

doc_vendor_install :: all

uninstall :: uninstall_from_$(INSTALLDIRS)dirs
 $(NOECHO) $(NOOP)

uninstall_from_perldirs ::

uninstall_from_sitedirs ::
 $(NOECHO) $(UNINSTALL) $(SITEARCHEXP)/auto/$(FULLEXT)/.packlist

uninstall_from_vendordirs ::

# --- MakeMaker force section:
# Phony target to force checking subdirectories.
FORCE :
 $(NOECHO) $(NOOP)

# --- MakeMaker perldepend section:

PERL_HDRS = 
 $(PERL_INC)/EXTERN.h 
 $(PERL_INC)/INTERN.h 
 $(PERL_INC)/XSUB.h 
 $(PERL_INC)/av.h 
 $(PERL_INC)/cc_runtime.h 
 $(PERL_INC)/config.h 
 $(PERL_INC)/cop.h 
 $(PERL_INC)/cv.h 
 $(PERL_INC)/dosish.h 
 $(PERL_INC)/embed.h 
 $(PERL_INC)/embedvar.h 
 $(PERL_INC)/fakethr.h 
 $(PERL_INC)/form.h 
 $(PERL_INC)/gv.h 
 $(PERL_INC)/handy.h 
 $(PERL_INC)/hv.h 
 $(PERL_INC)/intrpvar.h 
 $(PERL_INC)/iperlsys.h 
 $(PERL_INC)/keywords.h 
 $(PERL_INC)/mg.h 
 $(PERL_INC)/nostdio.h 
 $(PERL_INC)/op.h 
 $(PERL_INC)/opcode.h 
 $(PERL_INC)/patchlevel.h 
 $(PERL_INC)/perl.h 
 $(PERL_INC)/perlio.h 
 $(PERL_INC)/perlsdio.h 
 $(PERL_INC)/perlsfio.h 
 $(PERL_INC)/perlvars.h 
 $(PERL_INC)/perly.h 
 $(PERL_INC)/pp.h 
 $(PERL_INC)/pp_proto.h 
 $(PERL_INC)/proto.h 
 $(PERL_INC)/regcomp.h 
 $(PERL_INC)/regexp.h 
 $(PERL_INC)/regnodes.h 
 $(PERL_INC)/scope.h 
 $(PERL_INC)/sv.h 
 $(PERL_INC)/thread.h 
 $(PERL_INC)/unixish.h 
 $(PERL_INC)/util.h

$(OBJECT) : $(PERL_HDRS)

mylib.c : $(XSUBPPDEPS)

# --- MakeMaker makefile section:

$(OBJECT) : $(FIRST_MAKEFILE)

# We take a very conservative approach here, but it's worth it.
# We move Makefile to Makefile.old here to avoid gnu make looping.
$(FIRST_MAKEFILE) : Makefile.PL $(CONFIGDEP)
 $(NOECHO) $(ECHO) "Makefile out-of-date with respect to $?"
 $(NOECHO) $(ECHO) "Cleaning current config before rebuilding Makefile..."
 -$(NOECHO) $(RM_F) $(MAKEFILE_OLD)
 -$(NOECHO) $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD)
 - $(MAKE) $(USEMAKEFILE) $(MAKEFILE_OLD) clean $(DEV_NULL)
 $(PERLRUN) Makefile.PL
 $(NOECHO) $(ECHO) "==> Your Makefile has been rebuilt. Please rerun the $(MAKE) command. <=="
 false

# --- MakeMaker staticmake section:

# --- MakeMaker makeaperl section ---
MAP_TARGET = perl
FULLPERL = /usr/bin/perl

$(MAP_TARGET) :: static $(MAKE_APERL_FILE)
 $(MAKE) $(USEMAKEFILE) $(MAKE_APERL_FILE) $@

$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib
 $(NOECHO) $(ECHO) Writing "$(MAKE_APERL_FILE)" for this $(MAP_TARGET)
 $(NOECHO) $(PERLRUNINST) 
 Makefile.PL DIR= 
 MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static 
 MAKEAPERL=1 NORECURS=1 CCCDLFLAGS=

# --- MakeMaker test section:

TEST_VERBOSE=0
TEST_TYPE=test_$(LINKTYPE)
TEST_FILE = test.pl
TEST_FILES = t/*.t
TESTDB_SW = -d

testdb :: testdb_$(LINKTYPE)

test :: $(TEST_TYPE) subdirs-test

subdirs-test ::
 $(NOECHO) $(NOOP)

test_dynamic :: pure_all
 PERL_DL_NONLAZY=1 $(FULLPERLRUN) "-MExtUtils::Command::MM" "-e" "test_harness($(TEST_VERBOSE), '$(INST_LIB)', '$(INST_ARCHLIB)')" $(TEST_FILES)

testdb_dynamic :: pure_all
 PERL_DL_NONLAZY=1 $(FULLPERLRUN) $(TESTDB_SW) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE)

test_ : test_dynamic

test_static :: pure_all $(MAP_TARGET)
 PERL_DL_NONLAZY=1 ./$(MAP_TARGET) "-MExtUtils::Command::MM" "-e" "test_harness($(TEST_VERBOSE), '$(INST_LIB)', '$(INST_ARCHLIB)')" $(TEST_FILES)

testdb_static :: pure_all $(MAP_TARGET)
 PERL_DL_NONLAZY=1 ./$(MAP_TARGET) $(TESTDB_SW) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE)

# --- MakeMaker ppd section:
# Creates a PPD (Perl Package Description) for a binary distribution.
ppd :
 $(NOECHO) $(ECHO) '<SOFTPKG NAME="$(DISTNAME)" VERSION="0,01,0,0">' > $(DISTNAME).ppd
 $(NOECHO) $(ECHO) ' <TITLE>$(DISTNAME)</TITLE>' >> $(DISTNAME).ppd
 $(NOECHO) $(ECHO) ' <ABSTRACT>Perl extension for blah blah blah</ABSTRACT>' >> $(DISTNAME).ppd
 $(NOECHO) $(ECHO) ' <AUTHOR>Eric Melski <ericm@></AUTHOR>' >> $(DISTNAME).ppd
 $(NOECHO) $(ECHO) ' <IMPLEMENTATION>' >> $(DISTNAME).ppd
 $(NOECHO) $(ECHO) ' <OS NAME="$(OSNAME)" />' >> $(DISTNAME).ppd
 $(NOECHO) $(ECHO) ' <ARCHITECTURE NAME="i486-linux-gnu-thread-multi-5.1" />' >> $(DISTNAME).ppd
 $(NOECHO) $(ECHO) ' <CODEBASE HREF="" />' >> $(DISTNAME).ppd
 $(NOECHO) $(ECHO) ' </IMPLEMENTATION>' >> $(DISTNAME).ppd
 $(NOECHO) $(ECHO) '</SOFTPKG>' >> $(DISTNAME).ppd

# --- MakeMaker pm_to_blib section:

pm_to_blib : $(TO_INST_PM)
 $(NOECHO) $(ABSPERLRUN) -MExtUtils::Install -e 'pm_to_blib({@ARGV}, '''$(INST_LIB)/auto''', '''$(PM_FILTER)''')' -- 
 lib/mylib.pm blib/lib/mylib.pm
 $(NOECHO) $(TOUCH) pm_to_blib

# --- MakeMaker selfdocument section:

# --- MakeMaker postamble section:

# End.

It seems hopeless. This makefile suffers from a classic problem: unless you're the guy who wrote it in the first place, it's an impenetrable fog. You're in for a world of hurt when you try to understand it, or worse, try to modify it. Lucky for me — and for you if you ever find yourself in this situation — there's a powerful new tool in your toolbox: emake's annotated build logs, or simply annotation . If you have CloudBees Accelerator or SparkBuild , a free gmake- and NMAKE-compatible make replacement, you just need to enable annotation on your next build:

emake --emake-annodetail=basic > build.xml 2>&1

Now you can search build.xml for the log output or the command-line that you're interested in. You can use ElectricInsight or SparkBuild Insight, of course, but for a simple query like this I just use less . Searching for the log output of the command I'm looking for (gcc -shared ) leads me to this:

...
<output></output>
command></command> rm -f blib/arch/auto/mylib/mylib.so
<output>rm -f blib/arch/auto/mylib/mylib.so</output>
<output></output>
<command></command> gcc -shared -O2 -g -L/usr/local/lib mylib.o -o blib/arch/auto/mylib/mylib.so
<output>gcc -shared -O2 -g -L/usr/local/lib mylib.o -o blib/arch/auto/mylib/mylib.so</output>
<output></output>
...

Now, I just scan back a few lines to find the start of the <job> tag containing that text. The file attribute tells me which makefile contains the rule definition, and the line attribute tells me which line it starts on:

... 
<job id="J09be71b8" thread="b7b34940" type="rule" name="blib/arch/auto/mylib/mylib.so" file="Makefile" line="469" neededby="J09be7138"> 
...

Bingo! The rule I want starts on line 469 of the file Makefile . Using that as an anchor it's now trivial to see how to modify the makefile to produce the result I'm after.

The best tool for the job

Trying to figure out how a build system is put together can feel like being dropped in the middle of a dense jungle. Annotated build logs are like a map leading you back to daylight. There's nothing else like them.


Build Acceleration and Continuous Delivery

Continuous Delivery isn’t continuous if builds and tests take too long to complete. Learn more on how CloudBees Accelerator speeds up builds and tests by up to 20X, improving software time to market, infrastructure utilization and developer productivity.

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.