The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/local/bin/perl -w
#
# $Id: Makefile.PL,v 1.11 1998/08/14 18:28:20 timbo Exp $
#
# You may distribute under the terms of either the GNU General Public
# License or the Artistic License, as specified in the Perl README file.
#
BEGIN { require 5.004 }	# 5.004 is required for Win32
use Config;
use ExtUtils::MakeMaker 5.16, qw(&WriteMakefile $Verbose);
use File::Basename;
use Getopt::Long;
use File::Spec;

use DBI 1.21;		# must be installed first ...
use DBI::DBD;
use strict;

my %opts =
(
    NAME	=> 'DBD::ODBC',
    VERSION_FROM => 'ODBC.pm',
    clean	=> { FILES=> 'ODBC.xsi dbdodbc.h' },
    dist	=> {
	#DIST_DEFAULT=> 'clean distcheck disttest ci tardist',
	DIST_DEFAULT=> 'clean distcheck tardist',
	PREOP    => '$(MAKE) -f Makefile.old distdir',
	COMPRESS => 'gzip -v9', SUFFIX => 'gz'
    },
    OBJECT	=> '$(O_FILES)',
 );
if ($ExtUtils::MakeMaker::VERSION >= 5.43) {
    $opts{AUTHOR} = 'Tim Bunce and Jeff Urlwin mailto:dbi-users@perl.org';
    $opts{ABSTRACT} = 'ODBC driver for the DBI module.';
    $opts{PREREQ_PM} = { DBI => 1.21 };
    $opts{CAPI} = 'TRUE' if $Config{archname} =~ /-object\b/i;
}

our $opt_g = 0;
our $opt_o = '';
Getopt::Long::GetOptions("g!" => \$opt_g,
	   "o=s" => \$opt_o) or die "Invalid arguments";

    print "Overriding ODBC Directory with command line option: $opt_o\n" if $opt_o ;
$opts{OPTIMIZE} = '-g -O0' if $opt_g;

print "\nConfiguring DBD::ODBC ...\n
>>>\tRemember to actually *READ* the README file!
   \tAnd re-read it if you have any problems.\n
";

my $dbi_dir      = dbd_dbi_dir();
my $dbi_arch_dir = dbd_dbi_arch_dir();

open(SQLH, ">dbdodbc.h") || die "Can't open dbdodbc.h: $!\n";
print SQLH "/* Do not edit this file. It is automatically written by Makefile.PL.\n";
print SQLH "   Any changes made here will be lost. \n*/\n\n";
print SQLH "#undef WORD /* from perly.y */\n";

my (@known_drivers) = sort { $a cmp $b } (
	'Microsoft ODBC',
	'unixodbc',
	'iodbc',
	'esodbc',
	'empress',
	'intersolve',
	'sapdb',
	'adabas',
	'udbc',
	'easysoft',
	'solid',
	'informix',
	);

if ($^O eq 'MSWin32') {
    my $extrainc = "";
    $extrainc = ";$Config{incpath}\\mfc" if $Config{cc} eq 'bcc32';
    $opts{SKIP} = ['processPL'];
    $opts{DEFINE}  = "";
    $opts{INC}  = "-I$dbi_arch_dir" . $extrainc;
    $opts{LIBS} = ["ODBC32.LIB"];
    $opts{macro}->{EXTRALIB} = 'ODBC32.LIB';
    print SQLH "#include <windows.h>\n";
    print SQLH "#include <sql.h>\n#include <sqltypes.h>\n#include <sqlext.h>\n";
}
else {

    # for Adabas
    $ENV{ODBCHOME} = $ENV{DBROOT} if $ENV{DBROOT} && -f "$ENV{DBROOT}/lib/odbclib.a";

    print "Overriding ODBC Directory with command line option: $opt_o\n" if $opt_o ;
    my $odbchome= $opt_o || $ENV{ODBCHOME};

    $odbchome = VMS::Filespec::unixify($odbchome) if $^O eq 'VMS';

    # per patches from Teun Burgers
    if (!$odbchome && $ENV{WINDIR} && $^O eq 'cygwin') {
	my $tmp_odbchome = $ENV{WINDIR};
	$tmp_odbchome =~ s/^([A-Za-z]):*$/\/\/$1/;
	$tmp_odbchome =~ s/\\/\//g;
	$odbchome = $tmp_odbchome if (-e "$tmp_odbchome/odbc.ini")
    }

    if (!$odbchome && -f '/opt/sapdb/interfaces/odbc/lib/libsqlod.a') {
	$odbchome = '/opt/sapdb/interfaces/odbc/';
    }

    unless ($odbchome) {
	print "\n";
	print "The DBD::ODBC module needs to link with an ODBC 'Driver Manager'.\n";
	print "(The Driver Manager, in turn, needs one or more database specific ODBC drivers.\n";
	print "The DBD::ODBC module does _not_ include any ODBC drivers!)\n\n";
	print "You need to indicate where your ODBC Driver Manager is installed.\n";
	print "You can do this ether by setting the ODBCHOME environment variable\n";
	print "or by runing 'perl Makefile.PL -o odbcdir'.\n\n";
	print "If you do not have an ODBC Driver Manager you can try building\n";
	print "the free iODBC Driver Manager in the iodbcsrc directory.\n\n";
	die "Makefile.PL aborted.\n";
    }
    die "ODBCHOME environment variable ($odbchome) does not refer to a directory.\n"
	unless -d $odbchome;
    warn "Using ODBC in $odbchome\n";
    $opts{INC}  = "-I. -I$dbi_arch_dir";

    # cygwin patch
    $opts{INC}  .= " -I/usr/include/w32api" if $^O eq 'cygwin';

    # Try to work out which driver manager is being used.
    # Feel free to come up with neat (or un-neat) hacks to get your's to build!

    my $lib_d1 = "$odbchome/lib";
    my $lib_d2 = "$odbchome/dlls";
    my $libs   = "odbc";
    $opts{LIBS} = " -L$lib_d1 -R$lib_d1 -L$lib_d2 -R$lib_d2 -l$libs";


    my $myodbc ='';	# edit and hack to suit!
    $myodbc = 'Microsoft ODBC'
                 if (    -e "$odbchome/system/odbc32.dll" or
			 -e "$odbchome/system32/odbc32.dll" or
                         -e "$odbchome/odbc32.dll");

    my $dlext = $Config{dlext};
    my $arext = $Config{lib_ext};

    # per patches from Nick Gorham
    $myodbc = 'unixodbc'
		if !$myodbc && <$odbchome/lib/libodbc.*>;

    $myodbc = 'iodbc'
		if !$myodbc && (<$odbchome/*iodbc*> || <$odbchome/lib/*iodbc*>);

    $myodbc = 'esodbc'
		if !$myodbc && <$odbchome/*esoobclient*>;

    $myodbc = 'empress'
		if !$myodbc && <$odbchome/lib/libempodbc.*>;

    $myodbc = 'intersolve'
		if !$myodbc && -f "$odbchome/include/qeodbc.h";

    $myodbc = 'sapdb'
		if !$myodbc && -f "$odbchome/lib/libsqlod.$arext";

    $myodbc = 'adabas'
		if !$myodbc && $ENV{DBROOT} && $odbchome eq $ENV{DBROOT} && -f "$odbchome/lib/odbclib.$arext";

    $myodbc = 'udbc'
		if !$myodbc && -f "$odbchome/lib/libudbc.$arext";

    $myodbc = 'easysoft'
		if !$myodbc && -f "$odbchome/lib/libesoobclient.$dlext";

    $myodbc = 'solid'
		if !$myodbc && -f "$odbchome/lib/libsolcli.$dlext";

    # JL 2002-12-16: This test is accurate on Unix (Solaris 7) with IBM
    # Informix ClientSDK 2.80.UC1, which includes IBM Informix CLI
    # v3.81.000, an ODBC 3.x driver.
	# NB: The correct value for $ODBCHOME is $INFORMIXDIR.
    $myodbc = 'informix'
		if !$myodbc && -f "$odbchome/lib/cli/libifcli.$dlext";

    if (!$myodbc) {
	local($") = ", ";
	my($list) = "@known_drivers";
	$list =~ s%^(.{30,70})\s%$1\n\t%gmo;
	die qq%
Hmm...I cannot find an ODBC driver manager that I recognize.
...And I know about these drivers:
	$list
%;
    }

    warn "\nUmm, this looks like a $myodbc type of driver manager.\n";

    if ($myodbc eq 'Microsoft ODBC') {
	print "\nBuilding for Microsoft under Cygwin\n";
	$opts{LIBS} = "-L/usr/lib/w32api -lodbc32";
        print SQLH "#include <windows.h>\n";
        print SQLH "#include <sql.h>\n";
        print SQLH "#include <sqltypes.h>\n";
        print SQLH "#include <sqlext.h>\n";
        print SQLH "#undef WIN32\n";
        $opts{dynamic_lib} = {OTHERLDFLAGS => "-lodbc32"};
    }
    elsif ($myodbc eq 'iodbc') {
	my $ilibdir = "$odbchome/lib";
	my @ilibs = <$ilibdir/*iodbc*.*>;
	@ilibs = grep { /\.($Config{so}|$Config{dlext}|a)$/ } @ilibs;
	die "That's odd, I can't see any iodbc libs in $ilibdir" unless @ilibs;
	# This is a hack using Intersolve's free Solaris ODBC manager
	# Since it doesn't come with the sql header files (!) we get them from iODBC!
	# Note: we use DEFINE not INC for iODBC so we don't get its config.h
	print "\n";
	print "We expect to find the isql.h, isqlext.h and iodbc.h files (which were\n";
	print "supplied with iODBC) in \$ODBCHOME/include directory alongside\n";
	print "the @ilibs library.\n\n";
	my $ilibpath = $ilibs[0]; # XXX if both .so and .a, pick based on LINKTYPE?
	my $ilibname = basename($ilibpath);
	$opts{DEFINE} = "-I$odbchome/include";
	if ($ilibname =~ /^iodbc/) { # no "lib" prefix
	    $opts{LIBS} = "";
	    $opts{dynamic_lib} = { OTHERLDFLAGS => "$ilibpath" };
	}
	else {
	    # remove lib prefix and .so suffix so "-l" style link can be used
	    $ilibname =~ s/^lib(iodbc.*?)\.\w+$/$1/;
	    $opts{LIBS} = "-L$ilibdir -l$ilibname";

	    # changed /\Q$ilibpath/ to /\Q$ilibdir/ per recommendation
	    # by Ron Savage
	    warn "Warning: LD_LIBRARY_PATH doesn't include $odbchome/lib\n"
		unless $ENV{LD_LIBRARY_PATH} =~ /\Q$ilibdir/;
	}
	#print SQLH qq{#define FAR \n#define EXPORT \n#define CALLBACK \n};
	#print SQLH qq{#include <iodbc.h>\n};
	print SQLH qq{#include <isqlext.h>\n};
	print SQLH qq{#include <sql.h>\n};
	print SQLH qq{#include <sqltypes.h>\n};
	#print SQLH qq{#include "fixup_t.h"\n};
    }
    elsif ($myodbc eq 'unixodbc') {
	my @ilibs = <$odbchome/lib/libodbc.*>;
	@ilibs = grep { /\.($Config{so}|$Config{dlext}|a)$/ } @ilibs;
	die "That's odd, I can't see any unixodbc libs in $odbchome" unless @ilibs;
	print "We expect to find the sql.h, sqlext.h and (which were\n";
	print "supplied with unixODBC) in \$ODBCHOME/include directory alongside\n";
	print "the @ilibs library. in \$ODBCHOME/lib\n\n";
	my $ilibpath = $ilibs[0]; # XXX if both .so and .a, pick based on LINKTYPE?
	my $ilibname = basename($ilibpath);
	$opts{DEFINE} = "-I$odbchome/include";
	if ($ilibname =~ /^odbc/) { # no "lib" prefix
	    $opts{LIBS} = "";
	    $opts{dynamic_lib} = { OTHERLDFLAGS => "$ilibpath" };
	}
	else {
	    # remove lib prefix and .so suffix so "-l" style link can be used
	    $ilibname =~ s/^lib(odbc.*?)\.\w+$/$1/;
	    $opts{LIBS} = "-L$odbchome/lib -l$ilibname";
	    warn "Warning: LD_LIBRARY_PATH doesn't include $odbchome\n"
		unless $ENV{LD_LIBRARY_PATH} =~ /\Q$odbchome\/lib/;
	}
	print SQLH qq{#include <sql.h>\n};
	print SQLH qq{#include <sqlucode.h>\n};
	print SQLH qq{#include <sqltypes.h>\n};
	print SQLH qq{#include <sqlext.h>\n};
    }
    elsif ($myodbc eq 'esodbc') {
	my @ilibs = <$odbchome/*esoobclient.*>;
	print "Located library @ilibs\n";
	# omit . prefix in next grep as some $Config types have . and some don't
	@ilibs = grep { /($Config{so}|$Config{dlext}|$Config{lib_ext})$/ } @ilibs;
	die "That's odd, I can't see any esoobclient libs in $odbchome" unless @ilibs;
	print "We expect to find the sql.h and sqlext.h files (which were\n";
	print "supplied with esoobclient) in \$ODBCHOME/include directory alongside\n";
	print "the @ilibs library.\n\n";
	my $ilibpath = $ilibs[0]; # XXX if both .so and .a, pick based on LINKTYPE?
	my $ilibname = basename($ilibpath);
	print "Using library $ilibname\n";
	$opts{INC} .= " -I$odbchome/include";
	#
	# ptrmismatch avoids the char/unsigned problems in DBD
	# outtyplen is one incorrect fprintf in dbiimp.c(200)
	# promotmatchw - old prototypes problem
	#
	$opts{CCFLAGS} .= "/warnings=informational=(outtypelen,ptrmismatch,promotmatchw)"
	    if ($Config{cc} =~ /DECC/ && $^O eq 'VMS' );
	if ($ilibname =~ /^esoobclient/) { # no "lib" prefix
	    $opts{LIBS} = "";
	    $opts{dynamic_lib} = { OTHERLDFLAGS => "$ilibpath" };
	}
	else {
	    my $extralibs="";
	    if (($^O eq 'VMS') && ($ilibname =~ /$Config{lib_ext}$/)) {
		    $extralibs = " -lcs_share -lsupport -leasyrpc";
		    print "Adding libraries $extralibs\n";
	    }
	    # remove lib prefix and so suffix so "-l" style link can be used
	    $ilibname =~ s/^lib(esoobclient.*?)\.\w+$/$1/;
	    $opts{LIBS} = "-L$odbchome -l$ilibname $extralibs";
	    if ($^O ne "VMS") {
	       warn "Warning: LD_LIBRARY_PATH doesn't include $odbchome\n"
		     unless $ENV{LD_LIBRARY_PATH} =~ /\Q$odbchome/;
	    }
	}
	print SQLH qq{#define FAR \n#define EXPORT \n#define CALLBACK \n};
	print SQLH qq{#include <sqlext.h>\n};
	print SQLH qq{#include <sqlucode.h>\n};
	print SQLH qq{#include <sql.h>\n};
	print SQLH qq{#include <sqltypes.h>\n};
    }
    elsif ($myodbc eq 'intersolve') {
	$opts{DEFINE}  = "";
  	print SQLH qq{#include <qeodbc.h>\n};
	if (-f "$odbchome/include/sql.h") {
	    print "You seem to have the official header files.\n";
	    $opts{INC} .= " -I$odbchome/include";
	    print SQLH qq{#include <sql.h>\n#include <sqltypes.h>\n#include <sqlext.h>\n};
	}
	else {
	    # This is common on Solaris
	    print "You don't seem to have the official header files,\n";
	    print "so I'll use the iODBC ones instead.\n";
	    $opts{INC} .= " -I$odbchome/include -Iiodbcsrc";
	    print SQLH qq{#include <isql.h> \n#include <isqlext.h>\n};
	}
    }
    elsif ($myodbc eq 'empress') {
	$opts{INC} .= " -I$odbchome/include";
	$opts{DEFINE}  = "";
	print SQLH qq{#include <odbcsys.h>\n};
	print SQLH qq{#include <sql.h>\n#include <sqlext.h>\n};
	$opts{LIBS} = "-L$odbchome/lib -R$odbchome/lib -lempodbc";
    }
    elsif ($myodbc eq 'sapdb') {
	print SQLH "#include <WINDOWS.H>\n";
	print SQLH "#include <sql.h>\n";
	print SQLH "#include <sqlext.h>\n";
	print SQLH "#define HENV SQLHENV\n";
	print SQLH "#define HDBC SQLHDBC\n";
	print SQLH "#define HSTMT SQLHSTMT\n";
	print SQLH "#define DBD_ODBC_NO_SQLDRIVERCONNECT\n";
	print SQLH qq{#define DBD_ODBC_NO_DATASOURCES\n}; # unless ($^O eq 'MSWin32');

	$opts{INC} .= " -I$odbchome/incl";
	$opts{LDFROM} = "\$(OBJECT) $odbchome/lib/libsqlod.a";
    }
    elsif ($myodbc eq 'adabas') {
	print SQLH "#define FAR \n#define EXPORT \n#define CALLBACK \n";
	print SQLH "#include <WINDOWS.H>\n";
	print SQLH "#include <sql.h>\n";
	print SQLH "#include <sqlext.h>\n";
	$opts{INC} .= " -I$odbchome/incl";
	$opts{LIBS} = "-L$odbchome/lib -lsqlrte -lsqlptc";
	$opts{LDFROM} = "\$(OBJECT) $odbchome/lib/odbclib.a";
    }
    elsif ($myodbc eq 'udbc') {
        print SQLH qq{#include <libudbc.h>\n};
        $opts{INC} .= " -I$odbchome/include";
        $opts{DEFINE}  = "";
        $opts{LIBS} = "-L$odbchome/lib -R$odbchome/lib -ludbc";
    }
    elsif ($myodbc eq 'easysoft') {
        $opts{INC} .= " -I$odbchome/include";
        $opts{LIBS} = "-L$odbchome/lib -lesoobclient";
        print SQLH qq{#include <sql.h>\n#include <sqlext.h>\n};
    }
    elsif ($myodbc eq 'solid') {
        $opts{INC} .= " -I$odbchome/include";
        $opts{LIBS} = "-L$odbchome/lib -lsolcli";
	# Solid does not support DataSources
	print SQLH qq{#define DBD_ODBC_NO_DATASOURCES\n};
	# Solid does not support DataSources
	print SQLH qq{#define DBD_ODBC_NO_SQLDRIVERCONNECT\n};
        print SQLH qq{#include <cli0cli.h>\n};
    }
    elsif ($myodbc eq 'informix') {
		# JL 2002-12-16: See comments above for environment details.
        $opts{INC}  = "-I$odbchome/incl/cli $opts{INC}";
        $opts{LIBS} = "-L$odbchome/lib/cli -lifcli -lifdmr";
        $opts{DEFINE} .= "-DNO_WIN32";		# Applies to Unix only, of course
        print SQLH qq{#include <stddef.h>\n};
        print SQLH qq{#include <infxcli.h>\n};
    }
    else {
	print "\n*** WARNING ***\a\n";
	print "Unknown driver manager. Using default build process.\n";
	print "This will almost certainly fail at some point.\n";
	print "In which case you will need to edit/hack the Makefile.PL\n";
	print "to suit your needs. (Specifically to locate your odbc\n";
	print "library and header files.)\n\n";
	$opts{DEFINE}  = "";
	print SQLH qq{#include <sql.h> \n#include <sqlext.h>\n};
    }
}
print SQLH qq{\n};
print SQLH qq{#include "fixup_c.h"\n};
print SQLH qq{\n};
close(SQLH);

print "\n";
WriteMakefile(%opts);

local($^W)=0;
print qq{
The DBD::ODBC tests will use these values for the database connection:
    DBI_DSN=$ENV{DBI_DSN}		e.g. dbi:ODBC:demo
    DBI_USER=$ENV{DBI_USER}
    DBI_PASS=$ENV{DBI_PASS}
};
print "Warning: not all required environment variables are set.\n"
	unless ($ENV{DBI_DSN} && $ENV{DBI_USER} && $ENV{DBI_PASS});
print "Warning: DBI_DSN ($ENV{DBI_DSN}) doesn't start with 'dbi:ODBC:'\n"
	if ($ENV{DBI_DSN} && $ENV{DBI_DSN} !~ m/^dbi:ODBC:/);
print "\n";

sub MY::post_constants {
   my ($self) = shift;

   '
# make Changes file available as installed pod docs "perldoc DBI::Changes"
inst_libdbdodbc = ' . File::Spec->catdir($self->{INST_LIB}, 'DBD/ODBC') . '
changes_pm = ' . File::Spec->catfile($self->{INST_LIB}, 'DBD/ODBC', 'Changes.pm') . '

config :: $(changes_pm)
    @$(NOOP)

$(changes_pm): Changes
	$(NOECHO) $(MKPATH) $(inst_libdbdodbc)
	$(NOECHO) $(RM_F) $(changes_pm)
	$(CP) Changes $(changes_pm)
';

}

# ====================================================================

{
    package MY; # SUPER needs package context, $self is not sufficient

    use strict;
    use Config;


    sub postamble {
       return main::dbd_postamble(@_);
    }

    sub const_cccmd {
       my $self = shift;
       local($_) = $self->SUPER::const_cccmd(@_);

       # inject the defined local ODBC before default include to ensure
       # the ODBC driver we want is first
       if ($^O ne 'MSWin32') {
	  s/-c/-c \$\(DEFINE\)/;
	  print "Injecting selected odbc driver into cc command\n";
       }
       $_;
    }
}
__END__