forked from gladk/trunk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
yadeSCons.py
185 lines (166 loc) · 6.47 KB
/
yadeSCons.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def getRealVersion():
"Attempts to get yade version from RELEASE file if it exists or from bzr/svn/git, or from VERSION"
import os.path,re,os
if os.path.exists('RELEASE'):
return file('RELEASE').readline().strip()
if os.path.exists('.bzr'):
for l in os.popen("LC_ALL=C bzr revno 2>/dev/null").readlines():
return 'bzr'+l[:-1]
elif os.path.exists('.git'):
try:
import git
repo = git.Repo(".git/")
try:
head = repo.commits('master')[0]
rev = str(head)[:7]
dateP = head.authored_date
versionN = "%04d-%02d-%02d.git-%s" % (dateP.tm_year, dateP.tm_mon, dateP.tm_mday, rev)
return versionN
except AttributeError:
import datetime
head = repo.commit('master')
dateT = head.authored_date
dateP = datetime.date.fromtimestamp(dateT)
versionN = "%04d-%02d-%02d.git-%s" % (dateP.year, dateP.month, dateP.day, head.name_rev[:7])
return versionN
except ImportError:
print "\
=====================\n\
Package python-git is not installed.\nUnable to identify last git-version.\n\
On Debian-based systems it can be installed using the following command:\n\
sudo apt-get install python-git\n\
====================="
return None
if os.path.exists('VERSION'):
return file('VERSION').readline().strip()
return None
class Plugin:
def __init__(self,name,src,deps,feats,module):
self.name,self.src,self.deps,self.feats,self.module=name,src,deps,feats,module
def __str__(self):
return '%s/%s [%s] (%s)'%(self.module,self.name,','.join(self.feats),','.join(self.libs))
def grepForIncludes(root,f):
import re
ret=set()
skipping=False
lineNo=0
for l in open(root+'/'+f):
if re.match(r'\s*#endif.*$',l): skipping=False; continue
if skipping: continue
m=re.match(r'^\s*#include\s*<yade/([^/]+/[^/]+)/(.*)>.*$',l)
if m:
incMod=m.group(1); baseName=m.group(2).split('.')[0];
if incMod=='core' or incMod.startswith('lib/'): continue
if skipping: continue
ret.add(baseName)
continue
m=re.match(r'\s*#ifdef\s*YADE_(.*)\s*$',l)
if m:
feat=m.group(1).lower()
if feat not in features: skipping=True; continue
return ret
features=[]
def scanAllPlugins(cacheFile,feats):
"""Traverse all files in pkg/, recording what plugins they link with and what features they require.
Save the result in a cache file and only regenerate the information if the cache file is missing."""
import os, os.path, re, shelve
features=feats # update the module-level var
if cacheFile:
refresh=os.path.exists(cacheFile)
plugInfo=shelve.open(cacheFile)
else:
plugInfo={}; refresh=True
if refresh:
for root, dirs, files in os.walk('pkg/',topdown=True):
for f in files:
if not (f.endswith('.cpp') or f.endswith('.cc') or f.endswith('C')): continue
ff=root+'/'+f
linkDeps,featureDeps=set(),set()
isPlugin=True # False
skipping=False
for l in open(ff):
if re.match(r'\s*#endif.*$',l): skipping=False; continue
if skipping: continue
m=re.match(r'\s*#(ifdef|ifndef)\s*YADE_(.*)\s*$',l)
if m:
cond,feat=m.group(1),m.group(2).lower()
if (cond=='ifdef' and feat not in features) or (cond=='ifndef' and feat in features): skipping=True
if re.match(r'\s*YADE_PLUGIN\(.*',l): isPlugin=True
m=re.match(r'^\s*#include\s*<yade/([^/]+/[^/]+)/(.*)>.*$',l)
if m:
incMod=m.group(1); incHead=m.group(2); baseName=incHead.split('.')[0]; assert(len(incHead.split('.'))==2)
if incMod=='core' or incMod.startswith('lib/'): continue
if os.path.exists(root+'/'+m.group(2)):
linkDeps.update(grepForIncludes(root,m.group(2)))
linkDeps.add(incHead.split('.')[0])
continue
m=re.match('^\s*#include\s*"([^/]*)".*$',l)
if m:
inc=m.group(1); incBaseName=m.group(1).split('.')[0]
if not os.path.exists(root+'/'+m.group(1)):
print "WARNING: file %s included from %s doesn't exist"%(m.group(1),ff)
else:
linkDeps.update(grepForIncludes(root,m.group(1)))
continue
if isPlugin:
plugin=f.split('.')[0]
m=re.match(r'.*pkg/([^/]*)(/.*|)$',root)
plugInfo[plugin]=Plugin(plugin,ff,linkDeps,featureDeps,m.group(1))
pp={}
for p in plugInfo.keys(): pp[p]=plugInfo[p]
if cacheFile: plugInfo.close()
return pp
def getWantedPlugins(plugInfo,excludes,features,chunkSize,hotPlugins):
"""Use pluginInfo (generated by scanAllPlugins) and return only plugins that we should build,
based on excludes and available features.
Set the plugin object according to chunkSize and set also other plugins this one should link to."""
ret={}
feats=set([feat.upper() for feat in features])
excludes=set(excludes)
for p in plugInfo:
plug=plugInfo[p]
if plug.module in excludes: continue
if not plug.feats<=feats:
continue # plugin needs more feature than we have
ret[plug.name]=plug
for p in plugInfo.values(): p.obj=getPluginObj(p,chunkSize,hotPlugins)
for p in plugInfo.values(): p.libs=getPluginLibs(p,plugInfo)
return ret
def getPluginObj(plug,chunkSize,hotPlugins):
"""Return name of library this plugin will be compiled into, based on current chunkSize."""
if chunkSize==1: return plug.name
#elif linkStrategy=='per-pkg': return plug.module
elif chunkSize>1 or chunkSize<=0:
if plug.name in hotPlugins: return plug.name
else: return 'plugins'
#elif linkStrategy=='static': return 'plugins'
def getPluginLibs(p,plugInfo):
"""Returns library names this plugin should link to, based on current information about other plugins."""
ret=set()
for dep in p.deps:
if dep in plugInfo.keys():
ret.add(plugInfo[dep].obj)
elif dep.startswith('!'):
ret.add(dep[1:])
else:
pass
#print p.src+':',dep,"not a plugin?"
ret.discard(p.obj)
return ret
def buildPluginLibs(env,plugInfo):
objs={}
chunkSize=env['chunkSize']
for p in plugInfo.values():
if not objs.has_key(p.obj): objs[p.obj]=(set(),set())
objs[p.obj][0].add(p.src)
objs[p.obj][1].update(p.libs)
for obj in objs.keys():
srcs=list(objs[obj][0])
if len(srcs)>1:
if len(srcs)<chunkSize or chunkSize<=0: srcs=env.CombineWrapper('$buildDir/'+obj+'.cpp',srcs)
# thanks to http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python :
else: srcs=[env.CombineWrapper('$buildDir/'+obj+'%d.cpp'%j,srcs[i:i+chunkSize]) for j,i in enumerate(range(0,len(srcs),chunkSize))]
#if linkStrategy!='static':
env.Install('$LIBDIR/plugins',env.SharedLibrary(obj,srcs,LIBS=env['LIBS']+['yade-support','core']+list(objs[obj][1])))
#else:
# env.Install('$LIBDIR/plugins',env.StaticLibrary(obj,srcs,LIBS=env['LIBS']+['yade-support','core']+list(objs[obj][1])))