#!/usr/bin/perl
use
lib (__DIR__ .
'/..'
);
my
$Sharepath
= File::Spec->catfile(
'auto'
,
'share'
,
'dist'
,
'Couchbase-Client'
,
'Library'
);
my
$LIBCOUCHBASE
=
"libcouchbase"
;
my
$PARENT_MM
;
my
$SEARCHPATH_S
;
{
my
@checklib_libs
=
grep
$_
&&
$_
ne
'-lcouchbase'
,
@PLCBTopLevel::LIBS
;
$SEARCHPATH_S
=
join
(
' '
,
@checklib_libs
) ||
''
;
}
my
%CHECKLIB_OPTIONS
= (
LIBS
=>
$SEARCHPATH_S
,
INC
=>
$PLCBTopLevel::INC
);
my
%MM_Options
= (
NAME
=>
'Couchbase::libcouchbase'
,
AUTHOR
=>
q{M. Nunberg <mnunberg@haskalah.org}
,
VERSION_FROM
=>
'libcouchbase.pm'
,
ABSTRACT_FROM
=>
'libcouchbase.pm'
);
my
$LIBCOUCHBASE_CFUNC
=
<<'EOC';
unsigned int version = 0;
(void)libcouchbase_get_version(&version);
if(version >= 0x010001) {
return 0;
}
return 1;
EOC
my
$LIBEVENT_CFUNC
=
<<EOC;
int version_major = 0, version_minor = 0;
const char *version_string = event_get_version();
if(!version_string) {
return 1;
}
sscanf(version_string, "%d.%d", &version_major, &version_minor);
if(version_major >= 2) {
return 0;
} else if(version_major == 1 && version_minor >= 4) {
return 0;
}
return 1;
EOC
sub
check_dependency {
my
(
$names
,
$fn
,
%extra
) =
@_
;
$names
=
ref
$names
?
$names
: [
$names
];
print
STDERR
"\nChecking for @{$names}...\n"
;
local
%ENV
=
%ENV
;
if
(
$PLCBTopLevel::Bundled
) {
return
0;
}
foreach
my
$libname
(
@$names
) {
my
(
undef
,
undef
,
$ldargs
,
$runpath
,
$sofile
) =
ExtUtils::Liblist->ext(
"$SEARCHPATH_S -l$libname"
, 0, 1);
next
unless
(
$sofile
&& (
$sofile
=
$sofile
->[0]) );
print
STDERR
"\tfound shared object: $sofile \n"
;
my
%cl_opts
= (
%CHECKLIB_OPTIONS
,
lib
=>
$libname
,
debug
=> 1,
);
if
(
$runpath
) {
$ENV
{LD_RUN_PATH} .=
$runpath
;
}
if
(
$fn
) {
$cl_opts
{function} =
$fn
;
}
print
STDERR
"\tCompiling test program\n"
;
if
(check_lib(
%cl_opts
,
%extra
)) {
print
STDERR
"\tOK ($libname)\n"
;
return
1;
}
}
print
STDERR
"\tNOT FOUND\n"
;
return
0;
}
sub
insert_announcement {
my
$msg
=
shift
;
my
@lines
;
my
$line
=
"\t\$(NOECHO)\$(ECHO) "
;
push
(
@lines
,
$line
.
"~"
x 60)
for
(0..2);
push
@lines
,
$line
.
$msg
;
push
(
@lines
,
$line
.
"~"
x 60)
for
(0..2);
if
(
wantarray
) {
return
@lines
;
}
else
{
return
join
(
"\n"
,
@lines
);
}
}
sub
create_buildscript_invocation {
my
(
$mm
,
$build
,
$install
,
$deps
) =
@_
;
my
$script_cppflags
=
$mm
->{INC};
my
$config_ccflags
=
$Config
{ccflags};
$config_ccflags
=~ s/-(?:D|f|O|M|g)\S+//g;
$config_ccflags
=~ s/\s+/ /g;
$script_cppflags
.=
' '
.
$config_ccflags
;
$PLCBTopLevel::U_LibPath
||=
""
;
my
$script_ldflags
=
$mm
->{LDLOADLIBS} .
' '
.
$PLCBTopLevel::U_LibPath
.
' '
.
$Config
{ldflags};
my
$java_arg
=
$PLCBTopLevel::HaveJava
?
"--have-java"
:
""
;
my
@lines
= (
"\t"
.
'$(PERLRUN) '
.
File::Spec->catfile(
'..'
,
'build_libraries.pl'
) .
"\\"
,
"\t"
.
sprintf
(
" --build-prefix=%s \\\n\t\t--install-prefix=%s $java_arg"
,
$mm
->quote_literal(
$build
),
$mm
->quote_literal(
$install
)) .
"\\"
,
"\t"
.
sprintf
(
" --env-cppflags=%s"
,
$mm
->quote_literal(
$script_cppflags
)) .
"\\"
,
"\t"
.
sprintf
(
" --env-libs=%s"
,
$mm
->quote_literal(
$script_ldflags
)) .
"\\"
,
"\t"
.
sprintf
(
" --rpath=%s"
,
$mm
->quote_literal(
$mm
->{LD_RUN_PATH})) .
"\\"
,
"\t"
.
join
(
" "
,
@$deps
),
);
return
@lines
;
}
sub
ldrunpath2rpath {
my
(
$parent
,
$ld_run_path
) =
@_
;
return
unless
(
$Config
{lddlflags} =~ /([^ ]*-(?:rpath|R)[,=]?)([^ ]+)/
&& -d $2);
my
$prefix
= $1;
my
$existing_flags
=
$parent
->{LDDLFLAGS};
my
@components
=
map
{
"$prefix$_"
}
split
(
$Config
{path_sep},
$ld_run_path
);
$parent
->{LDDLFLAGS} =
join
(
" "
,
@components
) .
" "
.
$Config
{lddlflags};
printf
STDERR (
"\nFound RPATH directive in perl's linker flags.\n"
.
"Mangled compiler line now is: %s"
,
$parent
->{LDDLFLAGS});
}
sub
mangle_parent_makefile {
my
(
$parent
,
$deps
) =
@_
;
no
strict
'refs'
;
print
STDERR (
"Mangling parent MM methods for extra dependencies\n"
);
my
$libpath
= File::Spec->catfile(
$Sharepath
,
'lib'
);
my
$methname
=
ref
(
$parent
).
'::dynamic_lib'
;
my
$old_meth
=
$parent
->can(
'dynamic_lib'
);
my
$blib_dep_path
=
"\$(INST_LIB)\$(DFSEP)$Sharepath"
;
my
$dest_dep_path
=
"\$(DESTINSTALLSITELIB)\$(DFSEP)$Sharepath"
;
my
$dep
=
"$blib_dep_path\$(DFSEP)lib\$(DFSEP)$LIBCOUCHBASE.\$(SO)"
;
$parent
->{MYEXTLIB} =
$dep
;
*{
ref
(
$parent
) .
"::dynamic_lib"
} =
sub
{
my
(
$mm
,
@args
) =
@_
;
my
$ret
=
$old_meth
->(
$mm
,
@args
,
INST_DYNAMIC_DEP
=>
$dep
);
$ret
=
join
(
"\n"
,
"\$(MYEXTLIB) ::"
,
"\t\ "
.
$mm
->cd(
"src"
,
'$(MAKE)'
),
) .
$ret
;
return
$ret
;
};
my
$ldload
=
$parent
->{LDLOADLIBS} ||
""
;
my
$runpath
=
$parent
->{LD_RUN_PATH} ||
""
;
$runpath
=
"$blib_dep_path\$(DFSEP)lib:"
.
"$dest_dep_path\$(DFSEP)lib"
.
":$runpath"
;
$ldload
=
"-L$blib_dep_path\$(DFSEP)lib"
;
{
my
$parent_dir
= abs_path(
".."
);
$parent
->{INST_LIB} = File::Spec->catfile(
$parent_dir
,
$parent
->{INST_LIB});
}
$parent
->{LDLOADLIBS} =
$ldload
;
$parent
->{LD_RUN_PATH} =
$runpath
;
ldrunpath2rpath(
$parent
,
$runpath
);
$parent
->{INC} .=
" -I$blib_dep_path\$(DFSEP)include"
;
my
$parent_inc
=
$parent
->{INC};
my
$inc_oneliner
=
sprintf
(
"PLCB_ConfUtil::write_tmpflags(qq{%s})"
,
$parent_inc
);
no
warnings
qw(redefine once)
;
*MY::postamble
=
sub
{
my
@lines
= (
"$dep:"
,
(insert_announcement(
"will build for ultimate target $dep"
)),
(create_buildscript_invocation(
$parent
,
$blib_dep_path
,
$dest_dep_path
,
$deps
)),
(insert_announcement(
"dependencies done"
)),
"\t"
.
$parent
->oneliner(
$inc_oneliner
, [
'-I../'
,
'-MPLCB_ConfUtil'
]),
""
,
""
,
"all :: $dep"
,
);
return
join
(
"\n"
,
@lines
);
};
}
sub
MM_Configure {
my
(
$self
,
$h
) =
@_
;
my
$parent
=
$ExtUtils::MakeMaker::Parent
[0];
$PLCBTopLevel::MM_TopLevel
=
$parent
;
$PARENT_MM
=
$parent
;
die
(
"Must be run from within top-level Makefile.PL"
)
unless
$parent
;
my
@to_build
;
if
(
$ENV
{PLCB_BUILD_ALL}) {
log_err(
'build_all reuqested'
);
@to_build
=
qw(VBUCKET COUCHBASE EVENT)
;
goto
GT_MANGLE;
}
printf
STDERR (
"\nWill run a few test programs to see "
.
"if depencies are required\n"
);
my
$have_libcouchbase
=
check_dependency(
'couchbase'
,
$LIBCOUCHBASE_CFUNC
,
header
=> [
'sys/types.h'
,
'libcouchbase/couchbase.h'
] );
if
(
$have_libcouchbase
) {
return
$h
;
}
else
{
push
@to_build
,
qw(COUCHBASE VBUCKET)
;
}
if
(!check_dependency(
'event'
,
$LIBEVENT_CFUNC
,
header
=> [
'event.h'
,
'stdio.h'
] )) {
push
@to_build
,
'EVENT'
;
}
GT_MANGLE:
my
$errmsg
=
"\n"
.
"Couchbase::Client needs to build the following dependencies:\n"
.
"\t@to_build\n\n"
.
"You may want to install dependencies from your package manager\n"
.
"or install the bundled version.\n"
.
"\n"
.
"Installing the bundled version will (for better or worse) NOT\n"
.
"affect applications which depend on those libraries\n"
.
"\n"
.
"Install bundled libraries?"
;
my
$promptval
= prompt(
$errmsg
,
"y"
);
if
(
$promptval
!~ /^y/i) {
print
STDERR
"You have selected not to build and install the bundled\n"
.
"dependencies. Couchbase::Client will not be built\n"
;
exit
(0);
}
print
STDERR
"Will build: @to_build\n\n..."
;
mangle_parent_makefile(
$parent
, \
@to_build
);
return
$h
;
}
$MM_Options
{CONFIGURE} = \
&MM_Configure
;
WriteMakefile(
%MM_Options
);