~hjd/ubuntu/wily/gyp/debian-merged

« back to all changes in this revision

Viewing changes to pylib/gyp/generator/eclipse.py

  • Committer: Hans Joachim Desserud
  • Date: 2015-10-31 12:46:59 UTC
  • mfrom: (6.2.6 sid)
  • Revision ID: hans_joachim_desserud-20151031124659-lzxekr6woskh4k0b
Merge latest Debian version

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import subprocess
23
23
import gyp
24
24
import gyp.common
 
25
import gyp.msvs_emulation
25
26
import shlex
 
27
import xml.etree.cElementTree as ET
26
28
 
27
29
generator_wants_static_library_dependencies_adjusted = False
28
30
 
30
32
}
31
33
 
32
34
for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']:
33
 
  # Some gyp steps fail if these are empty(!).
34
 
  generator_default_variables[dirname] = 'dir'
 
35
  # Some gyp steps fail if these are empty(!), so we convert them to variables
 
36
  generator_default_variables[dirname] = '$' + dirname
35
37
 
36
38
for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
37
39
               'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
52
54
  generator_flags = params.get('generator_flags', {})
53
55
  for key, val in generator_flags.items():
54
56
    default_variables.setdefault(key, val)
55
 
  default_variables.setdefault('OS', gyp.common.GetFlavor(params))
 
57
  flavor = gyp.common.GetFlavor(params)
 
58
  default_variables.setdefault('OS', flavor)
 
59
  if flavor == 'win':
 
60
    # Copy additional generator configuration data from VS, which is shared
 
61
    # by the Eclipse generator.
 
62
    import gyp.generator.msvs as msvs_generator
 
63
    generator_additional_non_configuration_keys = getattr(msvs_generator,
 
64
        'generator_additional_non_configuration_keys', [])
 
65
    generator_additional_path_sections = getattr(msvs_generator,
 
66
        'generator_additional_path_sections', [])
 
67
 
 
68
    gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
56
69
 
57
70
 
58
71
def CalculateGeneratorInputInfo(params):
65
78
 
66
79
 
67
80
def GetAllIncludeDirectories(target_list, target_dicts,
68
 
                             shared_intermediate_dirs, config_name):
 
81
                             shared_intermediate_dirs, config_name, params,
 
82
                             compiler_path):
69
83
  """Calculate the set of include directories to be used.
70
84
 
71
85
  Returns:
76
90
  gyp_includes_set = set()
77
91
  compiler_includes_list = []
78
92
 
 
93
  # Find compiler's default include dirs.
 
94
  if compiler_path:
 
95
    command = shlex.split(compiler_path)
 
96
    command.extend(['-E', '-xc++', '-v', '-'])
 
97
    proc = subprocess.Popen(args=command, stdin=subprocess.PIPE,
 
98
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
99
    output = proc.communicate()[1]
 
100
    # Extract the list of include dirs from the output, which has this format:
 
101
    #   ...
 
102
    #   #include "..." search starts here:
 
103
    #   #include <...> search starts here:
 
104
    #    /usr/include/c++/4.6
 
105
    #    /usr/local/include
 
106
    #   End of search list.
 
107
    #   ...
 
108
    in_include_list = False
 
109
    for line in output.splitlines():
 
110
      if line.startswith('#include'):
 
111
        in_include_list = True
 
112
        continue
 
113
      if line.startswith('End of search list.'):
 
114
        break
 
115
      if in_include_list:
 
116
        include_dir = line.strip()
 
117
        if include_dir not in compiler_includes_list:
 
118
          compiler_includes_list.append(include_dir)
 
119
 
 
120
  flavor = gyp.common.GetFlavor(params)
 
121
  if flavor == 'win':
 
122
    generator_flags = params.get('generator_flags', {})
79
123
  for target_name in target_list:
80
124
    target = target_dicts[target_name]
81
125
    if config_name in target['configurations']:
85
129
      # may be done in gyp files to force certain includes to come at the end.
86
130
      # TODO(jgreenwald): Change the gyp files to not abuse cflags for this, and
87
131
      # remove this.
88
 
      cflags = config['cflags']
 
132
      if flavor == 'win':
 
133
        msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags)
 
134
        cflags = msvs_settings.GetCflags(config_name)
 
135
      else:
 
136
        cflags = config['cflags']
89
137
      for cflag in cflags:
90
 
        include_dir = ''
91
138
        if cflag.startswith('-I'):
92
139
          include_dir = cflag[2:]
93
 
        if include_dir and not include_dir in compiler_includes_list:
94
 
          compiler_includes_list.append(include_dir)
 
140
          if include_dir not in compiler_includes_list:
 
141
            compiler_includes_list.append(include_dir)
95
142
 
96
143
      # Find standard gyp include dirs.
97
144
      if config.has_key('include_dirs'):
106
153
              include_dir = base_dir + '/' + include_dir
107
154
              include_dir = os.path.abspath(include_dir)
108
155
 
109
 
            if not include_dir in gyp_includes_set:
110
 
              gyp_includes_set.add(include_dir)
111
 
 
 
156
            gyp_includes_set.add(include_dir)
112
157
 
113
158
  # Generate a list that has all the include dirs.
114
159
  all_includes_list = list(gyp_includes_set)
121
166
  return all_includes_list
122
167
 
123
168
 
124
 
def GetCompilerPath(target_list, target_dicts, data):
 
169
def GetCompilerPath(target_list, data, options):
125
170
  """Determine a command that can be used to invoke the compiler.
126
171
 
127
172
  Returns:
129
174
    the compiler from that.  Otherwise, see if a compiler was specified via the
130
175
    CC_target environment variable.
131
176
  """
132
 
 
133
177
  # First, see if the compiler is configured in make's settings.
134
178
  build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
135
179
  make_global_settings_dict = data[build_file].get('make_global_settings', {})
136
180
  for key, value in make_global_settings_dict:
137
181
    if key in ['CC', 'CXX']:
138
 
      return value
 
182
      return os.path.join(options.toplevel_dir, value)
139
183
 
140
184
  # Check to see if the compiler was specified as an environment variable.
141
185
  for key in ['CC_target', 'CC', 'CXX']:
146
190
  return 'gcc'
147
191
 
148
192
 
149
 
def GetAllDefines(target_list, target_dicts, data, config_name):
 
193
def GetAllDefines(target_list, target_dicts, data, config_name, params,
 
194
                  compiler_path):
150
195
  """Calculate the defines for a project.
151
196
 
152
197
  Returns:
156
201
 
157
202
  # Get defines declared in the gyp files.
158
203
  all_defines = {}
 
204
  flavor = gyp.common.GetFlavor(params)
 
205
  if flavor == 'win':
 
206
    generator_flags = params.get('generator_flags', {})
159
207
  for target_name in target_list:
160
208
    target = target_dicts[target_name]
161
209
 
 
210
    if flavor == 'win':
 
211
      msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags)
 
212
      extra_defines = msvs_settings.GetComputedDefines(config_name)
 
213
    else:
 
214
      extra_defines = []
162
215
    if config_name in target['configurations']:
163
216
      config = target['configurations'][config_name]
164
 
      for define in config['defines']:
165
 
        split_define = define.split('=', 1)
166
 
        if len(split_define) == 1:
167
 
          split_define.append('1')
168
 
        if split_define[0].strip() in all_defines:
169
 
          # Already defined
170
 
          continue
171
 
 
172
 
        all_defines[split_define[0].strip()] = split_define[1].strip()
173
 
 
 
217
      target_defines = config['defines']
 
218
    else:
 
219
      target_defines = []
 
220
    for define in target_defines + extra_defines:
 
221
      split_define = define.split('=', 1)
 
222
      if len(split_define) == 1:
 
223
        split_define.append('1')
 
224
      if split_define[0].strip() in all_defines:
 
225
        # Already defined
 
226
        continue
 
227
      all_defines[split_define[0].strip()] = split_define[1].strip()
174
228
  # Get default compiler defines (if possible).
175
 
  cc_target = GetCompilerPath(target_list, target_dicts, data)
176
 
  if cc_target:
177
 
    command = shlex.split(cc_target)
 
229
  if flavor == 'win':
 
230
    return all_defines  # Default defines already processed in the loop above.
 
231
  if compiler_path:
 
232
    command = shlex.split(compiler_path)
178
233
    command.extend(['-E', '-dM', '-'])
179
234
    cpp_proc = subprocess.Popen(args=command, cwd='.',
180
235
                                stdin=subprocess.PIPE, stdout=subprocess.PIPE)
240
295
  shared_intermediate_dirs = [os.path.join(toplevel_build, 'obj', 'gen'),
241
296
                              os.path.join(toplevel_build, 'gen')]
242
297
 
243
 
  if not os.path.exists(toplevel_build):
244
 
    os.makedirs(toplevel_build)
245
 
  out = open(os.path.join(toplevel_build, 'eclipse-cdt-settings.xml'), 'w')
246
 
 
247
 
  out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
248
 
  out.write('<cdtprojectproperties>\n')
249
 
 
250
 
  eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File',
251
 
                   'GNU C++', 'GNU C', 'Assembly']
252
 
  include_dirs = GetAllIncludeDirectories(target_list, target_dicts,
253
 
                                          shared_intermediate_dirs, config_name)
254
 
  WriteIncludePaths(out, eclipse_langs, include_dirs)
255
 
  defines = GetAllDefines(target_list, target_dicts, data, config_name)
256
 
  WriteMacros(out, eclipse_langs, defines)
257
 
 
258
 
  out.write('</cdtprojectproperties>\n')
259
 
  out.close()
 
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):
 
318
  gyp.common.EnsureDirExists(out_name)
 
319
  with open(out_name, 'w') as out:
 
320
    out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
 
321
    out.write('<cdtprojectproperties>\n')
 
322
 
 
323
    eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File',
 
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)
 
333
 
 
334
    out.write('</cdtprojectproperties>\n')
 
335
 
 
336
 
 
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, toplevel_dir))
 
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, toplevel_dir):
 
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 or parent_search == toplevel_dir:
 
403
              # Didn't find a known root, just return the original path
 
404
              yield dir_
 
405
              break
 
406
          else:
 
407
            yield parent_search
260
408
 
261
409
 
262
410
def GenerateOutput(target_list, target_dicts, data, params):
263
411
  """Generate an XML settings file that can be imported into a CDT project."""
264
412
 
265
413
  if params['options'].generator_output:
266
 
    raise NotImplementedError, "--generator_output not implemented for eclipse"
 
414
    raise NotImplementedError("--generator_output not implemented for eclipse")
267
415
 
268
416
  user_config = params.get('generator_flags', {}).get('config', None)
269
417
  if user_config: