summaryrefslogtreecommitdiffstats
path: root/bksys/generic.py
diff options
context:
space:
mode:
Diffstat (limited to 'bksys/generic.py')
-rw-r--r--bksys/generic.py498
1 files changed, 498 insertions, 0 deletions
diff --git a/bksys/generic.py b/bksys/generic.py
new file mode 100644
index 0000000..580cbd5
--- /dev/null
+++ b/bksys/generic.py
@@ -0,0 +1,498 @@
+## Thomas Nagy, 2005
+
+"""
+Detect and store the most common options
+* kdecxxflags : debug=1 (-g) or debug=full (-g3, slower)
+ else use the user CXXFLAGS if any, - or -O2 by default
+* prefix : the installation path
+* extraincludes : a list of paths separated by ':'
+ie: scons configure debug=full prefix=/usr/local extraincludes=/tmp/include:/usr/local
+"""
+
+BOLD ="\033[1m"
+RED ="\033[91m"
+GREEN ="\033[92m"
+YELLOW ="\033[1m" #"\033[93m" # unreadable on white backgrounds
+CYAN ="\033[96m"
+NORMAL ="\033[0m"
+
+import os, re, types, sys, string, shutil, stat
+
+import SCons.Defaults
+import SCons.Tool
+import SCons.Util
+from SCons.Script.SConscript import SConsEnvironment
+from SCons.Options import Options, PathOption
+
+class genobj:
+ def __init__(self, val, env):
+ if not val in "program shlib kioslave staticlib".split():
+ print "unknown genobj given: "+val
+ env.Exit(1)
+
+ self.type = val
+ self.orenv = env
+ self.env = None
+ self.executed = 0
+
+ self.target=''
+ self.src=None
+
+ self.cxxflags=''
+ self.cflags=''
+ self.includes=''
+
+ self.linkflags=''
+ self.libpaths=''
+ self.libs=''
+
+ # vars used by shlibs
+ self.vnum=''
+ self.libprefix=''
+
+ # a directory where to install the targets (optional)
+ self.instdir=''
+ # ignore the DESTDIR (optional)
+ self.nodestdir=''
+
+ # change the working directory before reading the targets
+ self.chdir=''
+
+ # these members are private
+ self.chdir_lock=None
+ self.old_os_dir=''
+ self.old_fs_dir=''
+ self.p_local_shlibs=[]
+ self.p_local_staticlibs=[]
+ self.p_global_shlibs=[]
+
+ #if not env.has_key('USE_THE_FORCE_LUKE'): env['USE_THE_FORCE_LUKE']=[self]
+ #else: env['USE_THE_FORCE_LUKE'].append(self)
+
+ def lockchdir(self):
+ if not self.chdir: return
+ self.chdir_lock=1
+ SConfFS=SCons.Node.FS.default_fs
+ self.old_fs_dir=SConfFS.getcwd()
+ self.old_os_dir=os.getcwd()
+ #os.chdir(old_os_dir+'/'+self.chdir)
+ SConfFS.chdir( SConfFS.Dir('#/'+self.chdir), change_os_dir=1)
+
+ def unlockchdir(self):
+ if not self.chdir: return
+ if self.chdir_lock:
+ #os.chdir(self.old_os_dir)
+ SCons.Node.FS.default_fs.chdir(self.old_fs_dir, change_os_dir=0)
+ self.chdir_lock=None
+
+ def execute(self):
+ if self.orenv.has_key('DUMPCONFIG'):
+ print self.xml()
+ return
+
+ self.lockchdir()
+
+ self.env = self.orenv.Copy()
+
+ if not self.src or len(self.src) == 0:
+ print RED+"no source file given to object - self.src"+NORMAL
+ self.env.Exit(1)
+ if not self.env.has_key('nosmart_includes'): self.env.AppendUnique(CPPPATH=['./'])
+ if self.type == "kioslave": self.libprefix=''
+
+ if len(self.includes)>0: self.env.AppendUnique(CPPPATH=self.env.make_list(self.includes))
+ if len(self.cxxflags)>0: self.env.AppendUnique(CXXFLAGS=self.env.make_list(self.cxxflags))
+ if len(self.cflags)>0: self.env.AppendUnique(CCFLAGS=self.env.make_list(self.cflags))
+
+ llist=self.env.make_list(self.libs)
+ lext='.so .la'.split()
+ sext='.a'.split()
+ for l in llist:
+ sal=SCons.Util.splitext(l)
+ if len(sal)>1:
+ if sal[1] in lext: self.p_local_shlibs.append(sal[0]+'.so')
+ elif sal[1] in sext: self.p_local_staticlibs.append(sal[0]+'.a')
+ else: self.p_global_shlibs.append(l)
+
+ if len(self.p_global_shlibs)>0: self.env.AppendUnique(LIBS=self.p_global_shlibs)
+ if len(self.libpaths)>0: self.env.PrependUnique(LIBPATH=self.env.make_list(self.libpaths))
+ if len(self.linkflags)>0: self.env.PrependUnique(LINKFLAGS=self.env.make_list(self.linkflags))
+
+ # the target to return
+ ret=None
+ if self.type=='shlib' or self.type=='kioslave':
+ ret=self.env.bksys_shlib(self.target, self.src, self.instdir,
+ self.libprefix, self.vnum, nodestdir=self.nodestdir)
+ elif self.type=='program':
+ ret=self.env.Program(self.target, self.src)
+ if not self.env.has_key('NOAUTOINSTALL'):
+ self.env.bksys_install(self.instdir, ret, nodestdir=self.nodestdir)
+ elif self.type=='staticlib':
+ ret=self.env.StaticLibrary(self.target, self.src)
+
+ # we link the program against a shared library made locally, add the dependency
+ if len(self.p_local_shlibs)>0:
+ self.env.link_local_shlib(self.p_local_shlibs)
+ if ret: self.env.Depends( ret, self.p_local_shlibs )
+ if len(self.p_local_staticlibs)>0:
+ self.env.link_local_staticlib(self.p_local_staticlibs)
+ if ret: self.env.Depends( ret, self.p_local_staticlibs )
+
+ self.unlockchdir()
+
+## Copy function that honors symlinks
+def copy_bksys(dest, source, env):
+ if os.path.islink(source):
+ #print "symlinking "+source+" "+dest
+ if os.path.islink(dest):
+ os.unlink(dest)
+ os.symlink(os.readlink(source), dest)
+ else:
+ shutil.copy2(source, dest)
+ st=os.stat(source)
+ os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
+ return 0
+
+## Return a list of things
+def make_list(env, s):
+ if type(s) is types.ListType:
+ return s
+ else:
+ return s.split()
+
+def exists(env):
+ return true
+
+def generate(env):
+ ## Bksys requires scons 0.96
+ env.EnsureSConsVersion(0, 96)
+
+ SConsEnvironment.make_list = make_list
+ def doConfigure(env):
+ return not env['HELP'] and (env['_CONFIGURE'] or not env.has_key('ISCONFIGURED'))
+
+ SConsEnvironment.doConfigure = doConfigure
+ env['HELP']=0
+ if '--help' in sys.argv or '-h' in sys.argv or 'help' in sys.argv:
+ env['HELP']=1
+
+ env.addHelpText("""
+b[*** Generic options ***
+-----------------------]
+b[* debug ]: debug=1 (-g) or debug=full (-g3, slower), otherwise use
+ environment CXXFLAGS, or -O2 by default.
+b[* prefix ]: the installation path
+b[* extraincludes ]: a list of paths separated by ':'
+
+ie: b[scons configure debug=full prefix=/usr/local extraincludes=/tmp/include:/usr/local]
+""")
+
+ ## Global cache directory
+ # Put all project files in it so a rm -rf cache will clean up the config
+ if not env.has_key('CACHEDIR'):
+ env['CACHEDIR'] = os.getcwd()+'/cache/'
+ if not os.path.isdir(env['CACHEDIR']):
+ os.mkdir(env['CACHEDIR'])
+
+ ## SCons cache directory
+ # This avoids recompiling the same files over and over again:
+ # very handy when working with cvs
+ if os.getuid() != 0:
+ env.CacheDir(os.getcwd()+'/cache/objects')
+
+ # Avoid spreading .sconsign files everywhere - keep this line
+ env.SConsignFile(env['CACHEDIR']+'/scons_signatures')
+
+ def makeHashTable(args):
+ table = { }
+ for arg in args:
+ if len(arg) > 1:
+ lst=arg.split('=')
+ if len(lst) < 2:
+ continue
+ key=lst[0]
+ value=lst[1]
+ if len(key) > 0 and len(value) >0:
+ table[key] = value
+ return table
+
+ env['ARGS']=makeHashTable(sys.argv)
+
+ ## Special trick for installing rpms ...
+ env['DESTDIR']=''
+ if 'install' in sys.argv:
+ dd=''
+ if os.environ.has_key('DESTDIR'):
+ dd=os.environ['DESTDIR']
+ if not dd:
+ if env['ARGS']: dd=env['ARGS']['DESTDIR']
+ if dd:
+ env['DESTDIR']=dd+'/'
+ print CYAN+'** Enabling DESTDIR for the project ** ' + NORMAL + env['DESTDIR']
+
+ ## install symlinks for shared libraries properly
+ env['INSTALL'] = copy_bksys
+
+ ## Use the same extension .o for all object files
+ env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
+
+ ## load the options
+ cachefile=env['CACHEDIR']+'generic.cache.py'
+ opts = Options(cachefile)
+ opts.AddOptions(
+ ( 'GENCCFLAGS', 'C flags' ),
+ ( 'GENCXXFLAGS', 'debug level for the project : full or just anything' ),
+ ( 'GENLINKFLAGS', 'additional link flags' ),
+ ( 'PREFIX', 'prefix for installation' ),
+ ( 'EXTRAINCLUDES', 'extra include paths for the project' ),
+ ( 'ISCONFIGURED', 'is the project configured' ),
+ )
+ opts.Update(env)
+
+ # Use this to avoid an error message 'how to make target configure ?'
+ env.Alias('configure', None)
+
+ # Check if the following command line arguments have been given
+ # and set a flag in the environment to show whether or not it was
+ # given.
+ if 'install' in sys.argv:
+ env['_INSTALL']=1
+ else:
+ env['_INSTALL']=0
+ if 'configure' in sys.argv:
+ env['_CONFIGURE']=1
+ else:
+ env['_CONFIGURE']=0
+
+ # Configure the environment if needed
+ if doConfigure(env):
+ # be paranoid, unset existing variables
+ for var in "GENCXXFLAGS GENCCFLAGS GENLINKFLAGS PREFIX EXTRAINCLUDES ISCONFIGURED EXTRAINCLUDES".split():
+ if env.has_key(var): env.__delitem__(var)
+
+ if env['ARGS'].get('debug', None):
+ debuglevel = env['ARGS'].get('debug', None)
+ print CYAN+'** Enabling debug for the project **' + NORMAL
+ if (debuglevel == "full"):
+ env['GENCXXFLAGS'] = ['-DDEBUG', '-g3', '-Wall']
+ else:
+ env['GENCXXFLAGS'] = ['-DDEBUG', '-g', '-Wall']
+ else:
+ if os.environ.has_key('CXXFLAGS'):
+ # user-defined flags (gentooers will be elighted)
+ env['GENCXXFLAGS'] = SCons.Util.CLVar( os.environ['CXXFLAGS'] )
+ env.Append( GENCXXFLAGS = ['-DNDEBUG', '-DNO_DEBUG'] )
+ else:
+ env.Append(GENCXXFLAGS = ['-O2', '-DNDEBUG', '-DNO_DEBUG'])
+
+ if os.environ.has_key('CFLAGS'):
+ env['GENCCFLAGS'] = SCons.Util.CLVar( os.environ['CFLAGS'] )
+
+ ## FreeBSD settings (contributed by will at freebsd dot org)
+ if os.uname()[0] == "FreeBSD":
+ if os.environ.has_key('PTHREAD_LIBS'):
+ env.AppendUnique( GENLINKFLAGS = SCons.Util.CLVar( os.environ['PTHREAD_LIBS'] ) )
+ else:
+ syspf = os.popen('/sbin/sysctl kern.osreldate')
+ osreldate = int(syspf.read().split()[1])
+ syspf.close()
+ if osreldate < 500016:
+ env.AppendUnique( GENLINKFLAGS = ['-pthread'])
+ env.AppendUnique( GENCXXFLAGS = ['-D_THREAD_SAFE'])
+ elif osreldate < 502102:
+ env.AppendUnique( GENLINKFLAGS = ['-lc_r'])
+ env.AppendUnique( GENCXXFLAGS = ['-D_THREAD_SAFE'])
+ else:
+ env.AppendUnique( GENLINKFLAGS = ['-pthread'])
+
+ # User-specified prefix
+ if env['ARGS'].has_key('prefix'):
+ env['PREFIX'] = os.path.abspath( env['ARGS'].get('prefix', '') )
+ print (CYAN+'** installation prefix for the project set to : ' +
+ env['PREFIX'] +' **'+ NORMAL)
+
+ # User-specified include paths
+ env['EXTRAINCLUDES'] = env['ARGS'].get('extraincludes', None)
+ if env['EXTRAINCLUDES']:
+ print (CYAN+'** extra include paths for the project set to: ' +
+ env['EXTRAINCLUDES'] +' **'+ NORMAL)
+
+ env['ISCONFIGURED']=1
+
+ # And finally save the options in the cache
+ opts.Save(cachefile, env)
+
+ def bksys_install(lenv, subdir, files, destfile=None, nodestdir=None):
+ """ Install files on "scons install"
+ If the DESTDIR env variable has been set, (e.g. by
+ "scons install DESTDIR=$CURDIR/debian) then install files to that
+ directory, regardless of where the configure stage showed that
+ files should be installed.
+ This feature is useful for packagers, and users of GNU stow.
+
+ NB. The DESTDIR will be ignored if NODESTDIR is also set, although
+ the same effect can be acheived by not setting DESTDIR in the first
+ place."""
+
+ if not env['_INSTALL']:
+ return
+ basedir = env['DESTDIR']
+ if nodestdir or env.has_key('NODESTDIR') : basedir = "/"
+ install_list = None
+ if not destfile:
+ install_list = env.Install(basedir+subdir+'/', files)
+ else:
+ if subdir:
+ install_list = env.InstallAs(basedir+subdir+'/'+destfile, files)
+ else:
+ install_list = env.InstallAs(basedir+'/'+destfile, files)
+ env.Alias('install', install_list)
+ return install_list
+
+ def build_la_file(target, source, env):
+ """ Action for building libtool files.
+ Writes a .la file, as used by libtool."""
+ dest=open(target[0].path, 'w')
+ sname=source[0].name
+ dest.write("dlname='%s'\n" % sname)
+ if len(env['BKSYS_VNUM'])>0:
+ vnum=env['BKSYS_VNUM']
+ nums=vnum.split('.')
+ src=source[0].name
+ name = src.split('so.')[0] + 'so'
+ strn = src+" "+name+"."+str(nums[0])+" "+name
+ dest.write("library_names='%s'\n" % (strn) )
+ else:
+ dest.write("library_names='%s %s %s'\n" % (sname, sname, sname) )
+ dest.write("old_library=''\ndependency_libs=''\ncurrent=0\n")
+ dest.write("age=0\nrevision=0\ninstalled=yes\nshouldnotlink=no\n")
+ dest.write("dlopen=''\ndlpreopen=''\n")
+ dest.write("libdir='%s'" % env['BKSYS_DESTDIR'])
+ dest.close()
+ return 0
+
+ def string_la_file(target, source, env):
+ print "building '%s' from '%s'" % (target[0].name, source[0].name)
+ la_file = env.Action(build_la_file, string_la_file, ['BKSYS_VNUM', 'BKSYS_DESTDIR'])
+ env['BUILDERS']['LaFile'] = env.Builder(action=la_file,suffix='.la',src_suffix=env['SHLIBSUFFIX'])
+
+ ## Function for building shared libraries
+ def bksys_shlib(lenv, target, source, libdir, libprefix='lib', vnum='', noinst=None, nodestdir=None):
+ """ Install a shared library.
+
+ Installs a shared library, with or without a version number, and create a
+ .la file for use by libtool.
+
+ If library version numbering is to be used, the version number
+ should be passed as a period-delimited version number (e.g.
+ vnum = '1.2.3'). This causes the library to be installed
+ with its full version number, and with symlinks pointing to it.
+
+ For example, for libfoo version 1.2.3, install the file
+ libfoo.so.1.2.3, and create symlinks libfoo.so and
+ libfoo.so.1 that point to it.
+ """
+ thisenv = lenv.Copy() # copying an existing environment is cheap
+ thisenv['BKSYS_DESTDIR']=libdir
+ thisenv['BKSYS_VNUM']=vnum
+ thisenv['SHLIBPREFIX']=libprefix
+
+ if len(vnum)>0:
+ thisenv['SHLIBSUFFIX']='.so.'+vnum
+ thisenv.Depends(target, thisenv.Value(vnum))
+
+ # Fix against a scons bug - shared libs and ordinal out of range(128)
+ if type(source) is types.ListType:
+ src2=[]
+ for i in source:
+ src2.append( str(i) )
+ source=src2
+
+ library_list = thisenv.SharedLibrary(target, source)
+ lafile_list = thisenv.LaFile(target, library_list)
+
+ ## Install the libraries automatically
+ if not thisenv.has_key('NOAUTOINSTALL') and not noinst:
+ thisenv.bksys_install(libdir, library_list, nodestdir=nodestdir)
+ thisenv.bksys_install(libdir, lafile_list, nodestdir=nodestdir)
+
+ ## Handle the versioning
+ if len(vnum)>0:
+ nums=vnum.split('.')
+ symlinkcom = ('cd $TARGET.dir && ' +
+ 'rm -f $TARGET.name && ' +
+ 'ln -s $SOURCE.name $TARGET.name')
+ tg = target+'.so.'+vnum
+ nm1 = target+'.so'
+ nm2 = target+'.so.'+nums[0]
+
+ thisenv.Command(nm1, tg, symlinkcom)
+ thisenv.Command(nm2, tg, symlinkcom)
+
+ #base=env['DESTDIR']+libdir+'/'
+ thisenv.bksys_install(libdir, nm1, nodestdir=nodestdir)
+ thisenv.bksys_install(libdir, nm2, nodestdir=nodestdir)
+
+ # Declare scons scripts to process
+ def subdirs(lenv, folderlist):
+ flist=[]
+ if type(folderlist) is types.ListType: flist = folderlist
+ else: flist = folderlist.split()
+ for i in flist:
+ lenv.SConscript(i+"/SConscript")
+
+ def link_local_shlib(lenv, str):
+ """ Links against a shared library made in the project """
+ lst = lenv.make_list(str)
+ for file in lst:
+ import re
+ reg = re.compile("(.*)/lib(.*).(la|so)")
+ result = reg.match(file)
+ if not result:
+ print "Unknown la file given "+file
+ continue
+ dir = result.group(1)
+ link = result.group(2)
+ lenv.AppendUnique(LIBS = [link])
+ lenv.PrependUnique(LIBPATH = [dir])
+
+ def link_local_staticlib(lenv, str):
+ """ Links against a shared library made in the project """
+ lst = lenv.make_list(str)
+ for file in lst:
+ import re
+ reg = re.compile("(.*)/(lib.*.a)")
+ result = reg.match(file)
+ if not result:
+ print "Unknown archive file given "+file
+ continue
+
+ f=SCons.Node.FS.default_fs.File(file)
+ lenv.Append(LINKFLAGS=[f.path])
+
+ #valid_targets = "program shlib kioslave staticlib".split()
+ SConsEnvironment.bksys_install = bksys_install
+ SConsEnvironment.bksys_shlib = bksys_shlib
+ SConsEnvironment.subdirs = subdirs
+ SConsEnvironment.link_local_shlib = link_local_shlib
+ SConsEnvironment.link_local_staticlib = link_local_staticlib
+
+ SConsEnvironment.genobj=genobj
+
+ if env.has_key('GENCXXFLAGS'):
+ env.PrependUnique( CXXFLAGS = env['GENCXXFLAGS'] )
+
+ if env.has_key('GENCCFLAGS'):
+ env.AppendUnique( CCFLAGS = env['GENCCFLAGS'] )
+
+ if env.has_key('GENLINKFLAGS'):
+ env.AppendUnique( LINKFLAGS = env['GENLINKFLAGS'] )
+
+ if env.has_key('EXTRAINCLUDES'):
+ if env['EXTRAINCLUDES']:
+ incpaths = []
+ for dir in str(env['EXTRAINCLUDES']).split(':'):
+ incpaths.append( dir )
+ env.Append(CPPPATH = incpaths)
+
+ env.Export('env')