1# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights 2# reserved. Use of this source code is governed by a BSD-style license that 3# can be found in the LICENSE file. 4 5from __future__ import absolute_import 6import os 7from file_util import * 8import sys 9 10# script directory. 11script_dir = os.path.dirname(__file__) 12 13# CEF root directory. 14cef_dir = os.path.abspath(os.path.join(script_dir, os.pardir)) 15 16 17def get_files_for_variable(cmake_path, variables, variable): 18 """ Returns the path values associated with |variable| and relative to the 19 |cmake_path| directory. """ 20 if not variable in variables: 21 raise Exception('Variable %s does not exist' % variable) 22 23 # Cmake file directory. 24 cmake_dirname = os.path.dirname(cmake_path) + '/' 25 26 # Return path values relative to the cmake file directory. 27 # Example 1: 28 # cmake file = "/path/to/libcef_dll/CMakeLists.txt" 29 # include path = "/path/to/libcef_dll/wrapper/cef_browser_info_map.h" 30 # return path = "wrapper/cef_browser_info_map.h" 31 # Example 2: 32 # cmake file = "/path/to/libcef_dll/CMakeLists.txt" 33 # include path = "/path/to/include/internal/cef_export.h" 34 # return path = "../include/internal/cef_export.h" 35 new_paths = [] 36 paths = variables[variable] 37 for path in paths: 38 abspath = os.path.join(cef_dir, path) 39 newpath = normalize_path(os.path.relpath(abspath, cmake_dirname)) 40 new_paths.append(newpath) 41 return new_paths 42 43 44def format_cmake_set(name, values): 45 result = 'set(%s\n' % name 46 for value in values: 47 result += ' %s\n' % value 48 return result + ' )\n' 49 50 51def format_cmake_group(cmake_path, name, files, platform_sep, append_macro): 52 platforms = {} 53 common = [] 54 55 # Folder will be the cmake parent directory name combined with the path to 56 # first file in the files list. 57 # Example 1: 58 # cmake file = "/path/to/libcef_dll/CMakeLists.txt" 59 # include path = "wrapper/cef_browser_info_map.h" 60 # folder = "libcef_dll\\\\wrapper" 61 # Example 2: 62 # cmake file = "/path/to/libcef_dll/CMakeLists.txt" 63 # include path = "../include/internal/cef_export.h" 64 # folder = "include\\\\internal" 65 folder = os.path.basename(os.path.dirname(cmake_path)) 66 folder = os.path.dirname(os.path.normpath(os.path.join(folder, files[0]))) 67 folder = normalize_path(folder).replace('/', '\\\\\\\\') 68 69 # Group the files by platform. 70 for file in files: 71 parts = file.split(platform_sep) 72 file = parts[0] 73 if len(parts) > 1: 74 # Add the file under the platform. 75 platform = parts[1] 76 if not platform in platforms: 77 platforms[platform] = [] 78 platforms[platform].append(file) 79 else: 80 common.append(file) 81 82 result = '' 83 if len(common) > 0: 84 result += format_cmake_set(name, common) 85 86 if len(platforms) > 0: 87 keys = sorted(platforms.keys()) 88 for key in keys: 89 result += format_cmake_set(name + '_' + key, platforms[key]) 90 result += '%s(%s)\n' % (append_macro, name) 91 92 result += 'source_group(%s FILES ${%s})\n\n' % (folder, name) 93 return result 94 95 96def format_cmake_library(name, group_names): 97 result = 'add_library(%s\n' % name 98 for group in group_names: 99 result += ' ${%s}\n' % group 100 return result + ' )\n\n' 101 102 103def process_cmake_template_segment(segment, segment_ct, cmake_path, variables): 104 prefix = None 105 library = None 106 set = None 107 includes = [] 108 suffix = '_SRCS' # Appended to each group name before the platform name. 109 platform_sep = ':' # Used to separate value from platform name. 110 append_macro = 'APPEND_PLATFORM_SOURCES' # CMake macro name. 111 112 # Extract values from |segment|. Example |segment| contents: 113 # 'prefix': 'cefsimple', 114 # 'includes': [ 115 # 'cefsimple_sources_common', 116 # 'cefsimple_sources_win:WINDOWS', 117 # 'cefsimple_sources_mac:MAC', 118 # 'cefsimple_sources_linux:LINUX', 119 # ], 120 values = eval('{' + segment + '}', {'__builtins__': None}, None) 121 if 'prefix' in values: 122 prefix = values['prefix'] 123 else: 124 raise Exception('Missing prefix value in segment %d' % segment_ct) 125 126 if 'library' in values: 127 library = values['library'] 128 129 if 'set' in values: 130 set = values['set'] 131 132 if 'append_macro' in values: 133 append_macro = values['append_macro'] 134 135 if 'includes' in values and len(values['includes']) > 0: 136 for include in values['includes']: 137 parts = include.strip().split(platform_sep) 138 files = get_files_for_variable(cmake_path, variables, parts[0]) 139 if len(parts) == 2: 140 # Append the platform to each file path. 141 files = [file + platform_sep + parts[1] for file in files] 142 includes.extend(files) 143 else: 144 raise Exception('Missing includes value in segment %d' % segment_ct) 145 146 # Sort the file paths alphabetically. 147 includes.sort() 148 149 # Group files by path. 150 # For example, '../include/base/foo.h' and '../include/base/bar.h' will be 151 # grouped as 'PREFIX_INCLUDE_BASE'. 152 groups = {} 153 for include in includes: 154 paths = include.split('/') 155 label = prefix 156 for path in paths[0:-1]: 157 if path == '..': 158 continue 159 label += '_' + path 160 label = label.replace('.', '_').upper() 161 if not label in groups: 162 groups[label] = [] 163 groups[label].append(include) 164 165 # Create the output results. 166 result = '' 167 168 keys = sorted(groups.keys()) 169 for key in keys: 170 # Add a group of files that share the same path. 171 result += format_cmake_group(cmake_path, key + suffix, groups[key], \ 172 platform_sep, append_macro) 173 174 if not library is None: 175 # Add the library declaration if requested. 176 result += format_cmake_library(library, [key + suffix for key in keys]) 177 178 if not set is None: 179 # Add the set declaration if requested. 180 result += format_cmake_set(set, \ 181 ['${' + key + suffix + '}' for key in keys]) 182 183 return result.strip() 184 185 186def process_cmake_template(input, output, variables, quiet=False): 187 """ Reads the |input| template, parses variable substitution sections and 188 writes |output|. """ 189 if not quiet: 190 sys.stdout.write('Processing "%s" to "%s"...\n' % (input, output)) 191 192 if not os.path.exists(input): 193 raise Exception('File %s does not exist' % input) 194 195 cmake_path = normalize_path(os.path.abspath(input)) 196 template = read_file(cmake_path) 197 198 delim_start = '{{' 199 delim_end = '}}' 200 201 # Process the template file, replacing segments delimited by |delim_start| 202 # and |delim_end|. 203 result = '' 204 end = 0 205 segment_ct = 0 206 while True: 207 start = template.find(delim_start, end) 208 if start == -1: 209 break 210 result += template[end:start] 211 end = template.find(delim_end, start + len(delim_start)) 212 if end == -1: 213 break 214 segment = template[start + len(delim_start):end] 215 segment_ct = segment_ct + 1 216 result += process_cmake_template_segment(segment, segment_ct, \ 217 cmake_path, variables) 218 end += len(delim_end) 219 result += template[end:] 220 221 # Only write the output file if the contents have changed. 222 changed = True 223 if os.path.exists(output): 224 existing = read_file(output) 225 changed = result != existing 226 if changed: 227 write_file(output, result) 228 229 230def read_gypi_variables(source): 231 """ Read the |source| gypi file and extract the variables section. """ 232 path = os.path.join(cef_dir, source + '.gypi') 233 if not os.path.exists(path): 234 raise Exception('File %s does not exist' % path) 235 contents = eval_file(path) 236 if not 'variables' in contents: 237 raise Exception('File %s does not have a variables section' % path) 238 return contents['variables'] 239 240 241# File entry point. 242if __name__ == "__main__": 243 # Verify that the correct number of command-line arguments are provided. 244 if len(sys.argv) != 3: 245 sys.stderr.write('Usage: ' + sys.argv[0] + ' <infile> <outfile>') 246 sys.exit() 247 248 # Read the gypi files and combine into a single dictionary. 249 variables1 = read_gypi_variables('cef_paths') 250 variables2 = read_gypi_variables('cef_paths2') 251 variables = dict(variables1.items() + variables2.items()) 252 253 # Process the cmake template. 254 process_cmake_template(sys.argv[1], sys.argv[2], variables) 255