| OLD | NEW |
| 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 shlex | 26 import shlex |
| 26 | 27 |
| 27 generator_wants_static_library_dependencies_adjusted = False | 28 generator_wants_static_library_dependencies_adjusted = False |
| 28 | 29 |
| 29 generator_default_variables = { | 30 generator_default_variables = { |
| 30 } | 31 } |
| 31 | 32 |
| 32 for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']: | 33 for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']: |
| 33 # Some gyp steps fail if these are empty(!). | 34 # Some gyp steps fail if these are empty(!). |
| 34 generator_default_variables[dirname] = 'dir' | 35 generator_default_variables[dirname] = 'dir' |
| (...skipping 10 matching lines...) Expand all Loading... |
| 45 # part of the path when dealing with generated headers. This value will be | 46 # part of the path when dealing with generated headers. This value will be |
| 46 # replaced dynamically for each configuration. | 47 # replaced dynamically for each configuration. |
| 47 generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \ | 48 generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \ |
| 48 '$SHARED_INTERMEDIATE_DIR' | 49 '$SHARED_INTERMEDIATE_DIR' |
| 49 | 50 |
| 50 | 51 |
| 51 def CalculateVariables(default_variables, params): | 52 def CalculateVariables(default_variables, params): |
| 52 generator_flags = params.get('generator_flags', {}) | 53 generator_flags = params.get('generator_flags', {}) |
| 53 for key, val in generator_flags.items(): | 54 for key, val in generator_flags.items(): |
| 54 default_variables.setdefault(key, val) | 55 default_variables.setdefault(key, val) |
| 55 default_variables.setdefault('OS', gyp.common.GetFlavor(params)) | 56 flavor = gyp.common.GetFlavor(params) |
| 57 default_variables.setdefault('OS', flavor) |
| 58 if flavor == 'win': |
| 59 # Copy additional generator configuration data from VS, which is shared |
| 60 # by the Eclipse generator. |
| 61 import gyp.generator.msvs as msvs_generator |
| 62 generator_additional_non_configuration_keys = getattr(msvs_generator, |
| 63 'generator_additional_non_configuration_keys', []) |
| 64 generator_additional_path_sections = getattr(msvs_generator, |
| 65 'generator_additional_path_sections', []) |
| 66 |
| 67 # Set a variable so conditions can be based on msvs_version. |
| 68 msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags) |
| 69 default_variables['MSVS_VERSION'] = msvs_version.ShortName() |
| 70 |
| 71 # To determine processor word size on Windows, in addition to checking |
| 72 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current |
| 73 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which |
| 74 # contains the actual word size of the system when running thru WOW64). |
| 75 if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or |
| 76 '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')): |
| 77 default_variables['MSVS_OS_BITS'] = 64 |
| 78 else: |
| 79 default_variables['MSVS_OS_BITS'] = 32 |
| 56 | 80 |
| 57 | 81 |
| 58 def CalculateGeneratorInputInfo(params): | 82 def CalculateGeneratorInputInfo(params): |
| 59 """Calculate the generator specific info that gets fed to input (called by | 83 """Calculate the generator specific info that gets fed to input (called by |
| 60 gyp).""" | 84 gyp).""" |
| 61 generator_flags = params.get('generator_flags', {}) | 85 generator_flags = params.get('generator_flags', {}) |
| 62 if generator_flags.get('adjust_static_libraries', False): | 86 if generator_flags.get('adjust_static_libraries', False): |
| 63 global generator_wants_static_library_dependencies_adjusted | 87 global generator_wants_static_library_dependencies_adjusted |
| 64 generator_wants_static_library_dependencies_adjusted = True | 88 generator_wants_static_library_dependencies_adjusted = True |
| 65 | 89 |
| 66 | 90 |
| 67 def GetAllIncludeDirectories(target_list, target_dicts, | 91 def GetAllIncludeDirectories(target_list, target_dicts, |
| 68 shared_intermediate_dirs, config_name): | 92 shared_intermediate_dirs, config_name, params): |
| 69 """Calculate the set of include directories to be used. | 93 """Calculate the set of include directories to be used. |
| 70 | 94 |
| 71 Returns: | 95 Returns: |
| 72 A list including all the include_dir's specified for every target followed | 96 A list including all the include_dir's specified for every target followed |
| 73 by any include directories that were added as cflag compiler options. | 97 by any include directories that were added as cflag compiler options. |
| 74 """ | 98 """ |
| 75 | 99 |
| 76 gyp_includes_set = set() | 100 gyp_includes_set = set() |
| 77 compiler_includes_list = [] | 101 compiler_includes_list = [] |
| 78 | 102 |
| 103 flavor = gyp.common.GetFlavor(params) |
| 104 if flavor == 'win': |
| 105 generator_flags = params.get('generator_flags', {}) |
| 79 for target_name in target_list: | 106 for target_name in target_list: |
| 80 target = target_dicts[target_name] | 107 target = target_dicts[target_name] |
| 81 if config_name in target['configurations']: | 108 if config_name in target['configurations']: |
| 82 config = target['configurations'][config_name] | 109 config = target['configurations'][config_name] |
| 83 | 110 |
| 84 # Look for any include dirs that were explicitly added via cflags. This | 111 # Look for any include dirs that were explicitly added via cflags. This |
| 85 # may be done in gyp files to force certain includes to come at the end. | 112 # may be done in gyp files to force certain includes to come at the end. |
| 86 # TODO(jgreenwald): Change the gyp files to not abuse cflags for this, and | 113 # TODO(jgreenwald): Change the gyp files to not abuse cflags for this, and |
| 87 # remove this. | 114 # remove this. |
| 88 cflags = config['cflags'] | 115 if flavor == 'win': |
| 116 msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags) |
| 117 cflags = msvs_settings.GetCflags(config_name) |
| 118 else: |
| 119 cflags = config['cflags'] |
| 89 for cflag in cflags: | 120 for cflag in cflags: |
| 90 include_dir = '' | 121 include_dir = '' |
| 91 if cflag.startswith('-I'): | 122 if cflag.startswith('-I'): |
| 92 include_dir = cflag[2:] | 123 include_dir = cflag[2:] |
| 93 if include_dir and not include_dir in compiler_includes_list: | 124 if include_dir and not include_dir in compiler_includes_list: |
| 94 compiler_includes_list.append(include_dir) | 125 compiler_includes_list.append(include_dir) |
| 95 | 126 |
| 96 # Find standard gyp include dirs. | 127 # Find standard gyp include dirs. |
| 97 if config.has_key('include_dirs'): | 128 if config.has_key('include_dirs'): |
| 98 include_dirs = config['include_dirs'] | 129 include_dirs = config['include_dirs'] |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 | 170 |
| 140 # Check to see if the compiler was specified as an environment variable. | 171 # Check to see if the compiler was specified as an environment variable. |
| 141 for key in ['CC_target', 'CC', 'CXX']: | 172 for key in ['CC_target', 'CC', 'CXX']: |
| 142 compiler = os.environ.get(key) | 173 compiler = os.environ.get(key) |
| 143 if compiler: | 174 if compiler: |
| 144 return compiler | 175 return compiler |
| 145 | 176 |
| 146 return 'gcc' | 177 return 'gcc' |
| 147 | 178 |
| 148 | 179 |
| 149 def GetAllDefines(target_list, target_dicts, data, config_name): | 180 def GetAllDefines(target_list, target_dicts, data, config_name, params): |
| 150 """Calculate the defines for a project. | 181 """Calculate the defines for a project. |
| 151 | 182 |
| 152 Returns: | 183 Returns: |
| 153 A dict that includes explict defines declared in gyp files along with all of | 184 A dict that includes explict defines declared in gyp files along with all of |
| 154 the default defines that the compiler uses. | 185 the default defines that the compiler uses. |
| 155 """ | 186 """ |
| 156 | 187 |
| 157 # Get defines declared in the gyp files. | 188 # Get defines declared in the gyp files. |
| 158 all_defines = {} | 189 all_defines = {} |
| 190 flavor = gyp.common.GetFlavor(params) |
| 191 if flavor == 'win': |
| 192 generator_flags = params.get('generator_flags', {}) |
| 159 for target_name in target_list: | 193 for target_name in target_list: |
| 160 target = target_dicts[target_name] | 194 target = target_dicts[target_name] |
| 161 | 195 |
| 196 if flavor == 'win': |
| 197 msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags) |
| 198 extra_defines = msvs_settings.GetComputedDefines(config_name) |
| 199 else: |
| 200 extra_defines = [] |
| 162 if config_name in target['configurations']: | 201 if config_name in target['configurations']: |
| 163 config = target['configurations'][config_name] | 202 config = target['configurations'][config_name] |
| 164 for define in config['defines']: | 203 target_defines = config['defines'] |
| 165 split_define = define.split('=', 1) | 204 else: |
| 166 if len(split_define) == 1: | 205 target_defines = [] |
| 167 split_define.append('1') | 206 for define in target_defines + extra_defines: |
| 168 if split_define[0].strip() in all_defines: | 207 split_define = define.split('=', 1) |
| 169 # Already defined | 208 if len(split_define) == 1: |
| 170 continue | 209 split_define.append('1') |
| 171 | 210 if split_define[0].strip() in all_defines: |
| 172 all_defines[split_define[0].strip()] = split_define[1].strip() | 211 # Already defined |
| 173 | 212 continue |
| 213 all_defines[split_define[0].strip()] = split_define[1].strip() |
| 174 # Get default compiler defines (if possible). | 214 # Get default compiler defines (if possible). |
| 215 if flavor == 'win': |
| 216 return all_defines # Default defines already processed in the loop above. |
| 175 cc_target = GetCompilerPath(target_list, target_dicts, data) | 217 cc_target = GetCompilerPath(target_list, target_dicts, data) |
| 176 if cc_target: | 218 if cc_target: |
| 177 command = shlex.split(cc_target) | 219 command = shlex.split(cc_target) |
| 178 command.extend(['-E', '-dM', '-']) | 220 command.extend(['-E', '-dM', '-']) |
| 179 cpp_proc = subprocess.Popen(args=command, cwd='.', | 221 cpp_proc = subprocess.Popen(args=command, cwd='.', |
| 180 stdin=subprocess.PIPE, stdout=subprocess.PIPE) | 222 stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
| 181 cpp_output = cpp_proc.communicate()[0] | 223 cpp_output = cpp_proc.communicate()[0] |
| 182 cpp_lines = cpp_output.split('\n') | 224 cpp_lines = cpp_output.split('\n') |
| 183 for cpp_line in cpp_lines: | 225 for cpp_line in cpp_lines: |
| 184 if not cpp_line.strip(): | 226 if not cpp_line.strip(): |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 if not os.path.exists(toplevel_build): | 285 if not os.path.exists(toplevel_build): |
| 244 os.makedirs(toplevel_build) | 286 os.makedirs(toplevel_build) |
| 245 out = open(os.path.join(toplevel_build, 'eclipse-cdt-settings.xml'), 'w') | 287 out = open(os.path.join(toplevel_build, 'eclipse-cdt-settings.xml'), 'w') |
| 246 | 288 |
| 247 out.write('<?xml version="1.0" encoding="UTF-8"?>\n') | 289 out.write('<?xml version="1.0" encoding="UTF-8"?>\n') |
| 248 out.write('<cdtprojectproperties>\n') | 290 out.write('<cdtprojectproperties>\n') |
| 249 | 291 |
| 250 eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File', | 292 eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File', |
| 251 'GNU C++', 'GNU C', 'Assembly'] | 293 'GNU C++', 'GNU C', 'Assembly'] |
| 252 include_dirs = GetAllIncludeDirectories(target_list, target_dicts, | 294 include_dirs = GetAllIncludeDirectories(target_list, target_dicts, |
| 253 shared_intermediate_dirs, config_name) | 295 shared_intermediate_dirs, config_name, |
| 296 params) |
| 254 WriteIncludePaths(out, eclipse_langs, include_dirs) | 297 WriteIncludePaths(out, eclipse_langs, include_dirs) |
| 255 defines = GetAllDefines(target_list, target_dicts, data, config_name) | 298 defines = GetAllDefines(target_list, target_dicts, data, config_name, params) |
| 256 WriteMacros(out, eclipse_langs, defines) | 299 WriteMacros(out, eclipse_langs, defines) |
| 257 | 300 |
| 258 out.write('</cdtprojectproperties>\n') | 301 out.write('</cdtprojectproperties>\n') |
| 259 out.close() | 302 out.close() |
| 260 | 303 |
| 261 | 304 |
| 262 def GenerateOutput(target_list, target_dicts, data, params): | 305 def GenerateOutput(target_list, target_dicts, data, params): |
| 263 """Generate an XML settings file that can be imported into a CDT project.""" | 306 """Generate an XML settings file that can be imported into a CDT project.""" |
| 264 | 307 |
| 265 if params['options'].generator_output: | 308 if params['options'].generator_output: |
| 266 raise NotImplementedError, "--generator_output not implemented for eclipse" | 309 raise NotImplementedError, "--generator_output not implemented for eclipse" |
| 267 | 310 |
| 268 user_config = params.get('generator_flags', {}).get('config', None) | 311 user_config = params.get('generator_flags', {}).get('config', None) |
| 269 if user_config: | 312 if user_config: |
| 270 GenerateOutputForConfig(target_list, target_dicts, data, params, | 313 GenerateOutputForConfig(target_list, target_dicts, data, params, |
| 271 user_config) | 314 user_config) |
| 272 else: | 315 else: |
| 273 config_names = target_dicts[target_list[0]]['configurations'].keys() | 316 config_names = target_dicts[target_list[0]]['configurations'].keys() |
| 274 for config_name in config_names: | 317 for config_name in config_names: |
| 275 GenerateOutputForConfig(target_list, target_dicts, data, params, | 318 GenerateOutputForConfig(target_list, target_dicts, data, params, |
| 276 config_name) | 319 config_name) |
| 277 | 320 |
| OLD | NEW |