Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(327)

Side by Side Diff: pylib/gyp/generator/ninja.py

Issue 11659002: Teach ninja to handle output directories outside the source dir. (Closed) Base URL: http://gyp.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright (c) 2012 Google Inc. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import copy 5 import copy
6 import hashlib 6 import hashlib
7 import multiprocessing 7 import multiprocessing
8 import os.path 8 import os.path
9 import re 9 import re
10 import signal 10 import signal
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 def Define(d, flavor): 90 def Define(d, flavor):
91 """Takes a preprocessor define and returns a -D parameter that's ninja- and 91 """Takes a preprocessor define and returns a -D parameter that's ninja- and
92 shell-escaped.""" 92 shell-escaped."""
93 if flavor == 'win': 93 if flavor == 'win':
94 # cl.exe replaces literal # characters with = in preprocesor definitions for 94 # cl.exe replaces literal # characters with = in preprocesor definitions for
95 # some reason. Octal-encode to work around that. 95 # some reason. Octal-encode to work around that.
96 d = d.replace('#', '\\%03o' % ord('#')) 96 d = d.replace('#', '\\%03o' % ord('#'))
97 return QuoteShellArgument(ninja_syntax.escape('-D' + d), flavor) 97 return QuoteShellArgument(ninja_syntax.escape('-D' + d), flavor)
98 98
99 99
100 def InvertRelativePath(path):
101 """Given a relative path like foo/bar, return the inverse relative path:
102 the path from the relative path back to the origin dir.
103
104 E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
105 should always produce the empty string."""
106
107 if not path:
108 return path
109 # Only need to handle relative paths into subdirectories for now.
110 assert '..' not in path, path
111 depth = len(path.split(os.path.sep))
112 return os.path.sep.join(['..'] * depth)
113
114
115 class Target: 100 class Target:
116 """Target represents the paths used within a single gyp target. 101 """Target represents the paths used within a single gyp target.
117 102
118 Conceptually, building a single target A is a series of steps: 103 Conceptually, building a single target A is a series of steps:
119 104
120 1) actions/rules/copies generates source/resources/etc. 105 1) actions/rules/copies generates source/resources/etc.
121 2) compiles generates .o files 106 2) compiles generates .o files
122 3) link generates a binary (library/executable) 107 3) link generates a binary (library/executable)
123 4) bundle merges the above in a mac bundle 108 4) bundle merges the above in a mac bundle
124 109
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 # 196 #
212 # - GypPathToNinja translates a gyp path (i.e. relative to the .gyp file) 197 # - GypPathToNinja translates a gyp path (i.e. relative to the .gyp file)
213 # into the equivalent ninja path. 198 # into the equivalent ninja path.
214 # 199 #
215 # - GypPathToUniqueOutput translates a gyp path into a ninja path to write 200 # - GypPathToUniqueOutput translates a gyp path into a ninja path to write
216 # an output file; the result can be namespaced such that it is unique 201 # an output file; the result can be namespaced such that it is unique
217 # to the input file name as well as the output target name. 202 # to the input file name as well as the output target name.
218 203
219 class NinjaWriter: 204 class NinjaWriter:
220 def __init__(self, qualified_target, target_outputs, base_dir, build_dir, 205 def __init__(self, qualified_target, target_outputs, base_dir, build_dir,
221 output_file, flavor, abs_build_dir=None): 206 output_file, flavor, toplevel_dir=None):
222 """ 207 """
223 base_dir: path from source root to directory containing this gyp file, 208 base_dir: path from source root to directory containing this gyp file,
224 by gyp semantics, all input paths are relative to this 209 by gyp semantics, all input paths are relative to this
225 build_dir: path from source root to build output 210 build_dir: path from source root to build output
226 abs_build_dir: absolute path to the build directory 211 toplevel_dir: path to the toplevel directory
227 """ 212 """
228 213
229 self.qualified_target = qualified_target 214 self.qualified_target = qualified_target
230 self.target_outputs = target_outputs 215 self.target_outputs = target_outputs
231 self.base_dir = base_dir 216 self.base_dir = base_dir
232 self.build_dir = build_dir 217 self.build_dir = build_dir
233 self.ninja = ninja_syntax.Writer(output_file) 218 self.ninja = ninja_syntax.Writer(output_file)
234 self.flavor = flavor 219 self.flavor = flavor
235 self.abs_build_dir = abs_build_dir 220 self.abs_build_dir = None
221 if toplevel_dir is not None:
222 self.abs_build_dir = os.path.abspath(os.path.join(toplevel_dir,
223 build_dir))
236 self.obj_ext = '.obj' if flavor == 'win' else '.o' 224 self.obj_ext = '.obj' if flavor == 'win' else '.o'
237 if flavor == 'win': 225 if flavor == 'win':
238 # See docstring of msvs_emulation.GenerateEnvironmentFiles(). 226 # See docstring of msvs_emulation.GenerateEnvironmentFiles().
239 self.win_env = {} 227 self.win_env = {}
240 for arch in ('x86', 'x64'): 228 for arch in ('x86', 'x64'):
241 self.win_env[arch] = 'environment.' + arch 229 self.win_env[arch] = 'environment.' + arch
242 230
243 # Relative path from build output dir to base dir. 231 # Relative path from build output dir to base dir.
244 self.build_to_base = os.path.join(InvertRelativePath(build_dir), base_dir) 232 build_to_top = gyp.common.InvertRelativePath(build_dir, toplevel_dir)
233 self.build_to_base = os.path.join(build_to_top, base_dir)
245 # Relative path from base dir to build dir. 234 # Relative path from base dir to build dir.
246 self.base_to_build = os.path.join(InvertRelativePath(base_dir), build_dir) 235 base_to_top = gyp.common.InvertRelativePath(base_dir, toplevel_dir)
236 self.base_to_build = os.path.join(base_to_top, build_dir)
247 237
248 def ExpandSpecial(self, path, product_dir=None): 238 def ExpandSpecial(self, path, product_dir=None):
249 """Expand specials like $!PRODUCT_DIR in |path|. 239 """Expand specials like $!PRODUCT_DIR in |path|.
250 240
251 If |product_dir| is None, assumes the cwd is already the product 241 If |product_dir| is None, assumes the cwd is already the product
252 dir. Otherwise, |product_dir| is the relative path to the product 242 dir. Otherwise, |product_dir| is the relative path to the product
253 dir. 243 dir.
254 """ 244 """
255 245
256 PRODUCT_DIR = '$!PRODUCT_DIR' 246 PRODUCT_DIR = '$!PRODUCT_DIR'
(...skipping 1108 matching lines...) Expand 10 before | Expand all | Expand 10 after
1365 ld = '$cxx' 1355 ld = '$cxx'
1366 ld_host = '$cxx_host' 1356 ld_host = '$cxx_host'
1367 1357
1368 cc_host = None 1358 cc_host = None
1369 cxx_host = None 1359 cxx_host = None
1370 cc_host_global_setting = None 1360 cc_host_global_setting = None
1371 cxx_host_global_setting = None 1361 cxx_host_global_setting = None
1372 1362
1373 build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) 1363 build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
1374 make_global_settings = data[build_file].get('make_global_settings', []) 1364 make_global_settings = data[build_file].get('make_global_settings', [])
1375 build_to_root = InvertRelativePath(build_dir) 1365 build_to_root = gyp.common.InvertRelativePath(build_dir,
1366 options.toplevel_dir)
1376 for key, value in make_global_settings: 1367 for key, value in make_global_settings:
1377 if key == 'CC': 1368 if key == 'CC':
1378 cc = os.path.join(build_to_root, value) 1369 cc = os.path.join(build_to_root, value)
1379 if key == 'CXX': 1370 if key == 'CXX':
1380 cxx = os.path.join(build_to_root, value) 1371 cxx = os.path.join(build_to_root, value)
1381 if key == 'LD': 1372 if key == 'LD':
1382 ld = os.path.join(build_to_root, value) 1373 ld = os.path.join(build_to_root, value)
1383 if key == 'CC.host': 1374 if key == 'CC.host':
1384 cc_host = os.path.join(build_to_root, value) 1375 cc_host = os.path.join(build_to_root, value)
1385 cc_host_global_setting = value 1376 cc_host_global_setting = value
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after
1722 1713
1723 base_path = os.path.dirname(build_file) 1714 base_path = os.path.dirname(build_file)
1724 obj = 'obj' 1715 obj = 'obj'
1725 if toolset != 'target': 1716 if toolset != 'target':
1726 obj += '.' + toolset 1717 obj += '.' + toolset
1727 output_file = os.path.join(obj, base_path, name + '.ninja') 1718 output_file = os.path.join(obj, base_path, name + '.ninja')
1728 1719
1729 abs_build_dir = os.path.abspath(toplevel_build) 1720 abs_build_dir = os.path.abspath(toplevel_build)
1730 writer = NinjaWriter(qualified_target, target_outputs, base_path, build_dir, 1721 writer = NinjaWriter(qualified_target, target_outputs, base_path, build_dir,
1731 OpenOutput(os.path.join(toplevel_build, output_file)), 1722 OpenOutput(os.path.join(toplevel_build, output_file)),
1732 flavor, abs_build_dir=abs_build_dir) 1723 flavor, toplevel_dir=options.toplevel_dir)
1733 master_ninja.subninja(output_file) 1724 master_ninja.subninja(output_file)
1734 1725
1735 target = writer.WriteSpec( 1726 target = writer.WriteSpec(
1736 spec, config_name, generator_flags, case_sensitive_filesystem) 1727 spec, config_name, generator_flags, case_sensitive_filesystem)
1737 if target: 1728 if target:
1738 if name != target.FinalOutput() and spec['toolset'] == 'target': 1729 if name != target.FinalOutput() and spec['toolset'] == 'target':
1739 target_short_names.setdefault(name, []).append(target) 1730 target_short_names.setdefault(name, []).append(target)
1740 target_outputs[qualified_target] = target 1731 target_outputs[qualified_target] = target
1741 if qualified_target in all_targets: 1732 if qualified_target in all_targets:
1742 all_outputs.add(target.FinalOutput()) 1733 all_outputs.add(target.FinalOutput())
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1790 arglists.append( 1781 arglists.append(
1791 (target_list, target_dicts, data, params, config_name)) 1782 (target_list, target_dicts, data, params, config_name))
1792 pool.map(CallGenerateOutputForConfig, arglists) 1783 pool.map(CallGenerateOutputForConfig, arglists)
1793 except KeyboardInterrupt, e: 1784 except KeyboardInterrupt, e:
1794 pool.terminate() 1785 pool.terminate()
1795 raise e 1786 raise e
1796 else: 1787 else:
1797 for config_name in config_names: 1788 for config_name in config_names:
1798 GenerateOutputForConfig(target_list, target_dicts, data, params, 1789 GenerateOutputForConfig(target_list, target_dicts, data, params,
1799 config_name) 1790 config_name)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698