Skip to content

Commit 39c00f2

Browse files
committed
Merge subtree drake/master.
2 parents 0422f44 + a0c5940 commit 39c00f2

File tree

4 files changed

+326
-17
lines changed

4 files changed

+326
-17
lines changed

drake/.gitlab-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ variables:
66

77
check:x86_64-trusty-gcc4:
88
stage: check
9-
image: registry.gitlab.gruntech.org/mefyl/drake/trusty-ci
9+
image: registry.gitlab.gruntech.org/infinit/drake/trusty-ci
1010
script:
1111
- pip3 install -r requirements.txt
1212
- cd _build && ./drake //check

drake/src/drake/cmake.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import drake
22
from functools import lru_cache
3+
from itertools import chain
34
import os
45

56
class CMakeBuilder(drake.Builder):
@@ -21,8 +22,8 @@ def __init__(self, toolkit, srcs, dsts, vars,
2122
else drake.path_source() / self.__prefix
2223
self.__env = dict(os.environ)
2324
self.__env.update({
24-
'CC': self.toolkit.c,
25-
'CXX': self.toolkit.cxx,
25+
'CC': ' '.join(toolkit.command_c),
26+
'CXX': ' '.join(toolkit.command_cxx),
2627
})
2728
self.__cmake_cache = drake.node('CMakeCache.txt')
2829
self.__targets = targets
@@ -49,21 +50,20 @@ def execute(self):
4950
cpath = str(self.__cmake_cache.path())
5051
if os.path.exists(cpath):
5152
os.unlink(cpath)
52-
with drake.CWDPrinter(self.__prefix):
53-
if not self.cmd(' '.join(self.cmake_cmd),
54-
self.cmake_cmd,
55-
cwd = self.__prefix,
56-
env = self.__env):
53+
if not self.cmd(' '.join(self.cmake_cmd),
54+
self.cmake_cmd,
55+
cwd = self.__prefix,
56+
env = self.__env):
57+
return False
58+
if self.__targets is None:
59+
return self.cmd('make', self.make_cmd, cwd = self.__prefix)
60+
for t in self.__targets:
61+
if isinstance(t, str):
62+
wd, tgt = '', t
63+
else:
64+
wd, tgt = t[0], t[1]
65+
if not self.cmd('make %s' % tgt, ['make', tgt], cwd = self.__prefix / wd):
5766
return False
58-
if self.__targets is None:
59-
return self.cmd('make', self.make_cmd, cwd = self.__prefix)
60-
for t in self.__targets:
61-
if isinstance(t, str):
62-
wd, tgt = '', t
63-
else:
64-
wd, tgt = t[0], t[1]
65-
if not self.cmd('make %s' % tgt, ['make', tgt], cwd = self.__prefix / wd):
66-
return False
6767
return True
6868

6969
@property

drake/src/drake/cxx/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,10 @@ def command_c(self):
717717
def c(self):
718718
return self.compiler_c
719719

720+
@property
721+
def compiler_wrappers(self):
722+
return list(self.__compiler_wrappers)
723+
720724
def preprocess_istrue(self, vars, **kwargs):
721725
return map(lambda e: bool(int(e)),
722726
self.preprocess_values(vars, **kwargs))

drake/src/drake/gnu.py

Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
import collections
2+
import functools
3+
import itertools
4+
import subprocess
5+
6+
import drake
7+
import drake.cxx
8+
import drake.git
9+
10+
@functools.lru_cache(1)
11+
def _default_make_binary():
12+
from drake.which import which
13+
to_try = [
14+
'make',
15+
'gmake',
16+
'mingw32-make',
17+
'mingw64-make',
18+
]
19+
for binary in to_try:
20+
path = which(binary)
21+
if path is not None:
22+
return path
23+
24+
class GNUBuilder(drake.Builder):
25+
26+
def __init__(
27+
self,
28+
cxx_toolkit,
29+
targets = [],
30+
configure: """Configure script path (or None if no configure
31+
step is needed)""" = None,
32+
working_directory: "Deduced from configure" = None,
33+
configure_args: "Arguments of the configure script" = [],
34+
sources = [],
35+
make_binary: "Make binary" = None,
36+
makefile: "Makefile filename, used if not None" = None,
37+
build_args: "Additional arguments for the make command" = ['install'],
38+
additional_env: "Additional environment variables" = {},
39+
configure_interpreter = None,
40+
patch = None,
41+
configure_stdout: 'Show configure standard output' = False,
42+
build_stdout: 'Show build standard output' = False):
43+
self.__toolkit = cxx_toolkit
44+
self.__build_stdout = build_stdout
45+
self.__configure = configure
46+
self.__configure_args = configure_args
47+
self.__configure_interpreter = configure_interpreter
48+
self.__configure_stdout = configure_stdout
49+
self.__targets = list(targets)
50+
if make_binary is None:
51+
self.__make_binary = _default_make_binary()
52+
else:
53+
self.__make_binary = make_binary
54+
self.__makefile = makefile
55+
self.__build_args = build_args
56+
self.__env = {}
57+
self.__env.update(additional_env)
58+
self.__patch = patch
59+
if make_binary is not None:
60+
self.__env.setdefault('MAKE', make_binary.replace('\\', '/'))
61+
if working_directory is not None:
62+
self.__working_directory = working_directory
63+
if not self.__working_directory.exists():
64+
self.__working_directory.mkpath()
65+
else:
66+
if self.__configure is None:
67+
raise Exception(
68+
"Cannot deduce the working directory (no configure script)"
69+
)
70+
self.__working_directory = self.__configure.path().dirname()
71+
drake.Builder.__init__(
72+
self,
73+
(configure is not None and [configure] or []) + sources,
74+
self.__targets)
75+
if isinstance(cxx_toolkit.patchelf, drake.BaseNode):
76+
self.add_src(cxx_toolkit.patchelf)
77+
78+
def execute(self):
79+
env = dict(self.__env)
80+
import os
81+
env.update(os.environ)
82+
# Patch
83+
if self.__patch is not None:
84+
patch_path = str(drake.path_root() / self.__patch.path())
85+
patch_cmd = ['patch', '-N', '-p', '1', '-i', patch_path],
86+
if not self.cmd('Patch %s' % self.work_directory,
87+
patch_cmd,
88+
cwd = self.work_directory):
89+
return False
90+
# Configure step
91+
if self.__configure is not None:
92+
if not self.cmd('Configure %s' % self.work_directory,
93+
self.command_configure,
94+
cwd = self.work_directory,
95+
env = env,
96+
leave_stdout = self.__configure_stdout):
97+
return False
98+
# Build step
99+
if not self.cmd('Build %s' % self.work_directory,
100+
self.command_build,
101+
cwd = self.work_directory,
102+
env = env,
103+
leave_stdout = self.__build_stdout):
104+
return False
105+
for target in self.__targets:
106+
path = target.path().without_prefix(self.work_directory)
107+
if isinstance(target, drake.cxx.DynLib):
108+
rpath = '.'
109+
elif isinstance(target, drake.cxx.Executable):
110+
rpath = '../lib'
111+
else:
112+
continue
113+
with drake.WritePermissions(target):
114+
cmd = self.__toolkit.rpath_set_command(target.path(), rpath)
115+
if self.__toolkit.os is not drake.os.windows:
116+
if not self.cmd('Fix rpath for %s' % target.path(), cmd):
117+
return False
118+
if self.__toolkit.os is drake.os.macos:
119+
cmd = ['install_name_tool',
120+
'-id', '@rpath/%s' % target.name().basename(),
121+
str(target.path())]
122+
if not self.cmd('Fix rpath for %s' % target.path(), cmd):
123+
return False
124+
lib_dependecies = self.parse_otool_libraries(target.path())
125+
for dep in lib_dependecies:
126+
if dep.basename() in (t.path().basename() for t in self.__targets):
127+
cmd = [
128+
'install_name_tool',
129+
'-change',
130+
str(dep),
131+
'@rpath/%s' % dep.basename(),
132+
str(target.path()),
133+
]
134+
if not self.cmd('Fix dependency name for %s' % target.path(), cmd):
135+
return False
136+
return True
137+
138+
def parse_otool_libraries(self, path):
139+
command = ['otool', '-L', str(path)]
140+
return [drake.Path(line[1:].split(' ')[0])
141+
for line
142+
in subprocess.check_output(command).decode().split('\n')
143+
if line.startswith('\t')]
144+
145+
@property
146+
def command_configure(self):
147+
if self.__configure is None:
148+
return None
149+
config = [str(drake.path_build(absolute = True) / self.__configure.path())]
150+
if self.__configure_interpreter is not None:
151+
config.insert(0, self.__configure_interpreter)
152+
return config + self.__configure_args
153+
154+
@property
155+
def command_build(self):
156+
if self.__makefile is not None:
157+
return [self.__make_binary, '-f', self.__makefile, 'install'] + self.__build_args
158+
return [self.__make_binary] + self.__build_args
159+
160+
@property
161+
def work_directory(self):
162+
return str(self.__working_directory)
163+
164+
165+
def hash(self):
166+
env = {}
167+
env.update(self.__env)
168+
env.pop('DRAKE_RAW', '1')
169+
return ''.join([
170+
str(self.command_configure),
171+
str(self.command_build),
172+
str(tuple(sorted(env))),
173+
])
174+
175+
def __str__(self):
176+
return '%s(%s)' % (self.__class__.__name__, self.__working_directory)
177+
178+
class FatLibraryGenerator(drake.Builder):
179+
180+
def __init__(self,
181+
input_libs,
182+
output_lib,
183+
headers = [],
184+
input_headers = None,
185+
output_headers = None):
186+
drake.Builder.__init__(self,
187+
input_libs,
188+
itertools.chain([output_lib], (drake.node(output_headers / p)
189+
for p in headers)))
190+
self.__input_libs = input_libs
191+
self.__output_lib = output_lib
192+
self.__headers = headers
193+
if input_headers:
194+
self.__input_headers = drake.path_build(input_headers)
195+
else:
196+
self.__input_headers = None
197+
if output_headers:
198+
self.__output_headers = drake.path_build(output_headers)
199+
else:
200+
self.__output_headers = None
201+
202+
def execute(self):
203+
res = self.cmd('Lipo %s' % self.input_paths,
204+
self.lipo_command,
205+
leave_stdout = False)
206+
if not res:
207+
return False
208+
if self.__headers and self.__input_headers and self.__output_headers:
209+
res = self.cmd('cp %s' % self.__input_headers,
210+
self.copy_headers_command,
211+
leave_stdout = False)
212+
return res
213+
214+
@property
215+
def lipo_command(self):
216+
if len(self.__input_libs) == 1:
217+
res = ['cp']
218+
res.extend(self.input_paths)
219+
res.append(self.__output_lib.path())
220+
else:
221+
res = ['lipo']
222+
res.extend(self.input_paths)
223+
res.extend(['-create', '-output'])
224+
res.append(self.__output_lib.path())
225+
return res
226+
227+
@property
228+
def input_paths(self):
229+
res = []
230+
for input in self.__input_libs:
231+
res.append(input.path())
232+
return res
233+
234+
@property
235+
def copy_headers_command(self):
236+
return ['cp', '-r',
237+
self.__input_headers, self.__output_headers]
238+
239+
240+
class VersionGenerator(drake.Builder):
241+
242+
def __init__(self, output, git = None, production_build = True):
243+
git = git or drake.git.Git()
244+
drake.Builder.__init__(self, [git], [output])
245+
self.__git = git
246+
self.__output = output
247+
self.__production_build = production_build
248+
249+
def execute(self):
250+
self.output('Generate %s' % self.__output.path())
251+
chunks = collections.OrderedDict()
252+
if self.__production_build:
253+
version = self.__git.description()
254+
else:
255+
version = '%s-dev' % self.__git.version().split('-')[0]
256+
chunks['version'] = version
257+
chunks['major'], chunks['minor'], chunks['subminor'] = \
258+
map(int, version.split('-')[0].split('.'))
259+
with open(str(self.__output.path()), 'w') as f:
260+
variables = (self._variable(*item) for item in chunks.items())
261+
for line in itertools.chain(
262+
self._prologue(), variables, self._epilogue()):
263+
print(line, file = f)
264+
return True
265+
266+
def _prologue(self):
267+
return iter(())
268+
269+
def _epilogue(self):
270+
return iter(())
271+
272+
def _variable(self, name, value):
273+
raise NotImplementedError()
274+
275+
def hash(self):
276+
return self.__production_build
277+
278+
279+
class PythonVersionGenerator(VersionGenerator):
280+
281+
def _variable(self, name, value):
282+
return '%s = %s' % (name, repr(value))
283+
284+
class CxxVersionGenerator(VersionGenerator):
285+
286+
def __init__(self, prefix, *args, **kwargs):
287+
super().__init__(*args, **kwargs)
288+
self.__prefix = prefix
289+
290+
def _variable(self, name, value):
291+
try:
292+
return '#define %s_%s %s' % \
293+
(self.__prefix.upper(), name.upper(), int(value))
294+
except:
295+
return '#define %s_%s "%s"' % \
296+
(self.__prefix.upper(), name.upper(), value)
297+
298+
def _prologue(self):
299+
yield '#ifndef %s_GIT_VERSION_HH' % self.__prefix
300+
yield '# define %s_GIT_VERSION_HH' % self.__prefix
301+
yield ''
302+
303+
def _epilogue(self):
304+
yield ''
305+
yield '#endif'

0 commit comments

Comments
 (0)