• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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