+package My::Build;
+
+use v5.10;
+use warnings FATAL => 'all';
+use strict;
+use utf8;
+
+use Archive::Tar;
+use Cwd qw/realpath/;
+use Digest::SHA qw/sha1_hex/;
+use File::Path qw/remove_tree/;
+use File::Spec::Functions qw/catdir catfile/;
+use IPC::Cmd qw/can_run run/;
+use LWP::Simple qw/getstore RC_OK/;
+use Module::Build;
+
+use base 'Module::Build';
+
+sub ACTION_code {
+ my $self = shift;
+
+ $self->SUPER::ACTION_code;
+
+ return if -e 'build-zeromq';
+ $self->add_to_cleanup('build-zeromq');
+
+ my %args = $self->args;
+ my %vars;
+
+ $self->have_c_compiler or die "C compiler not found";
+
+ unless (exists $args{'zmq-skip-probe'}) {
+ say "Probing...";
+ %vars = $self->probe_zeromq;
+ }
+
+ if ($vars{inc_version} && $vars{lib_version}) {
+ say "Found ØMQ $vars{lib_version}; skipping installation";
+ } else {
+ say "ØMQ not found; building from source...";
+ %vars = $self->install_zeromq;
+ }
+
+ # write vars to ZMQ.pm
+ my $module = catfile qw/blib lib Alien ZMQ.pm/;
+ open my $LIB, "<$module" or die "Cannot read module";
+ my $lib = do { local $/; <$LIB> };
+ close $LIB;
+ $lib =~ s/^sub inc_dir.*$/sub inc_dir { "$vars{inc_dir}" }/m;
+ $lib =~ s/^sub lib_dir.*$/sub lib_dir { "$vars{lib_dir}" }/m;
+ $lib =~ s/^sub inc_version.*$/sub inc_version { v$vars{inc_version} }/m;
+ $lib =~ s/^sub lib_version.*$/sub lib_version { v$vars{lib_version} }/m;
+ my @stats = stat $module;
+ chmod 0644, $module;
+ open $LIB, ">$module" or die "Cannot write config to module";
+ print $LIB $lib;
+ close $LIB;
+ chmod $stats[2], $module;
+
+ open my $TARGET, ">build-zeromq";
+ print $TARGET time, "\n";
+ close $TARGET;
+}
+
+sub probe_zeromq {
+ my $self = shift;
+ my $cb = $self->cbuilder;
+
+ my $src = "test-$$.c";
+ open my $SRC, ">$src";
+ print $SRC <<END;
+#include <stdio.h>
+#include <zmq.h>
+int main(int argc, char* argv[]) {
+ int major, minor, patch;
+ zmq_version(&major, &minor, &patch);
+ printf("%d.%d.%d %d.%d.%d",
+ ZMQ_VERSION_MAJOR, ZMQ_VERSION_MINOR, ZMQ_VERSION_PATCH,
+ major, minor, patch);
+ return 0;
+}
+END
+ close $SRC;
+
+ my @inc_search;
+ my @lib_search;
+
+ my $cflags = $self->args('zmq-cflags');
+ my $libs = $self->args('zmq-libs');
+
+ my $pkg_version;
+
+ my $pkg_config = $ENV{PKG_CONFIG_COMMAND} || "pkg-config";
+ for my $pkg (qw/libzmq zeromq3/) {
+ $pkg_version = `$pkg_config $pkg --modversion`;
+ chomp $pkg_version;
+ next unless $pkg_version;
+
+ $cflags ||= `$pkg_config $pkg --cflags`;
+ $libs ||= `$pkg_config $pkg --libs`;
+
+ # use -I and -L flag arguments as extra search directories
+ my $inc = `$pkg_config $pkg --cflags-only-I`;
+ push @inc_search, map { s/^-I//; $_ } split(/\s+/, $inc);
+ my $lib = `$pkg_config $pkg --libs-only-L`;
+ push @lib_search, map { s/^-L//; $_ } split(/\s+/, $lib);
+
+ last;
+ }
+
+ my $obj = eval {
+ $cb->compile(source => $src, include_dirs => [@inc_search], extra_compiler_flags => $cflags);
+ };
+ unlink $src;
+ return unless $obj;
+
+ my $exe = eval {
+ $cb->link_executable(objects => $obj, extra_linker_flags => $libs);
+ };
+ unlink $obj;
+ return unless $exe;
+
+ my $out = `./$exe`;
+ unlink $exe;
+ my ($inc_version, $lib_version) = $out =~ /(\d\.\d\.\d) (\d\.\d\.\d)/;
+
+ # query the compiler for include and library search paths
+ my $cc = $ENV{CC} || "cc";
+ push @lib_search, map {
+ my $path = $_;
+ $path =~ s/^.+ =?//;
+ $path =~ s/\n.*$//;
+ -d $path ? realpath($path) : ();
+ } split /:/, `$cc -print-search-dirs`;
+ push @inc_search, map {
+ my $path = $_;
+ $path =~ s/lib(32|64)?$/include/;
+ $path;
+ } @lib_search;
+
+ # search for the header and library files
+ my ($inc_dir) = grep { -f catfile($_, "zmq.h") } @inc_search;
+ my ($lib_dir) = grep {
+ -f catfile($_, "libzmq.so") ||
+ -f catfile($_, "libzmq.dylib") ||
+ -f catfile($_, "libzmq.dll")
+ } @lib_search;
+
+ (
+ inc_version => $inc_version,
+ lib_version => $lib_version,
+ pkg_version => $pkg_version,
+ inc_dir => $inc_dir,
+ lib_dir => $lib_dir,
+ );
+}
+
+sub install_zeromq {
+ my $self = shift;
+
+ can_run("libtool") or die "The libtool command cannot be found";
+
+ my $version = $self->notes('zmq-version');
+ my $sha1 = $self->notes('zmq-sha1');
+ my $archive = "zeromq-$version.tar.gz";
+
+ say "Downloading ØMQ $version source archive from download.zeromq.org...";
+ getstore("http://download.zeromq.org/$archive", $archive) == RC_OK
+ or die "Failed to download ØMQ source archive";
+
+ say "Verifying...";
+ my $sha1sum = Digest::SHA->new;
+ open my $ARCHIVE, "<$archive";
+ binmode $ARCHIVE;
+ $sha1sum->addfile($ARCHIVE);
+ close $ARCHIVE;
+ $sha1sum->hexdigest eq $sha1 or die "Source archive checksum mismatch";
+
+ say "Extracting...";
+ Archive::Tar->new($archive)->extract;
+ unlink $archive;
+
+ my $prefix = catdir($self->install_destination("lib"), qw/auto share dist Alien-ZMQ/);
+ my $basedir = $self->base_dir;
+ my $datadir = catdir($basedir, "share");
+ my $srcdir = catdir($basedir, "zeromq-$version");
+
+ say "Configuring...";
+ my @config = split(/\s/, $self->args('zmq-config') || "");
+ chdir $srcdir;
+ run(command => ["./configure", "--prefix=$prefix", @config])
+ or die "Failed to configure ØMQ";
+
+ say "Compiling...";
+ run(command => ['make']) or die "Failed to make ØMQ";
+
+ say "Installing...";
+ run(command => [qw|make install prefix=/|, "DESTDIR=$datadir"])
+ or die "Failed to install ØMQ";
+
+ chdir $basedir;
+ remove_tree($srcdir);
+
+ (
+ inc_version => $version,
+ lib_version => $version,
+ inc_dir => catdir($prefix, "include"),
+ lib_dir => catdir($prefix, "lib"),
+ );
+}
+
+1;