#!/usr/bin/python
# $Id: build.py 21 2008-01-16 13:08:31Z mhordecki $
# $Author: mhordecki $
# $LastChangedDate: 2008-01-16 13:08:31 +0000 (Wed, 16 Jan 2008) $
# $LastChangedRevision: 21 $
# $LastChangedBy: mhordecki $
#
#######################################
#
# Build.py v. 0.3beta
#
# Copyright (c) 2008 Michal Hordecki
# Licensed under GNU GPLv3
#
#######################################
from optparse import OptionParser
import sys
import os
import shutil
import pickle
import hashlib
def _pkgconfig_check():
global PKGCONFIG_LIBS
if len(PKGCONFIG_LIBS)==0: return true
def _pkgconfig_cflags():
if len(PKGCONFIG_LIBS)==0: return ''
pkgc='`pkg-config --cflags '
for i in PKGCONFIG_LIBS:
pkgc+=i+' '
pkgc+='` '
return pkgc
def _pkgconfig_libs():
if len(PKGCONFIG_LIBS)==0: return ''
pkgc='`pkg-config --libs '
for i in PKGCONFIG_LIBS:
pkgc+=i+' '
pkgc+='` '
return pkgc
#### BUILDFILE MACROS
X=0
ACT_TARGET=''
EXT={}
FILES={}
DATA=[]
LINKER=''
PKGCONFIG_LIBS=[]
PREFIX='/usr'
_SHAREDIR=''
STEP=''
FLAGS={}
INCLUDE={}
LIBS=[]
#private
LOG=[]
LOCLOG={}
def _save_progress():
global LOCLOG
f=open('.buildpy.tmp','w+')
pickle.dump(LOCLOG,f)
f.close()
def _load_progress():
global LOCLOG
if not os.path.exists('.buildpy.tmp'):
LOCLOG={}
return
f=open('.buildpy.tmp')
LOCLOG=pickle.load(f)
f.close()
def _file_calc_hash(p):
f=open(p)
return hashlib.md5(f.read()).hexdigest()
def _fmt_libs():
global LIBS
ret=''
for l in LIBS:
ret+='-l'+l+' '
return ret
def _fmt_include(c):
global INCLUDE
ret=''
if not c in INCLUDE: return ''
for l in INCLUDE[c]:
ret+='-I'+l+' '
return ret
def target(t):
TARGET='target_'+t
eval(TARGET)()
def clean(t):
CLEAN='clean_'+t
target(t)
eval(CLEAN)()
def build(t):
BUILD='build_'+t
target(t)
eval(BUILD)()
def install(t):
INSTALL='install_'+t
target(t)
eval(INSTALL)()
def remove(t):
REMOVE='remove_'+t
target(t)
eval(REMOVE)()
def assign_c(c):
EXT['c']=c
FILES[c]=[]
def assign_cxx(c):
EXT['cpp']=c
EXT['cxx']=c
FILES[c]=[]
def add_dir_recursively(c,d):
if not os.path.exists(d):
warning('Given path '+d+' does not exist.')
if c=='source':
for root, dirs, files in os.walk(d):
for file in files:
if root.find('/.')!=-1: continue #checking against hidden folders
ext=os.path.splitext(file)[1][1:]
if not EXT.has_key(ext):
print 'Found ',root+os.sep+file,'- ommitting'
else:
print 'Found ',root+os.sep+file
FILES[EXT[ext]].append(root+os.sep+file)
elif c=='data':
for root, dirs, files in os.walk(d):
for file in files:
if root.find('/.')!=-1: continue #checking against hidden folders
print 'Found data file',root+os.sep+file
DATA.append(root+os.sep+file)
else:
warning('Unrecongized add_dir_recursively category.')
def process_build():
global OBJ,LOCLOG,FLAGS,LIBS
OBJ=[]
libstr=_fmt_libs()
print "Building.."
_load_progress()
if not os.path.exists('obj'):
os.mkdir('obj')
if not os.path.exists('bin'):
os.mkdir('bin')
for c in FILES:
print 'Using',c
incstr=_fmt_include(c)
for f in FILES[c]:
objpath=os.path.splitext(f)[0]+'.o '
if f in LOCLOG:
if LOCLOG[f]==_file_calc_hash(f):
OBJ.append(objpath)
continue
cmd=c+' '+incstr
if c in FLAGS:
cmd+=FLAGS[c]+' '
cmd+=' -c '
cmd+=f+' '
cmd+='-o'
cmd+=objpath
cmd+=_pkgconfig_cflags()
print cmd
if os.system(cmd)!=0:
_save_progress()
error('Build error, stopping.')
OBJ.append(objpath)
LOCLOG[f]=_file_calc_hash(f)
# linking
print 'Linking'
cmd=LINKER+' '+libstr
cmd+='-obin/'+ACT_TARGET+' '
for c in OBJ:
cmd+=c+' '
cmd+=_pkgconfig_libs()
print cmd
if os.system(cmd)!=0:
error('Linking error, stopping.')
_save_progress()
print "Finished building",ACT_TARGET
def start_install():
global SHAREDIR,_SHAREDIR,LOG
_SHAREDIR=SHAREDIR
print 'Installing',ACT_TARGET
SHAREDIR=os.path.join(SHAREDIR,ACT_TARGET)
LOG=[]
def end_install():
global SHAREDIR,_SHAREDIR,LOG
LOG.append(SHAREDIR)
print 'Creating log file'
f=open(os.path.join(SHAREDIR,'.buildpy.log'),'w+')
pickle.dump(LOG,f)
f.close()
SHAREDIR=_SHAREDIR
print 'Finshed',ACT_TARGET
def copy(s,dest):
global DATA,SHAREDIR,LOG
if s=='data':
for d in DATA:
destdir=os.path.join(dest,os.path.split(d)[0])
if not os.path.exists(destdir):
os.makedirs(destdir)
cmd='install '+d+' '+destdir+os.sep
print cmd
LOG.append(os.path.join(destdir,os.path.basename(d)))
os.system(cmd)
else:
warning('Bad copy() target.')
def copy_bin(dest,symlink=''):
global LOG,ACT_TARGET
cmd='install bin'+os.sep+ACT_TARGET+' '+dest+os.sep
LOG.append(os.path.join(dest,ACT_TARGET))
print cmd
os.system(cmd)
if symlink!='':
cmd='ln -s '+dest+os.sep+ACT_TARGET+' '+symlink+os.sep+ACT_TARGET
LOG.append(os.path.join(symlink,ACT_TARGET))
print cmd
os.system(cmd)
def _recursive_del(d):
if not os.path.exists(d): return
for root, dirs, files in os.walk(d, topdown=False):
for name in files:
os.remove(os.path.join(root, name))
for name in dirs:
os.rmdir(os.path.join(root, name))
os.rmdir(d)
def process_clean():
_recursive_del('bin')
if os.path.exists('.buildpy.tmp'):
os.remove('.buildpy.tmp')
for c in FILES:
for f in FILES[c]:
objpath=os.path.splitext(f)[0]+'.o'
if os.path.exists(objpath):
print objpath
os.remove(objpath)
print 'Finished cleaning'
def process_remove(dir):
global ACT_TARGET
dir=os.path.join(dir,ACT_TARGET,'.buildpy.log')
print 'Removing',ACT_TARGET
f=open(dir)
log=pickle.load(f)
f.close()
for f in log:
if os.path.isdir(f):
_recursive_del(f)
else:
os.remove(f)
print 'Finished removing',ACT_TARGET
#### BUILD.PY CODE
def die(text):
print text
exit()
def error(text):
print 'ERROR :',text
exit()
def warning(text):
print 'WARNING :',text
opts=OptionParser(version='%prog 0.1', usage="%prog [TARGET] [OPTIONS]", description='Simple build tool written in Python. Useful in small projects where overbloated features of make, jam & co are unnecessary. build.py uses external configuration files called buildfiles, similar to Makefiles and Jamfiles. See docs for more info.')
opts.set_defaults(file='Buildfile')
opts.add_option('-f','--file',dest='file',help='set buildfile path. Default : \'buildfile\'')
"""opts.add_option('-G','--Get',action='store_const',const='G',dest='mode',help='Get mangas from server')
opts.add_option('-Q','--Query',action='store_const',const='Q',dest='mode',help='Query info about mangas from server')
opts.add_option('-m','--manga',dest='manga',help='Select manga which has NAME as a keyword (See also -Q option)',metavar='NAME')
opts.add_option('-c','--chapter',dest='chapter',help='Query/get manga from chapter specified by NUM',metavar="NUM")
opts.add_option('-r','--range',dest='range',help='Query/get range of chapters specified by RANGE (format: START-END)',metavar="RANGE")
opts.add_option('-a','--all',action="store_true",dest='all',help='Query/get all chapters of manga')
"""
TARGETS=[]
opt=opts.parse_args(sys.argv[1:])
opt=opt[0]
for a in sys.argv[1:]:
if a[0]=='-': break
TARGETS.append(a)
if len(TARGETS)==0:
TARGETS=['build']
if not os.path.exists(opt.file):
error('Buildfile '+opt.file+' does not exist.')
execfile(opt.file)
for t in TARGETS:
target(t)