OLD | NEW |
| (Empty) |
1 # Copyright (c) 2012 Google Inc. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 """ | |
6 SCons generator. | |
7 | |
8 This contains class definitions and supporting functions for generating | |
9 pieces of SCons files for the different types of GYP targets. | |
10 """ | |
11 | |
12 import os | |
13 | |
14 | |
15 def WriteList(fp, list, prefix='', | |
16 separator=',\n ', | |
17 preamble=None, | |
18 postamble=None): | |
19 fp.write(preamble or '') | |
20 fp.write((separator or ' ').join([prefix + l for l in list])) | |
21 fp.write(postamble or '') | |
22 | |
23 | |
24 class TargetBase(object): | |
25 """ | |
26 Base class for a SCons representation of a GYP target. | |
27 """ | |
28 is_ignored = False | |
29 target_prefix = '' | |
30 target_suffix = '' | |
31 def __init__(self, spec): | |
32 self.spec = spec | |
33 def full_product_name(self): | |
34 """ | |
35 Returns the full name of the product being built: | |
36 | |
37 * Uses 'product_name' if it's set, else prefix + 'target_name'. | |
38 * Prepends 'product_dir' if set. | |
39 * Appends SCons suffix variables for the target type (or | |
40 product_extension). | |
41 """ | |
42 suffix = self.target_suffix | |
43 product_extension = self.spec.get('product_extension') | |
44 if product_extension: | |
45 suffix = '.' + product_extension | |
46 prefix = self.spec.get('product_prefix', self.target_prefix) | |
47 name = self.spec['target_name'] | |
48 name = prefix + self.spec.get('product_name', name) + suffix | |
49 product_dir = self.spec.get('product_dir') | |
50 if product_dir: | |
51 name = os.path.join(product_dir, name) | |
52 else: | |
53 name = os.path.join(self.out_dir, name) | |
54 return name | |
55 | |
56 def write_input_files(self, fp): | |
57 """ | |
58 Writes the definition of the input files (sources). | |
59 """ | |
60 sources = self.spec.get('sources') | |
61 if not sources: | |
62 fp.write('\ninput_files = []\n') | |
63 return | |
64 preamble = '\ninput_files = [\n ' | |
65 postamble = ',\n]\n' | |
66 WriteList(fp, map(repr, sources), preamble=preamble, postamble=postamble) | |
67 | |
68 def builder_call(self): | |
69 """ | |
70 Returns the actual SCons builder call to build this target. | |
71 """ | |
72 name = self.full_product_name() | |
73 return 'env.%s(env.File(%r), input_files)' % (self.builder_name, name) | |
74 def write_target(self, fp, src_dir='', pre=''): | |
75 """ | |
76 Writes the lines necessary to build this target. | |
77 """ | |
78 fp.write('\n' + pre) | |
79 fp.write('_outputs = %s\n' % self.builder_call()) | |
80 fp.write('target_files.extend(_outputs)\n') | |
81 | |
82 | |
83 class NoneTarget(TargetBase): | |
84 """ | |
85 A GYP target type of 'none', implicitly or explicitly. | |
86 """ | |
87 def write_target(self, fp, src_dir='', pre=''): | |
88 fp.write('\ntarget_files.extend(input_files)\n') | |
89 | |
90 | |
91 class SettingsTarget(TargetBase): | |
92 """ | |
93 A GYP target type of 'settings'. | |
94 """ | |
95 is_ignored = True | |
96 | |
97 | |
98 compilable_sources_template = """ | |
99 _result = [] | |
100 for infile in input_files: | |
101 if env.compilable(infile): | |
102 if (type(infile) == type('') | |
103 and (infile.startswith(%(src_dir)r) | |
104 or not os.path.isabs(env.subst(infile)))): | |
105 # Force files below the build directory by replacing all '..' | |
106 # elements in the path with '__': | |
107 base, ext = os.path.splitext(os.path.normpath(infile)) | |
108 base = [d == '..' and '__' or d for d in base.split('/')] | |
109 base = os.path.join(*base) | |
110 object = '${OBJ_DIR}/${COMPONENT_NAME}/${TARGET_NAME}/' + base | |
111 if not infile.startswith(%(src_dir)r): | |
112 infile = %(src_dir)r + infile | |
113 infile = env.%(name)s(object, infile)[0] | |
114 else: | |
115 infile = env.%(name)s(infile)[0] | |
116 _result.append(infile) | |
117 input_files = _result | |
118 """ | |
119 | |
120 class CompilableSourcesTargetBase(TargetBase): | |
121 """ | |
122 An abstract base class for targets that compile their source files. | |
123 | |
124 We explicitly transform compilable files into object files, | |
125 even though SCons could infer that for us, because we want | |
126 to control where the object file ends up. (The implicit rules | |
127 in SCons always put the object file next to the source file.) | |
128 """ | |
129 intermediate_builder_name = None | |
130 def write_target(self, fp, src_dir='', pre=''): | |
131 if self.intermediate_builder_name is None: | |
132 raise NotImplementedError | |
133 if src_dir and not src_dir.endswith('/'): | |
134 src_dir += '/' | |
135 variables = { | |
136 'src_dir': src_dir, | |
137 'name': self.intermediate_builder_name, | |
138 } | |
139 fp.write(compilable_sources_template % variables) | |
140 super(CompilableSourcesTargetBase, self).write_target(fp) | |
141 | |
142 | |
143 class ProgramTarget(CompilableSourcesTargetBase): | |
144 """ | |
145 A GYP target type of 'executable'. | |
146 """ | |
147 builder_name = 'GypProgram' | |
148 intermediate_builder_name = 'StaticObject' | |
149 target_prefix = '${PROGPREFIX}' | |
150 target_suffix = '${PROGSUFFIX}' | |
151 out_dir = '${TOP_BUILDDIR}' | |
152 | |
153 | |
154 class StaticLibraryTarget(CompilableSourcesTargetBase): | |
155 """ | |
156 A GYP target type of 'static_library'. | |
157 """ | |
158 builder_name = 'GypStaticLibrary' | |
159 intermediate_builder_name = 'StaticObject' | |
160 target_prefix = '${LIBPREFIX}' | |
161 target_suffix = '${LIBSUFFIX}' | |
162 out_dir = '${LIB_DIR}' | |
163 | |
164 | |
165 class SharedLibraryTarget(CompilableSourcesTargetBase): | |
166 """ | |
167 A GYP target type of 'shared_library'. | |
168 """ | |
169 builder_name = 'GypSharedLibrary' | |
170 intermediate_builder_name = 'SharedObject' | |
171 target_prefix = '${SHLIBPREFIX}' | |
172 target_suffix = '${SHLIBSUFFIX}' | |
173 out_dir = '${LIB_DIR}' | |
174 | |
175 | |
176 class LoadableModuleTarget(CompilableSourcesTargetBase): | |
177 """ | |
178 A GYP target type of 'loadable_module'. | |
179 """ | |
180 builder_name = 'GypLoadableModule' | |
181 intermediate_builder_name = 'SharedObject' | |
182 target_prefix = '${SHLIBPREFIX}' | |
183 target_suffix = '${SHLIBSUFFIX}' | |
184 out_dir = '${TOP_BUILDDIR}' | |
185 | |
186 | |
187 TargetMap = { | |
188 None : NoneTarget, | |
189 'none' : NoneTarget, | |
190 'settings' : SettingsTarget, | |
191 'executable' : ProgramTarget, | |
192 'static_library' : StaticLibraryTarget, | |
193 'shared_library' : SharedLibraryTarget, | |
194 'loadable_module' : LoadableModuleTarget, | |
195 } | |
196 | |
197 | |
198 def Target(spec): | |
199 return TargetMap[spec.get('type')](spec) | |
OLD | NEW |