cperlmakefilemakemaker

ExtUtils::MakeMaker including external *.mk and using defines within *.mk file for LIBS and INC parameters in WriteMakefile


I have a top level defines.mk file which lists certain directories and C libraries to include depending on the project like so.

KERNEL_LIB = -lkdev  
DRIVER_LIB = -ldriver -lutil -linit $(KERNEL_LIB)
DRIVER_INCLUDE = -I../../include

I use XS to allow perl scripts to access these libraries and MakeMaker to generate the Makefile which will link these libraries in. I want to make it such that when the Makefile is generated, it pulls in these defines.

Given a WriteMakefile like this

WriteMakefile(  
    NAME              => 'generic_scripts',
    VERSION_FROM      => 'generic_scripts.pm', 
    LIBS              => ['-L/usr/local/app/lib -lkdev -lpthread -lrt -ldriver -lutil -linit'],
    DEFINE            => '', 
    INC               => '-I../../include', 
    clean             => {FILES=>"*.o"},
);

I want to achieve this

WriteMakefile(  
    NAME              => 'generic_scripts',
    VERSION_FROM      => 'generic_scripts.pm', 
    LIBS              => ['-L/usr/local/dx/lib $(KERNEL_LIB) -lpthread -lrt $(DRIVER_LIB)'],
    DEFINE            => '', 
    INC               => '$(DRIVER_INCLUDE)', 
    clean             => {FILES=>"*.o"},
);

From @mobrule I now have this Makefile.PL

use 5.008008;
use ExtUtils::MakeMaker;
use ExtUtils::MM_Unix;
use ExtUtils::MM;

sub MY::post_initialize {
    open my $defs, '<', 'defines.mk';
    my $extra_defines = join '', <$defs>;
    close $defs;
    return $extra_defines;
}

sub MM::init_others {
    my $self = shift;
    $self->ExtUtils::MM_Unix::init_others(@_);

    $self->{EXTRALIBS} = '-L/usr/local/app/lib $(DRIVER_LIB) -lpthread -lrt';
    $self->{BSLOADLIBS} = $self->{LDLOADLIBS} = $self->{EXTRALIBS};
}

WriteMakefile(
    NAME              => 'generic_scripts',
    VERSION_FROM      => 'generic_scripts.pm',
    DEFINE            => '',
    INC               => '$(DRIVER_INCLUDE)',
    clean             => {FILES=>"*.o"},
);

Which looks like it does what I want. Thanks!


Solution

  • Override the post_initialize method to include your additional definitions:

    sub MY::post_initialize {
        open my $defs, '<', 'defines.mk';
        my $extra_defines = join '', <$defs>;
        close $defs;
        return $extra_defines;
    }
    

    These will appear at the top of the Makefile, so later definitions (e.g. LIBS, can use them).

    The next problem is getting MakeMaker to let the "invalid" entries in the LIBS and INC parameters passed through to the Makefile.

    On Windows I think you can just put a :nosearch, like

    LIBS => ['-lm', ':nosearch $(OTHER_LIBS)']
    

    and it will pass through (consult the docs to ExtUtils::Liblist). On Unix-y systems that doesn't work, and you may need to do something more radical like overriding init_others:

    sub MM::init_others {      # MM package is a subclass of ExtUtils::MM_Unix and will
                               # get called instead of ExtUtils::MM_Unix::init_others
        my $self = shift;
        $self->SUPER::init_others(@_); # invoke ExtUtils::MM_Unix::init_others
    
        # now repair the attributes that ExtUtils::MM_Any::init_others didn't set
        $self->{EXTRALIBS} = '-lkdev $(KERNEL_LIB) -lrt $(DRIVER_LIB)';
        $self->{BSLOADLIBS} = $self->{LDLOADLIBS} = $self->{EXTRALIBS};
        1; 
    }
    

    I haven't tested this and this might not be a complete working solution. Hopefully it will get you going in the right direction (if you are still reading this far).