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

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

Issue 774693004: Add support for generating an Eclipse .classpath file (Closed) Base URL: https://chromium.googlesource.com/external/gyp.git@master
Patch Set: Nico comments Created 6 years 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 """GYP backend that generates Eclipse CDT settings files. 5 """GYP backend that generates Eclipse CDT settings files.
6 6
7 This backend DOES NOT generate Eclipse CDT projects. Instead, it generates XML 7 This backend DOES NOT generate Eclipse CDT projects. Instead, it generates XML
8 files that can be imported into an Eclipse CDT project. The XML file contains a 8 files that can be imported into an Eclipse CDT project. The XML file contains a
9 list of include paths and symbols (i.e. defines). 9 list of include paths and symbols (i.e. defines).
10 10
11 Because a full .cproject definition is not created by this generator, it's not 11 Because a full .cproject definition is not created by this generator, it's not
12 possible to properly define the include dirs and symbols for each file 12 possible to properly define the include dirs and symbols for each file
13 individually. Instead, one set of includes/symbols is generated for the entire 13 individually. Instead, one set of includes/symbols is generated for the entire
14 project. This works fairly well (and is a vast improvement in general), but may 14 project. This works fairly well (and is a vast improvement in general), but may
15 still result in a few indexer issues here and there. 15 still result in a few indexer issues here and there.
16 16
17 This generator has no automated tests, so expect it to be broken. 17 This generator has no automated tests, so expect it to be broken.
18 """ 18 """
19 19
20 from xml.sax.saxutils import escape 20 from xml.sax.saxutils import escape
21 import os.path 21 import os.path
22 import subprocess 22 import subprocess
23 import gyp 23 import gyp
24 import gyp.common 24 import gyp.common
25 import gyp.msvs_emulation 25 import gyp.msvs_emulation
26 import shlex 26 import shlex
27 import xml.etree.cElementTree as ET
27 28
28 generator_wants_static_library_dependencies_adjusted = False 29 generator_wants_static_library_dependencies_adjusted = False
29 30
30 generator_default_variables = { 31 generator_default_variables = {
31 } 32 }
32 33
33 for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']: 34 for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']:
34 # Some gyp steps fail if these are empty(!). 35 # Some gyp steps fail if these are empty(!), so we convert them to variables
35 generator_default_variables[dirname] = 'dir' 36 generator_default_variables[dirname] = '$' + dirname
36 37
37 for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME', 38 for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
38 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT', 39 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
39 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX', 40 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
40 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX', 41 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
41 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX', 42 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
42 'CONFIGURATION_NAME']: 43 'CONFIGURATION_NAME']:
43 generator_default_variables[unused] = '' 44 generator_default_variables[unused] = ''
44 45
45 # Include dirs will occasionally use the SHARED_INTERMEDIATE_DIR variable as 46 # Include dirs will occasionally use the SHARED_INTERMEDIATE_DIR variable as
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 # e.g. "out/Debug" 288 # e.g. "out/Debug"
288 build_dir = os.path.join(generator_flags.get('output_dir', 'out'), 289 build_dir = os.path.join(generator_flags.get('output_dir', 'out'),
289 config_name) 290 config_name)
290 291
291 toplevel_build = os.path.join(options.toplevel_dir, build_dir) 292 toplevel_build = os.path.join(options.toplevel_dir, build_dir)
292 # Ninja uses out/Debug/gen while make uses out/Debug/obj/gen as the 293 # Ninja uses out/Debug/gen while make uses out/Debug/obj/gen as the
293 # SHARED_INTERMEDIATE_DIR. Include both possible locations. 294 # SHARED_INTERMEDIATE_DIR. Include both possible locations.
294 shared_intermediate_dirs = [os.path.join(toplevel_build, 'obj', 'gen'), 295 shared_intermediate_dirs = [os.path.join(toplevel_build, 'obj', 'gen'),
295 os.path.join(toplevel_build, 'gen')] 296 os.path.join(toplevel_build, 'gen')]
296 297
297 out_name = os.path.join(toplevel_build, 'eclipse-cdt-settings.xml') 298 GenerateCdtSettingsFile(target_list,
299 target_dicts,
300 data,
301 params,
302 config_name,
303 os.path.join(toplevel_build,
304 'eclipse-cdt-settings.xml'),
305 options,
306 shared_intermediate_dirs)
307 GenerateClasspathFile(target_list,
308 target_dicts,
309 options.toplevel_dir,
310 toplevel_build,
311 os.path.join(toplevel_build,
312 'eclipse-classpath.xml'))
313
314
315 def GenerateCdtSettingsFile(target_list, target_dicts, data, params,
316 config_name, out_name, options,
317 shared_intermediate_dirs):
298 gyp.common.EnsureDirExists(out_name) 318 gyp.common.EnsureDirExists(out_name)
299 out = open(out_name, 'w') 319 with open(out_name, 'w') as out:
320 out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
321 out.write('<cdtprojectproperties>\n')
300 322
301 out.write('<?xml version="1.0" encoding="UTF-8"?>\n') 323 eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File',
302 out.write('<cdtprojectproperties>\n') 324 'GNU C++', 'GNU C', 'Assembly']
325 compiler_path = GetCompilerPath(target_list, data, options)
326 include_dirs = GetAllIncludeDirectories(target_list, target_dicts,
327 shared_intermediate_dirs,
328 config_name, params, compiler_path)
329 WriteIncludePaths(out, eclipse_langs, include_dirs)
330 defines = GetAllDefines(target_list, target_dicts, data, config_name,
331 params, compiler_path)
332 WriteMacros(out, eclipse_langs, defines)
303 333
304 eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File', 334 out.write('</cdtprojectproperties>\n')
305 'GNU C++', 'GNU C', 'Assembly']
306 compiler_path = GetCompilerPath(target_list, data, options)
307 include_dirs = GetAllIncludeDirectories(target_list, target_dicts,
308 shared_intermediate_dirs, config_name,
309 params, compiler_path)
310 WriteIncludePaths(out, eclipse_langs, include_dirs)
311 defines = GetAllDefines(target_list, target_dicts, data, config_name, params,
312 compiler_path)
313 WriteMacros(out, eclipse_langs, defines)
314 335
315 out.write('</cdtprojectproperties>\n') 336
316 out.close() 337 def GenerateClasspathFile(target_list, target_dicts, toplevel_dir,
338 toplevel_build, out_name):
339 '''Generates a classpath file suitable for symbol navigation and code
340 completion of Java code (such as in Android projects) by finding all
341 .java and .jar files used as action inputs.'''
342 gyp.common.EnsureDirExists(out_name)
343 result = ET.Element('classpath')
344
345 def AddElements(kind, paths):
346 # First, we need to normalize the paths so they are all relative to the
347 # toplevel dir.
348 rel_paths = set()
349 for path in paths:
350 if os.path.isabs(path):
351 rel_paths.add(os.path.relpath(path, toplevel_dir))
352 else:
353 rel_paths.add(path)
354
355 for path in sorted(rel_paths):
356 entry_element = ET.SubElement(result, 'classpathentry')
357 entry_element.set('kind', kind)
358 entry_element.set('path', path)
359
360 AddElements('lib', GetJavaJars(target_list, target_dicts, toplevel_dir))
361 AddElements('src', GetJavaSourceDirs(target_list, target_dicts))
362 # Include the standard JRE container and a dummy out folder
363 AddElements('con', ['org.eclipse.jdt.launching.JRE_CONTAINER'])
364 # Include a dummy out folder so that Eclipse doesn't use the default /bin
365 # folder in the root of the project.
366 AddElements('output', [os.path.join(toplevel_build, '.eclipse-java-build')])
367
368 ET.ElementTree(result).write(out_name)
369
370
371 def GetJavaJars(target_list, target_dicts, toplevel_dir):
372 '''Generates a sequence of all .jars used as inputs.'''
373 for target_name in target_list:
374 target = target_dicts[target_name]
375 for action in target.get('actions', []):
376 for input_ in action['inputs']:
377 if os.path.splitext(input_)[1] == '.jar' and not input_.startswith('$'):
378 if os.path.isabs(input_):
379 yield input_
380 else:
381 yield os.path.join(os.path.dirname(target_name), input_)
382
383
384 def GetJavaSourceDirs(target_list, target_dicts):
385 '''Generates a sequence of all likely java package root directories.'''
386 for target_name in target_list:
387 target = target_dicts[target_name]
388 for action in target.get('actions', []):
389 for input_ in action['inputs']:
390 if (os.path.splitext(input_)[1] == '.java' and
391 not input_.startswith('$')):
392 dir_ = os.path.dirname(os.path.join(os.path.dirname(target_name),
393 input_))
394 # If there is a parent 'src' or 'java' folder, navigate up to it -
395 # these are canonical package root names in Chromium. This will
396 # break if 'src' or 'java' exists in the package structure. This
397 # could be further improved by inspecting the java file for the
398 # package name if this proves to be too fragile in practice.
399 parent_search = dir_
400 while os.path.basename(parent_search) not in ['src', 'java']:
401 parent_search, _ = os.path.split(parent_search)
402 if not parent_search:
403 # Didn't find a known root, just return the original path
404 yield dir_
405 break
406 else:
407 yield parent_search
317 408
318 409
319 def GenerateOutput(target_list, target_dicts, data, params): 410 def GenerateOutput(target_list, target_dicts, data, params):
320 """Generate an XML settings file that can be imported into a CDT project.""" 411 """Generate an XML settings file that can be imported into a CDT project."""
321 412
322 if params['options'].generator_output: 413 if params['options'].generator_output:
323 raise NotImplementedError("--generator_output not implemented for eclipse") 414 raise NotImplementedError("--generator_output not implemented for eclipse")
324 415
325 user_config = params.get('generator_flags', {}).get('config', None) 416 user_config = params.get('generator_flags', {}).get('config', None)
326 if user_config: 417 if user_config:
327 GenerateOutputForConfig(target_list, target_dicts, data, params, 418 GenerateOutputForConfig(target_list, target_dicts, data, params,
328 user_config) 419 user_config)
329 else: 420 else:
330 config_names = target_dicts[target_list[0]]['configurations'].keys() 421 config_names = target_dicts[target_list[0]]['configurations'].keys()
331 for config_name in config_names: 422 for config_name in config_names:
332 GenerateOutputForConfig(target_list, target_dicts, data, params, 423 GenerateOutputForConfig(target_list, target_dicts, data, params,
333 config_name) 424 config_name)
334 425
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698