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.