#! /usr/bin/perl
######################################################################
# Copyright (C) 2001-2002 Peter J Jones (pjones@pmade.org)
# All Rights Reserved
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
# 3. Neither the name of the Author nor the names of its contributors
#    may be used to endorse or promote products derived from this software
#    without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
################################################################################
#
# cxxflags (Helper script to get compiler flags)
# Peter J Jones (pjones@pmade.org)
#
# This file is part of cxxtools (http://pmade.org/pjones/software/cxxtools/)
#
################################################################################
#
# Includes
#
################################################################################
use strict;
use Getopt::Long;
################################################################################
#
# Constants
#
################################################################################
use constant DATE   => 'Sat Aug 18 12:09:00 2001';
use constant ID	    => '$Id: cxxflags,v 1.1 2003/08/12 06:28:53 jason Exp $';
################################################################################
#
# Global Variables
#
################################################################################
use vars qw($VERSION);
$VERSION = '0.0.1';

my %clo;

my %flags = (
    'getid'	    => '',
    'debug'	    => '',
    'depend'	    => '',
    'pic'	    => '',
    'optimize'	    => '',
    'ar'	    => '',
    'arflags'	    => '',
    'arextra'	    => '',
    'sar'	    => '',
    'sarflags'	    => '',
    'warn'	    => '',
    'general'	    => '',
    'object-ext'    => '',
    'static-ext'    => '',
    'shared-ext'    => '',
    'static-pre'    => '',
    'shared-pre'    => '',
    'shared-mjr'    => '',
    'exec-ext'	    => '',
    'mkexec'	    => '',
    'mkstatic'	    => '',
    'mkshared'	    => '',
    'linker'	    => '',
    'linkwith'	    => '',
    'mtcompile'	    => '',
    'mtlink'	    => '',
);
################################################################################
#
# Code Start
#
################################################################################
GetOptions(
    \%clo,
    'help|h!',
    'cxx=s',
    'getid!',
    'setid=s',

    'arflags|A!',
    'ar|a!',
    'arextra',
    'sar!',
    'sarflags!',
    'debug!',
    'depend|d!',
    'exec-extension!',
    'general!',
    'linker!',
    'linkwith=s@',
    'mkexec=s',
    'mkstatic=s',
    'mkshared=s',
    'mkshared-name=s',
    'major=i',
    'object-extension!',
    'optimize|O!',
    'pic|p!',
    'static-lib-extension!',
    'shared-lib-extension!',
    'static-lib-prefix!',
    'shared-lib-prefix!',
    'warn!',
    'mtcompile!',
    'mtlink!',

) or usage(); $clo{'help'} and usage();

sub usage {
    print "Usage: $0 [options]\n", <<EOT;
  --cxx string            The path to the compiler to use instead of \$CXX
  --getid                 Get the current compiler ID
  --setid id              Don't run the compiler, assume it has the given id

  --ar, a                 Get the name of the tool for making archives
  --arflags, A            Get the flags for the ar tool
  --arextra               Get any commands to run after ar (ie ranlib)
  --sar                   Get the name of the tool to create shared libs
  --sarflags              Get the flags for the sar tool
  --debug                 Get flags for debugging
  --depend, d             Get the make depend compiler flags
  --exec-extension        Get the file extension for binary executables
  --general               Get general compiler flags that should always be used
  --linker                Get the name of the linker
  --linkwith lib          Get linker line for library
  --linkwith path,lib     Get linker libe for library in path
  --mkexec file           Get flag to output executable with given name
  --mkstatic file         Get flag to output static library with given name
  --mkshared file         Get flag to output shared library with given name
  --mkshared-name file    Get the complete name for a shared lib
  --major number          Set the major number for a shared lib
  --mtcomplile            Get flags for compiling multithreaded code
  --mtlink                Get flags for linking multithreaded objects
  --object-extension      Get the file extension for object files
  --optimize, O           Get the compilers level two optimization flags
  --pic, p                Get the flags for Position Independ Code
  --static-lib-extension  Get the file extension for a static library
  --shared-lib-extension  Get the file extension for a shared library
  --static-lib-prefix     Get the prefix for static libraries
  --shared-lib-prefix     Get the prefix for shared libraries
  --warn                  Get compiler flags for generating warnings
EOT
    exit;
}

$clo{'cxx'}	    ||= $ENV{'CXX'} || 'c++';
$clo{'linkwith'}    ||= [];
$clo{'major'}	    ||= '1';

stat_compiler();

################################################################################

#
# this got out of hand !
#
$clo{'debug'}		    and print "$flags{'debug'} ";
$clo{'depend'}		    and print "$flags{'depend'} ";
$clo{'pic'}		    and print "$flags{'pic'} ";
$clo{'optimize'}	    and print "$flags{'optimize'} ";
$clo{'ar'}		    and print "$flags{'ar'} ";
$clo{'arflags'}		    and print "$flags{'arflags'} ";
$clo{'arextra'}		    and print "$flags{'arextra'} ";
$clo{'sar'}		    and	print "$flags{'sar'} ";
$clo{'sarflags'}	    and print "$flags{'sarflags'} ";
$clo{'warn'}		    and print "$flags{'warn'} ";
$clo{'general'}		    and print "$flags{'general'} ";
$clo{'object-extension'}    and print "$flags{'object-ext'} ";
$clo{'static-lib-extension'}and print "$flags{'static-ext'} ";
$clo{'shared-lib-extension'}and print "$flags{'shared-ext'} ";
$clo{'static-lib-prefix'}   and print "$flags{'static-pre'} ";
$clo{'shared-lib-prefix'}   and print "$flags{'shared-pre'} ";
$clo{'mkshared-name'}	    and print "$flags{'shared-mjr'} ";
$clo{'exec-extension'}	    and print "$flags{'exec-ext'} ";
$clo{'mkexec'}		    and print "$flags{'mkexec'} ";
$clo{'mkstatic'}	    and print "$flags{'mkstatic'} ";
$clo{'mkshared'}	    and print "$flags{'mkshared'} ";
$clo{'linker'}		    and print "$flags{'linker'} ";
$clo{'linkwith'}	    and print "$flags{'linkwith'} ";
$clo{'mtcompile'}	    and print "$flags{'mtcompile'} ";
$clo{'mtlink'}		    and print "$flags{'mtlink'} ";
$clo{'getid'}		    and print "$flags{'getid'} ";
			        print "\n";
################################################################################

sub stat_compiler {
    my $output;

    if ($^O =~ /solaris/i) {
	$flags{'mtcompile'} .= " -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT";
    }

    ################################################################################
    # gcc
    if ($clo{'setid'} and $clo{'setid'} =~ /^gcc/) {
	$output = $clo{'setid'};
    } else {
	$output = `$clo{'cxx'} -v 2>&1`;
    }

    if ($output =~ /gcc/) {
	my $linker = 'gnu'; # default for now

	if ($^O =~ /solaris/i) {
	    if ($clo{'setid'}) {
		if ($clo{'setid'} eq 'gcc-sun') { $linker = 'sun'; }
	    } else {
		$output = `$clo{'cxx'} -Wl,-v 2>&1`;

		if ($output =~ /\[-h\s+name\]/ and $output =~ /\[-G\]/) {
		    $linker = 'sun';
		}
	    }
	} elsif ($^O =~ /darwin/i) {
	    $linker = 'mach';
	}

	$flags{'debug'}		= "-g";
	$flags{'depend'}	= '-M';
	$flags{'optimize'}	= '-O2';
	$flags{'ar'}		= $ENV{'AR'} || 'ar';
	$flags{'arflags'}	= $ENV{'ARFLAGS'} || 'rc';
	$flags{'sar'}		= $clo{'cxx'};
	$flags{'sarflags'}	= $ENV{'LDFLAGS'} || '';
	$flags{'warn'}		= '-Wall -W -Wcast-align -Wwrite-strings';
	$flags{'object-ext'}	= '.o';
	$flags{'static-ext'}	= '.a';
	$flags{'shared-ext'}	= '.so';
	$flags{'static-pre'}	= "lib";
	$flags{'shared-pre'}	= "lib";
	$flags{'linker'}	= $clo{'cxx'};
	$flags{'mkexec'}	= "-o $clo{'mkexec'}" if $clo{'mkexec'};
	$flags{'mkstatic'}	= $clo{'mkstatic'} if $clo{'mkstatic'};

	if ($clo{'mkshared'} or $clo{'mkshared-name'}) {
	    $flags{'shared-mjr'} = "lib$clo{'mkshared-name'}.so.$clo{'major'}" if $clo{'mkshared-name'};

	    if ($clo{'mkshared'}) {
		if ($linker eq 'gnu') {
		    $flags{'mkshared'} = "-shared -o $clo{'mkshared'} -Wl,-soname,$clo{'mkshared'}.$clo{'major'}";
		} elsif ($linker eq 'sun') {
		    $flags{'mkshared'} = "-o $clo{'mkshared'} -Wl,-G,-h,$clo{'mkshared'}.$clo{'major'}";
		} elsif ($linker eq 'mach') {
		    $flags{'mkshared'} = "-o $clo{'mkshared'} -dynamiclib -compatibility_version $clo{'major'} -current_version $clo{'major'}";
		} else {
		    print STDERR "$0: your linker is not supported.\n";
		    print STDERR "$0: you might want to install the GNU linker.\n";
		}
	    }
	}

	foreach (@{$clo{'linkwith'}}) {
	    my ($path, $lib) = split(/,/, $_, 2);
	    if ($lib) {
		$lib =~ s/^lib//;
		$flags{'linkwith'} .= "-L$path -l$lib ";
	    } else {
		$path =~ s/^lib//;
		$flags{'linkwith'} .= "-l$path";
	    }
	}

	if ($^O =~ /freebsd/i) {
	    $flags{'mtlink'} .= " -pthread";
	    $flags{'arextra'}.= "ranlib";
	} elsif ($^O =~ /darwin/i) {
	    $flags{'pic'} = '';
	    $flags{'shared.ext'} = '.dylib';
	    $flags{'exec-ext'} = '';
	    $flags{'arextra'} = "ranlib";
	} elsif ($^O =~ /cygwin/i) {
	    $flags{'pic'} = '';
	} else {
	    $flags{'mtlink'} .= " -lpthread";
	    $flags{'pic'} = '-fpic -shared';
	}

	$flags{'getid'} = "gcc-$linker";
	return;
    }

    ################################################################################
	# Microsoft Visual C++ (cl.exe)
    if ($clo{'setid'} && $clo{'setid'} =~ /^microsoft/) {
	$output = 'Microsoft';
    } else {
	$output = `$clo{'cxx'} -verbose=version 2>&1`;
    }
    if ($output =~ /Microsoft/) {

	$flags{'debug'}		= '/Od /Gz /Zi';
	$flags{'debug'}	   .= '/GA' if ($clo{'mkstatic'});
	$flags{'debug'}	   .= '/GD' if ($clo{'mkshared'});
	$flags{'depend'}	= '';
	$flags{'pic'}		= '';
	$flags{'optimize'}	= '/O2 /GB';
	$flags{'ar'}		= $clo{'cxx'};
	$flags{'ar'}		=~ s/^(.*)([\/\\]).*$/$1$2lib.exe/;
#	$flags{'arflags'}	= '-xar -o';
	$flags{'sar'}		= $flags{'ar'};
	$flags{'sarflags'}	= "/SL";
	$flags{'sarflags'}     .= 'd' if ($flags{'debug'});
	$flags{'warn'}		= '/W3';
	$flags{'object-ext'}	= '.obj';
	$flags{'static-ext'}	= '.lib';
	$flags{'shared-ext'}	= '.dll';
	$flags{'static-pre'}	= '';
	$flags{'shared-pre'}	= '';
	$flags{'mkexec'}	= "/o $clo{'mkexec'}" if $clo{'mkexec'};
	$flags{'mkstatic'}	= "$clo{'mkstatic'}" if $clo{'mkstatic'};
	# Figure out linker name
	$flags{'linker'}	= $clo{'cxx'};
	$flags{'linker'}	=~ s/^(.*)([\/\\]).*$/$1$2link.exe/;
	$flags{'mtcompile'}    .= '/MT';
	$flags{'mtcompile'}    .= 'd' if ($flags{'debug'});
	$flags{'mtlink'}       .= '/MT';
	$flags{'mtlink'}       .= 'd' if ($flags{'debug'});
    }

    ################################################################################
    # sun forte
    if ($clo{'setid'} && $clo{'setid'} =~ /^sun/) {
	$output = 'Sun';
    } else {
	$output = `$clo{'cxx'} -verbose=version 2>&1`;
    }

    if ($output =~ /Sun/) {

	$flags{'debug'}		= "-g";
	$flags{'depend'}	= '-xM';
	$flags{'pic'}		= '-Kpic';
	$flags{'optimize'}	= '-s -xlibmil -xlibmopt -xO2';
	$flags{'ar'}		= $clo{'cxx'};
	$flags{'arflags'}	= '-xar -o';
	$flags{'sar'}		= $clo{'cxx'};
	$flags{'sarflags'}	= $ENV{'LDFLAGS'} || '';
	$flags{'warn'}		= '+w';
	$flags{'object-ext'}	= '.o';
	$flags{'static-ext'}	= '.a';
	$flags{'shared-ext'}	= '.so';
	$flags{'static-pre'}	= 'lib';
	$flags{'shared-pre'}	= 'lib';
	$flags{'mkexec'}	= "-o $clo{'mkexec'}" if $clo{'mkexec'};
	$flags{'mkstatic'}	= "$clo{'mkstatic'}" if $clo{'mkstatic'};
	$flags{'linker'}	= $clo{'cxx'};
	$flags{'mtcompile'}	.= " -mt";
	$flags{'mtlink'}	.= " -mt";

	foreach (@{$clo{'linkwith'}}) {
	    my ($path, $lib) = split(/,/, $_, 2);
	    if ($lib) {
		$lib =~ s/^lib//;
		$flags{'linkwith'} .= "-L$path -l$lib ";
	    } else {
		$path =~ s/^lib//;
		$flags{'linkwith'} .= "-l$path";
	    }
	}

	if ($clo{'mkshared'} or $clo{'mkshared-name'}) {
	    $flags{'mkshared'} = "-G -o $clo{'mkshared'} -h $clo{'mkshared'}.$clo{'major'}" if $clo{'mkshared'};
	    $flags{'shared-mjr'} = "lib$clo{'mkshared-name'}.so.$clo{'major'}" if $clo{'mkshared-name'};
	}

	$flags{'getid'} = 'sun-sun';
	return;
    }

    print STDERR "$0: unknown complier $clo{'cxx'}\n";
    exit 1;
}
