#!/usr/bin/env python

# This is the experimental scons build script for Samba 4. For a proper 
# build use the old build system (configure + make). scons may
# eventually replace this system.
#
# Copyright (C) 2005 Jelmer Vernooij <jelmer@samba.org>
# Copyright (C) 2005 Tim Potter <tpot@samba.org>
#
# Published under the GNU GPL
#
# TODO:
# - finish fallback code
# - support for init functions
# - separate config file for lib/replace/
# - Subsystem() ?

import cPickle, string, os

opts = Options(None, ARGUMENTS)
opts.AddOptions(
		BoolOption('developer','enable developer flags', False),
		PathOption('prefix','installation prefix','/usr/local/samba'),
		BoolOption('configure','run configure checks', False),
)

class SambaEnvironment(Environment):
    def Subsystem(self, target, source, **kwargs):
        """Create a Samba subsystem, basically a static library.

	By default a prototype file for the subsystem is created,
	unless the keyword argument 'noproto' is present.  A variable
	corresponding to the target name is exported, unless the
	keyword argument 'noexport' is present."""

	# Generate prototype file for subsystem

	if not kwargs.has_key('noproto'):
	    self.proto_headers += self.CProtoHeader(
		'%s_proto.h' % target, [str(x) for x in source])

	# Maketh the library

	result = self.Library(target, source, **kwargs)

	# Export library symbol

	if not kwargs.has_key('noexport'):
	    locals()[target] = result	# Eww
	    Export(target)

	return result

hostenv = SambaEnvironment(
		toolpath=['build/scons','.'],
		tools=['default','pidl','proto','et','asn1','samba'],
		options=opts,
		CPPPATH=['#include','#','#lib'], 
        CPPDEFINES={'_SAMBA_BUILD_': None},
		)

hostenv.Help(opts.GenerateHelpText(hostenv))

# We don't care about NFS builds...
hostenv.SetOption('max_drift', 1)

if hostenv['developer']:
	hostenv.Append(CCFLAGS='-Wall')
	hostenv.Append(CCFLAGS='-Wshadow')
	hostenv.Append(CCFLAGS='-Werror-implicit-function-declaration')
	hostenv.Append(CCFLAGS='-Wstrict-prototypes')
	hostenv.Append(CCFLAGS='-Wpointer-arith')
	hostenv.Append(CCFLAGS='-Wcast-qual')
	hostenv.Append(CCFLAGS='-Wcast-align')
	hostenv.Append(CCFLAGS='-Wwrite-strings')
	hostenv.Append(CCFLAGS='-Wmissing-format-attribute')
	hostenv.Append(CCFLAGS='-Wformat=2')
	hostenv.Append(CCFLAGS='-Wno-format-y2k')
	hostenv.Append(CCFLAGS='-Wno-declaration-after-statement')

# Some tools get confused if $HOME isn't defined
hostenv.Append(ENV={'HOME': os.environ['HOME']})

# Store configuration data in a dictionary.

def saveconfig(data):
	"""Save configuration dict to a file."""
	cached = cPickle.dump(data, open('sconf.cache', 'w'))

def loadconfig():
	"""Load configuration dict from a file."""
	try:
		return cPickle.load(open('sconf.cache', 'r'))
	except IOError:
		return None

defines = loadconfig()

if defines == None:
	hostenv['configure'] = 1

if hostenv['configure']:
	defines = {}

Export('defines')

hostenv.Append(CPPPATH = ['#heimdal_build', '#heimdal/lib/krb5',
			  '#heimdal/lib/hdb', '#heimdal/lib/gssapi',
			  '#heimdal/lib/asn1', '#heimdal/lib/des',
			  '#heimdal/kdc', '#heimdal/lib/roken',
			  '#heimdal/lib/com_err'])

Export('hostenv')

buildenv = hostenv

Export('buildenv')

cross_compiling = 0

if cross_compiling:
	buildenv = hostenv.Copy()
	buildenv.BuildDir('build-env','.')

dynenv = hostenv.Copy()

paths = { 
	'BINDIR': 'bin',
	'SBINDIR': 'sbin',
	'CONFIGFILE': 'cfg',
	'LOGFILEBASE': 'lfb',
	'NCALRPCDIR': 'ncalrpc',
	'LMHOSTSFILE': 'lmhosts',
	'LIBDIR': 'libdir',
	'SHLIBEXT': 'ext',
	'LOCKDIR': 'lockdir',
	'PIDDIR': 'piddir',
	'PRIVATE_DIR': 'private',
	'SWATDIR': 'swat'
}

Export('paths')

if hostenv['configure']:
	
	conf = hostenv.Configure()

	for h in ['sys/select.h','fcntl.h','sys/fcntl.h'] + \
		['utime.h','grp.h','sys/id.h','limits.h','memory.h'] + \
		['compat.h','math.h','sys/param.h','ctype.h','sys/wait.h'] + \
		['sys/resource.h','sys/ioctl.h','sys/ipc.h','sys/mode.h'] + \
		['sys/mman.h','sys/filio.h','sys/priv.h','sys/shm.h','string.h'] + \
		['strings.h','stdlib.h','sys/vfs.h','sys/fs/s5param.h','sys/filsys.h'] + \
		['termios.h','termio.h','fnmatch.h','pwd.h','sys/termio.h'] + \
		['sys/time.h','sys/statfs.h','sys/statvfs.h','stdarg.h'] + \
		['sys/syslog.h','syslog.h','stdint.h','inttypes.h','locale.h'] + \
		['shadow.h','nss.h','nss_common.h','ns_api.h','sys/security.h'] + \
		['security/pam_appl.h','sys/capability.h'] + \
		['sys/acl.h','stdbool.h', 'netinet/in.h', 'sys/socket.h', 'arpa/inet.h', 'netdb.h']:
		if conf.CheckCHeader(h):
			defines['HAVE_' + h.upper().replace('.','_').replace('/','_')] = 1

	for f in ['setsid','pipe','crypt16','getauthuid','strftime','sigprocmask',
		'sigblock','sigaction','initgroups','setgroups','sysconf', 'getpwanam',
		'setlinebuf','srandom','random','srand','rand','usleep','timegm',
		'backtrace','setbuffer']:
		if conf.CheckFunc(f):
			defines['HAVE_' + f.upper()] = 1

	# Pull in GNU extensions
	defines['_GNU_SOURCE'] = 1

	# Hardcode signal return type for now
	defines['RETSIGTYPE'] = 'void'
	
	if conf.CheckType('comparison_fn_t', '#define _GNU_SOURCE\n#include <stdlib.h>'):
		defines['HAVE_COMPARISON_FN_T'] = 1

	if conf.CheckType('sig_atomic_t', '#include <signal.h>'):
		defines['HAVE_SIG_ATOMIC_T_TYPE'] = 1

	if conf.TryCompile("""
#include <sys/types.h>

int main() 
{
	volatile int i = 0;
	return 0;
}""", '.c'):
		defines['HAVE_VOLATILE'] = 1

	if conf.TryCompile("""
#include <stdio.h>

int main() 
{
   typedef struct {unsigned x;} FOOBAR;
   #define X_FOOBAR(x) ((FOOBAR) { x })
   #define FOO_ONE X_FOOBAR(1)
   FOOBAR f = FOO_ONE;   
   static struct {
	FOOBAR y; 
	} f2[] = {
		{FOO_ONE}
	};   
	return 0;
}""", '.c'):
		defines['HAVE_IMMEDIATE_STRUCTURES'] = 1

	hostenv.AlwaysBuild('include/config.h')

	if conf.TryCompile("""
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>

int
main ()
{
if ((struct tm *) 0)
return 0;
  return 0;
}
""", '.c'):
		defines['TIME_WITH_SYS_TIME'] = 1

	if conf.TryCompile("""
#include <sys/time.h>
#include <unistd.h>
main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}
""", '.c'):
		defines['HAVE_GETTIMEOFDAY_TZ'] = 1

	# Check for header that defines "DIR"
	for h in ['dirent.h','sys/ndir.h','sys/dir.h','ndir.h']:
		if conf.TryCompile("""
#include <%s>

int main() { DIR *x; return 0; }""" % h, '.c'):
			defines['HAVE_' + h.upper().replace('.','_').replace('/','_')] = 1
			break

	conf.Finish()

[dynenv.Append(CPPDEFINES = {p: '\\"%s\\"' % paths[p]}) for p in paths]
	
dynconfig = dynenv.Object('dynconfig.c')
Export('dynconfig')

hostenv.proto_headers = []

SConscript(
		dirs=['dsdb', 'libcli', 'lib','torture','rpc_server','cldap_server',
		'nbt_server','client','ldap_server','libnet','nsswitch','web_server',
		'smbd','dsdb','heimdal_build','ntptr','kdc','smb_server','ntvfs',
		'winbind','scripting','auth', 'librpc','script/tests'])

# proto.h

def create_global_proto(env, target, source):
	fd = open(str(target[0]), 'w')
	[fd.write('#include "%s"\n' % x) for x in source]
	fd.close()

def create_global_proto_print(*args, **kwargs):
	print 'Building global proto.h'

hostenv.Command('include/proto.h', hostenv.proto_headers,
	Action(create_global_proto, create_global_proto_print))

# Save configuration

if hostenv['configure']:
	saveconfig(defines)

# How to create config.h file
def create_config_h(env, target, source):
	fd = open(str(target[0]), 'w')
	[fd.write('#define %s %s\n' % (x, defines[x])) for x in defines]
	fd.close()

def create_config_h_print(*args, **kwargs):
	print 'Building config.h'

hostenv.Command('include/config.h', [],
		Action(create_config_h, create_config_h_print))
hostenv.Append(CPPDEFINES = {'HAVE_CONFIG_H': 1})