redsnow 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +20 -0
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +21 -0
  8. data/README.md +62 -0
  9. data/Rakefile +36 -0
  10. data/Vagrantfile +20 -0
  11. data/ext/snowcrash/Makefile +64 -0
  12. data/ext/snowcrash/Vagrantfile +20 -0
  13. data/ext/snowcrash/bin/snowcrash +0 -0
  14. data/ext/snowcrash/common.gypi +163 -0
  15. data/ext/snowcrash/config.gypi +10 -0
  16. data/ext/snowcrash/config.mk +5 -0
  17. data/ext/snowcrash/configure +213 -0
  18. data/ext/snowcrash/provisioning.sh +15 -0
  19. data/ext/snowcrash/snowcrash.gyp +141 -0
  20. data/ext/snowcrash/src/ActionParser.h +503 -0
  21. data/ext/snowcrash/src/AssetParser.h +215 -0
  22. data/ext/snowcrash/src/BlockUtility.h +186 -0
  23. data/ext/snowcrash/src/Blueprint.h +283 -0
  24. data/ext/snowcrash/src/BlueprintParser.h +347 -0
  25. data/ext/snowcrash/src/BlueprintParserCore.h +190 -0
  26. data/ext/snowcrash/src/BlueprintSection.h +140 -0
  27. data/ext/snowcrash/src/BlueprintUtility.h +126 -0
  28. data/ext/snowcrash/src/CBlueprint.cc +600 -0
  29. data/ext/snowcrash/src/CBlueprint.h +354 -0
  30. data/ext/snowcrash/src/CSourceAnnotation.cc +140 -0
  31. data/ext/snowcrash/src/CSourceAnnotation.h +106 -0
  32. data/ext/snowcrash/src/CodeBlockUtility.h +189 -0
  33. data/ext/snowcrash/src/DescriptionSectionUtility.h +156 -0
  34. data/ext/snowcrash/src/HTTP.cc +46 -0
  35. data/ext/snowcrash/src/HTTP.h +105 -0
  36. data/ext/snowcrash/src/HeaderParser.h +289 -0
  37. data/ext/snowcrash/src/ListBlockUtility.h +273 -0
  38. data/ext/snowcrash/src/ListUtility.h +95 -0
  39. data/ext/snowcrash/src/MarkdownBlock.cc +176 -0
  40. data/ext/snowcrash/src/MarkdownBlock.h +93 -0
  41. data/ext/snowcrash/src/MarkdownParser.cc +266 -0
  42. data/ext/snowcrash/src/MarkdownParser.h +88 -0
  43. data/ext/snowcrash/src/ParameterDefinitonParser.h +570 -0
  44. data/ext/snowcrash/src/ParametersParser.h +252 -0
  45. data/ext/snowcrash/src/Parser.cc +71 -0
  46. data/ext/snowcrash/src/Parser.h +29 -0
  47. data/ext/snowcrash/src/ParserCore.cc +120 -0
  48. data/ext/snowcrash/src/ParserCore.h +82 -0
  49. data/ext/snowcrash/src/PayloadParser.h +672 -0
  50. data/ext/snowcrash/src/Platform.h +54 -0
  51. data/ext/snowcrash/src/RegexMatch.h +32 -0
  52. data/ext/snowcrash/src/ResourceGroupParser.h +195 -0
  53. data/ext/snowcrash/src/ResourceParser.h +584 -0
  54. data/ext/snowcrash/src/SectionUtility.h +142 -0
  55. data/ext/snowcrash/src/Serialize.cc +52 -0
  56. data/ext/snowcrash/src/Serialize.h +69 -0
  57. data/ext/snowcrash/src/SerializeJSON.cc +601 -0
  58. data/ext/snowcrash/src/SerializeJSON.h +21 -0
  59. data/ext/snowcrash/src/SerializeYAML.cc +336 -0
  60. data/ext/snowcrash/src/SerializeYAML.h +21 -0
  61. data/ext/snowcrash/src/SourceAnnotation.h +177 -0
  62. data/ext/snowcrash/src/StringUtility.h +109 -0
  63. data/ext/snowcrash/src/SymbolTable.h +83 -0
  64. data/ext/snowcrash/src/UriTemplateParser.cc +195 -0
  65. data/ext/snowcrash/src/UriTemplateParser.h +243 -0
  66. data/ext/snowcrash/src/Version.h +39 -0
  67. data/ext/snowcrash/src/csnowcrash.cc +23 -0
  68. data/ext/snowcrash/src/csnowcrash.h +38 -0
  69. data/ext/snowcrash/src/posix/RegexMatch.cc +99 -0
  70. data/ext/snowcrash/src/snowcrash.cc +18 -0
  71. data/ext/snowcrash/src/snowcrash.h +41 -0
  72. data/ext/snowcrash/src/snowcrash/snowcrash.cc +170 -0
  73. data/ext/snowcrash/src/win/RegexMatch.cc +78 -0
  74. data/ext/snowcrash/sundown/CONTRIBUTING.md +10 -0
  75. data/ext/snowcrash/sundown/Makefile +83 -0
  76. data/ext/snowcrash/sundown/Makefile.win +33 -0
  77. data/ext/snowcrash/sundown/examples/smartypants.c +72 -0
  78. data/ext/snowcrash/sundown/examples/sundown.c +80 -0
  79. data/ext/snowcrash/sundown/html/houdini.h +37 -0
  80. data/ext/snowcrash/sundown/html/houdini_href_e.c +108 -0
  81. data/ext/snowcrash/sundown/html/houdini_html_e.c +84 -0
  82. data/ext/snowcrash/sundown/html/html.c +647 -0
  83. data/ext/snowcrash/sundown/html/html.h +77 -0
  84. data/ext/snowcrash/sundown/html/html_smartypants.c +389 -0
  85. data/ext/snowcrash/sundown/html_block_names.txt +25 -0
  86. data/ext/snowcrash/sundown/src/autolink.c +297 -0
  87. data/ext/snowcrash/sundown/src/autolink.h +51 -0
  88. data/ext/snowcrash/sundown/src/buffer.c +225 -0
  89. data/ext/snowcrash/sundown/src/buffer.h +96 -0
  90. data/ext/snowcrash/sundown/src/html_blocks.h +206 -0
  91. data/ext/snowcrash/sundown/src/markdown.c +2701 -0
  92. data/ext/snowcrash/sundown/src/markdown.h +147 -0
  93. data/ext/snowcrash/sundown/src/src_map.c +200 -0
  94. data/ext/snowcrash/sundown/src/src_map.h +58 -0
  95. data/ext/snowcrash/sundown/src/stack.c +81 -0
  96. data/ext/snowcrash/sundown/src/stack.h +29 -0
  97. data/ext/snowcrash/sundown/sundown.def +20 -0
  98. data/ext/snowcrash/tools/gyp/AUTHORS +11 -0
  99. data/ext/snowcrash/tools/gyp/DEPS +24 -0
  100. data/ext/snowcrash/tools/gyp/OWNERS +1 -0
  101. data/ext/snowcrash/tools/gyp/PRESUBMIT.py +120 -0
  102. data/ext/snowcrash/tools/gyp/buildbot/buildbot_run.py +190 -0
  103. data/ext/snowcrash/tools/gyp/codereview.settings +10 -0
  104. data/ext/snowcrash/tools/gyp/data/win/large-pdb-shim.cc +12 -0
  105. data/ext/snowcrash/tools/gyp/gyp +8 -0
  106. data/ext/snowcrash/tools/gyp/gyp.bat +5 -0
  107. data/ext/snowcrash/tools/gyp/gyp_main.py +18 -0
  108. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSNew.py +340 -0
  109. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSProject.py +208 -0
  110. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSSettings.py +1063 -0
  111. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSToolFile.py +58 -0
  112. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSUserFile.py +147 -0
  113. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSUtil.py +267 -0
  114. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSVersion.py +409 -0
  115. data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.py +537 -0
  116. data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.pyc +0 -0
  117. data/ext/snowcrash/tools/gyp/pylib/gyp/common.py +521 -0
  118. data/ext/snowcrash/tools/gyp/pylib/gyp/common.pyc +0 -0
  119. data/ext/snowcrash/tools/gyp/pylib/gyp/easy_xml.py +157 -0
  120. data/ext/snowcrash/tools/gyp/pylib/gyp/flock_tool.py +49 -0
  121. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.py +0 -0
  122. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.pyc +0 -0
  123. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/android.py +1069 -0
  124. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/cmake.py +1143 -0
  125. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/dump_dependency_json.py +81 -0
  126. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/eclipse.py +335 -0
  127. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/gypd.py +87 -0
  128. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/gypsh.py +56 -0
  129. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.py +2181 -0
  130. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.pyc +0 -0
  131. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/msvs.py +3335 -0
  132. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/ninja.py +2156 -0
  133. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.py +1224 -0
  134. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.pyc +0 -0
  135. data/ext/snowcrash/tools/gyp/pylib/gyp/input.py +2809 -0
  136. data/ext/snowcrash/tools/gyp/pylib/gyp/input.pyc +0 -0
  137. data/ext/snowcrash/tools/gyp/pylib/gyp/mac_tool.py +510 -0
  138. data/ext/snowcrash/tools/gyp/pylib/gyp/msvs_emulation.py +972 -0
  139. data/ext/snowcrash/tools/gyp/pylib/gyp/ninja_syntax.py +160 -0
  140. data/ext/snowcrash/tools/gyp/pylib/gyp/ordered_dict.py +289 -0
  141. data/ext/snowcrash/tools/gyp/pylib/gyp/win_tool.py +292 -0
  142. data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.py +1440 -0
  143. data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.pyc +0 -0
  144. data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.py +2889 -0
  145. data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.pyc +0 -0
  146. data/ext/snowcrash/tools/gyp/pylib/gyp/xml_fix.py +69 -0
  147. data/ext/snowcrash/tools/gyp/pylintrc +307 -0
  148. data/ext/snowcrash/tools/gyp/samples/samples +81 -0
  149. data/ext/snowcrash/tools/gyp/samples/samples.bat +5 -0
  150. data/ext/snowcrash/tools/gyp/setup.py +19 -0
  151. data/ext/snowcrash/tools/gyp/tools/Xcode/Specifications/gyp.pbfilespec +27 -0
  152. data/ext/snowcrash/tools/gyp/tools/Xcode/Specifications/gyp.xclangspec +226 -0
  153. data/ext/snowcrash/tools/gyp/tools/emacs/gyp.el +252 -0
  154. data/ext/snowcrash/tools/gyp/tools/graphviz.py +100 -0
  155. data/ext/snowcrash/tools/gyp/tools/pretty_gyp.py +155 -0
  156. data/ext/snowcrash/tools/gyp/tools/pretty_sln.py +168 -0
  157. data/ext/snowcrash/tools/gyp/tools/pretty_vcproj.py +329 -0
  158. data/ext/snowcrash/tools/homebrew/snowcrash.rb +11 -0
  159. data/ext/snowcrash/vcbuild.bat +184 -0
  160. data/lib/redsnow.rb +31 -0
  161. data/lib/redsnow/binding.rb +132 -0
  162. data/lib/redsnow/blueprint.rb +365 -0
  163. data/lib/redsnow/object.rb +18 -0
  164. data/lib/redsnow/parseresult.rb +107 -0
  165. data/lib/redsnow/version.rb +4 -0
  166. data/provisioning.sh +20 -0
  167. data/redsnow.gemspec +35 -0
  168. data/test/_helper.rb +15 -0
  169. data/test/fixtures/sample-api-ast.json +97 -0
  170. data/test/fixtures/sample-api.apib +20 -0
  171. data/test/redsnow_binding_test.rb +35 -0
  172. data/test/redsnow_parseresult_test.rb +50 -0
  173. data/test/redsnow_test.rb +285 -0
  174. metadata +358 -0
@@ -0,0 +1,1143 @@
1
+ # Copyright (c) 2013 Google Inc. All rights reserved.
2
+ # Use of this source code is governed by a BSD-style license that can be
3
+ # found in the LICENSE file.
4
+
5
+ """cmake output module
6
+
7
+ This module is under development and should be considered experimental.
8
+
9
+ This module produces cmake (2.8.8+) input as its output. One CMakeLists.txt is
10
+ created for each configuration.
11
+
12
+ This module's original purpose was to support editing in IDEs like KDevelop
13
+ which use CMake for project management. It is also possible to use CMake to
14
+ generate projects for other IDEs such as eclipse cdt and code::blocks. QtCreator
15
+ will convert the CMakeLists.txt to a code::blocks cbp for the editor to read,
16
+ but build using CMake. As a result QtCreator editor is unaware of compiler
17
+ defines. The generated CMakeLists.txt can also be used to build on Linux. There
18
+ is currently no support for building on platforms other than Linux.
19
+
20
+ The generated CMakeLists.txt should properly compile all projects. However,
21
+ there is a mismatch between gyp and cmake with regard to linking. All attempts
22
+ are made to work around this, but CMake sometimes sees -Wl,--start-group as a
23
+ library and incorrectly repeats it. As a result the output of this generator
24
+ should not be relied on for building.
25
+
26
+ When using with kdevelop, use version 4.4+. Previous versions of kdevelop will
27
+ not be able to find the header file directories described in the generated
28
+ CMakeLists.txt file.
29
+ """
30
+
31
+ import multiprocessing
32
+ import os
33
+ import signal
34
+ import string
35
+ import subprocess
36
+ import gyp.common
37
+
38
+ generator_default_variables = {
39
+ 'EXECUTABLE_PREFIX': '',
40
+ 'EXECUTABLE_SUFFIX': '',
41
+ 'STATIC_LIB_PREFIX': 'lib',
42
+ 'STATIC_LIB_SUFFIX': '.a',
43
+ 'SHARED_LIB_PREFIX': 'lib',
44
+ 'SHARED_LIB_SUFFIX': '.so',
45
+ 'SHARED_LIB_DIR': '${builddir}/lib.${TOOLSET}',
46
+ 'LIB_DIR': '${obj}.${TOOLSET}',
47
+ 'INTERMEDIATE_DIR': '${obj}.${TOOLSET}/${TARGET}/geni',
48
+ 'SHARED_INTERMEDIATE_DIR': '${obj}/gen',
49
+ 'PRODUCT_DIR': '${builddir}',
50
+ 'RULE_INPUT_PATH': '${RULE_INPUT_PATH}',
51
+ 'RULE_INPUT_DIRNAME': '${RULE_INPUT_DIRNAME}',
52
+ 'RULE_INPUT_NAME': '${RULE_INPUT_NAME}',
53
+ 'RULE_INPUT_ROOT': '${RULE_INPUT_ROOT}',
54
+ 'RULE_INPUT_EXT': '${RULE_INPUT_EXT}',
55
+ 'CONFIGURATION_NAME': '${configuration}',
56
+ }
57
+
58
+ FULL_PATH_VARS = ('${CMAKE_SOURCE_DIR}', '${builddir}', '${obj}')
59
+
60
+ generator_supports_multiple_toolsets = True
61
+ generator_wants_static_library_dependencies_adjusted = True
62
+
63
+ COMPILABLE_EXTENSIONS = {
64
+ '.c': 'cc',
65
+ '.cc': 'cxx',
66
+ '.cpp': 'cxx',
67
+ '.cxx': 'cxx',
68
+ '.s': 's', # cc
69
+ '.S': 's', # cc
70
+ }
71
+
72
+
73
+ def RemovePrefix(a, prefix):
74
+ """Returns 'a' without 'prefix' if it starts with 'prefix'."""
75
+ return a[len(prefix):] if a.startswith(prefix) else a
76
+
77
+
78
+ def CalculateVariables(default_variables, params):
79
+ """Calculate additional variables for use in the build (called by gyp)."""
80
+ default_variables.setdefault('OS', gyp.common.GetFlavor(params))
81
+
82
+
83
+ def Compilable(filename):
84
+ """Return true if the file is compilable (should be in OBJS)."""
85
+ return any(filename.endswith(e) for e in COMPILABLE_EXTENSIONS)
86
+
87
+
88
+ def Linkable(filename):
89
+ """Return true if the file is linkable (should be on the link line)."""
90
+ return filename.endswith('.o')
91
+
92
+
93
+ def NormjoinPathForceCMakeSource(base_path, rel_path):
94
+ """Resolves rel_path against base_path and returns the result.
95
+
96
+ If rel_path is an absolute path it is returned unchanged.
97
+ Otherwise it is resolved against base_path and normalized.
98
+ If the result is a relative path, it is forced to be relative to the
99
+ CMakeLists.txt.
100
+ """
101
+ if os.path.isabs(rel_path):
102
+ return rel_path
103
+ if any([rel_path.startswith(var) for var in FULL_PATH_VARS]):
104
+ return rel_path
105
+ # TODO: do we need to check base_path for absolute variables as well?
106
+ return os.path.join('${CMAKE_SOURCE_DIR}',
107
+ os.path.normpath(os.path.join(base_path, rel_path)))
108
+
109
+
110
+ def NormjoinPath(base_path, rel_path):
111
+ """Resolves rel_path against base_path and returns the result.
112
+ TODO: what is this really used for?
113
+ If rel_path begins with '$' it is returned unchanged.
114
+ Otherwise it is resolved against base_path if relative, then normalized.
115
+ """
116
+ if rel_path.startswith('$') and not rel_path.startswith('${configuration}'):
117
+ return rel_path
118
+ return os.path.normpath(os.path.join(base_path, rel_path))
119
+
120
+
121
+ def CMakeStringEscape(a):
122
+ """Escapes the string 'a' for use inside a CMake string.
123
+
124
+ This means escaping
125
+ '\' otherwise it may be seen as modifying the next character
126
+ '"' otherwise it will end the string
127
+ ';' otherwise the string becomes a list
128
+
129
+ The following do not need to be escaped
130
+ '#' when the lexer is in string state, this does not start a comment
131
+
132
+ The following are yet unknown
133
+ '$' generator variables (like ${obj}) must not be escaped,
134
+ but text $ should be escaped
135
+ what is wanted is to know which $ come from generator variables
136
+ """
137
+ return a.replace('\\', '\\\\').replace(';', '\\;').replace('"', '\\"')
138
+
139
+
140
+ def SetFileProperty(output, source_name, property_name, values, sep):
141
+ """Given a set of source file, sets the given property on them."""
142
+ output.write('set_source_files_properties(')
143
+ output.write(source_name)
144
+ output.write(' PROPERTIES ')
145
+ output.write(property_name)
146
+ output.write(' "')
147
+ for value in values:
148
+ output.write(CMakeStringEscape(value))
149
+ output.write(sep)
150
+ output.write('")\n')
151
+
152
+
153
+ def SetFilesProperty(output, source_names, property_name, values, sep):
154
+ """Given a set of source files, sets the given property on them."""
155
+ output.write('set_source_files_properties(\n')
156
+ for source_name in source_names:
157
+ output.write(' ')
158
+ output.write(source_name)
159
+ output.write('\n')
160
+ output.write(' PROPERTIES\n ')
161
+ output.write(property_name)
162
+ output.write(' "')
163
+ for value in values:
164
+ output.write(CMakeStringEscape(value))
165
+ output.write(sep)
166
+ output.write('"\n)\n')
167
+
168
+
169
+ def SetTargetProperty(output, target_name, property_name, values, sep=''):
170
+ """Given a target, sets the given property."""
171
+ output.write('set_target_properties(')
172
+ output.write(target_name)
173
+ output.write(' PROPERTIES ')
174
+ output.write(property_name)
175
+ output.write(' "')
176
+ for value in values:
177
+ output.write(CMakeStringEscape(value))
178
+ output.write(sep)
179
+ output.write('")\n')
180
+
181
+
182
+ def SetVariable(output, variable_name, value):
183
+ """Sets a CMake variable."""
184
+ output.write('set(')
185
+ output.write(variable_name)
186
+ output.write(' "')
187
+ output.write(CMakeStringEscape(value))
188
+ output.write('")\n')
189
+
190
+
191
+ def SetVariableList(output, variable_name, values):
192
+ """Sets a CMake variable to a list."""
193
+ if not values:
194
+ return SetVariable(output, variable_name, "")
195
+ if len(values) == 1:
196
+ return SetVariable(output, variable_name, values[0])
197
+ output.write('list(APPEND ')
198
+ output.write(variable_name)
199
+ output.write('\n "')
200
+ output.write('"\n "'.join([CMakeStringEscape(value) for value in values]))
201
+ output.write('")\n')
202
+
203
+
204
+ def UnsetVariable(output, variable_name):
205
+ """Unsets a CMake variable."""
206
+ output.write('unset(')
207
+ output.write(variable_name)
208
+ output.write(')\n')
209
+
210
+
211
+ def WriteVariable(output, variable_name, prepend=None):
212
+ if prepend:
213
+ output.write(prepend)
214
+ output.write('${')
215
+ output.write(variable_name)
216
+ output.write('}')
217
+
218
+
219
+ class CMakeTargetType:
220
+ def __init__(self, command, modifier, property_modifier):
221
+ self.command = command
222
+ self.modifier = modifier
223
+ self.property_modifier = property_modifier
224
+
225
+
226
+ cmake_target_type_from_gyp_target_type = {
227
+ 'executable': CMakeTargetType('add_executable', None, 'RUNTIME'),
228
+ 'static_library': CMakeTargetType('add_library', 'STATIC', 'ARCHIVE'),
229
+ 'shared_library': CMakeTargetType('add_library', 'SHARED', 'LIBRARY'),
230
+ 'loadable_module': CMakeTargetType('add_library', 'MODULE', 'LIBRARY'),
231
+ 'none': CMakeTargetType('add_custom_target', 'SOURCES', None),
232
+ }
233
+
234
+
235
+ def StringToCMakeTargetName(a):
236
+ """Converts the given string 'a' to a valid CMake target name.
237
+
238
+ All invalid characters are replaced by '_'.
239
+ Invalid for cmake: ' ', '/', '(', ')'
240
+ Invalid for make: ':'
241
+ Invalid for unknown reasons but cause failures: '.'
242
+ """
243
+ return a.translate(string.maketrans(' /():.', '______'))
244
+
245
+
246
+ def WriteActions(target_name, actions, extra_sources, extra_deps,
247
+ path_to_gyp, output):
248
+ """Write CMake for the 'actions' in the target.
249
+
250
+ Args:
251
+ target_name: the name of the CMake target being generated.
252
+ actions: the Gyp 'actions' dict for this target.
253
+ extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
254
+ extra_deps: [<cmake_taget>] to append with generated targets.
255
+ path_to_gyp: relative path from CMakeLists.txt being generated to
256
+ the Gyp file in which the target being generated is defined.
257
+ """
258
+ for action in actions:
259
+ action_name = StringToCMakeTargetName(action['action_name'])
260
+ action_target_name = '%s__%s' % (target_name, action_name)
261
+
262
+ inputs = action['inputs']
263
+ inputs_name = action_target_name + '__input'
264
+ SetVariableList(output, inputs_name,
265
+ [NormjoinPathForceCMakeSource(path_to_gyp, dep) for dep in inputs])
266
+
267
+ outputs = action['outputs']
268
+ cmake_outputs = [NormjoinPathForceCMakeSource(path_to_gyp, out)
269
+ for out in outputs]
270
+ outputs_name = action_target_name + '__output'
271
+ SetVariableList(output, outputs_name, cmake_outputs)
272
+
273
+ # Build up a list of outputs.
274
+ # Collect the output dirs we'll need.
275
+ dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
276
+
277
+ if int(action.get('process_outputs_as_sources', False)):
278
+ extra_sources.extend(zip(cmake_outputs, outputs))
279
+
280
+ # add_custom_command
281
+ output.write('add_custom_command(OUTPUT ')
282
+ WriteVariable(output, outputs_name)
283
+ output.write('\n')
284
+
285
+ if len(dirs) > 0:
286
+ for directory in dirs:
287
+ output.write(' COMMAND ${CMAKE_COMMAND} -E make_directory ')
288
+ output.write(directory)
289
+ output.write('\n')
290
+
291
+ output.write(' COMMAND ')
292
+ output.write(gyp.common.EncodePOSIXShellList(action['action']))
293
+ output.write('\n')
294
+
295
+ output.write(' DEPENDS ')
296
+ WriteVariable(output, inputs_name)
297
+ output.write('\n')
298
+
299
+ output.write(' WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/')
300
+ output.write(path_to_gyp)
301
+ output.write('\n')
302
+
303
+ output.write(' COMMENT ')
304
+ if 'message' in action:
305
+ output.write(action['message'])
306
+ else:
307
+ output.write(action_target_name)
308
+ output.write('\n')
309
+
310
+ output.write(' VERBATIM\n')
311
+ output.write(')\n')
312
+
313
+ # add_custom_target
314
+ output.write('add_custom_target(')
315
+ output.write(action_target_name)
316
+ output.write('\n DEPENDS ')
317
+ WriteVariable(output, outputs_name)
318
+ output.write('\n SOURCES ')
319
+ WriteVariable(output, inputs_name)
320
+ output.write('\n)\n')
321
+
322
+ extra_deps.append(action_target_name)
323
+
324
+
325
+ def NormjoinRulePathForceCMakeSource(base_path, rel_path, rule_source):
326
+ if rel_path.startswith(("${RULE_INPUT_PATH}","${RULE_INPUT_DIRNAME}")):
327
+ if any([rule_source.startswith(var) for var in FULL_PATH_VARS]):
328
+ return rel_path
329
+ return NormjoinPathForceCMakeSource(base_path, rel_path)
330
+
331
+
332
+ def WriteRules(target_name, rules, extra_sources, extra_deps,
333
+ path_to_gyp, output):
334
+ """Write CMake for the 'rules' in the target.
335
+
336
+ Args:
337
+ target_name: the name of the CMake target being generated.
338
+ actions: the Gyp 'actions' dict for this target.
339
+ extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
340
+ extra_deps: [<cmake_taget>] to append with generated targets.
341
+ path_to_gyp: relative path from CMakeLists.txt being generated to
342
+ the Gyp file in which the target being generated is defined.
343
+ """
344
+ for rule in rules:
345
+ rule_name = StringToCMakeTargetName(target_name + '__' + rule['rule_name'])
346
+
347
+ inputs = rule.get('inputs', [])
348
+ inputs_name = rule_name + '__input'
349
+ SetVariableList(output, inputs_name,
350
+ [NormjoinPathForceCMakeSource(path_to_gyp, dep) for dep in inputs])
351
+ outputs = rule['outputs']
352
+ var_outputs = []
353
+
354
+ for count, rule_source in enumerate(rule.get('rule_sources', [])):
355
+ action_name = rule_name + '_' + str(count)
356
+
357
+ rule_source_dirname, rule_source_basename = os.path.split(rule_source)
358
+ rule_source_root, rule_source_ext = os.path.splitext(rule_source_basename)
359
+
360
+ SetVariable(output, 'RULE_INPUT_PATH', rule_source)
361
+ SetVariable(output, 'RULE_INPUT_DIRNAME', rule_source_dirname)
362
+ SetVariable(output, 'RULE_INPUT_NAME', rule_source_basename)
363
+ SetVariable(output, 'RULE_INPUT_ROOT', rule_source_root)
364
+ SetVariable(output, 'RULE_INPUT_EXT', rule_source_ext)
365
+
366
+ # Build up a list of outputs.
367
+ # Collect the output dirs we'll need.
368
+ dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
369
+
370
+ # Create variables for the output, as 'local' variable will be unset.
371
+ these_outputs = []
372
+ for output_index, out in enumerate(outputs):
373
+ output_name = action_name + '_' + str(output_index)
374
+ SetVariable(output, output_name,
375
+ NormjoinRulePathForceCMakeSource(path_to_gyp, out,
376
+ rule_source))
377
+ if int(rule.get('process_outputs_as_sources', False)):
378
+ extra_sources.append(('${' + output_name + '}', out))
379
+ these_outputs.append('${' + output_name + '}')
380
+ var_outputs.append('${' + output_name + '}')
381
+
382
+ # add_custom_command
383
+ output.write('add_custom_command(OUTPUT\n')
384
+ for out in these_outputs:
385
+ output.write(' ')
386
+ output.write(out)
387
+ output.write('\n')
388
+
389
+ for directory in dirs:
390
+ output.write(' COMMAND ${CMAKE_COMMAND} -E make_directory ')
391
+ output.write(directory)
392
+ output.write('\n')
393
+
394
+ output.write(' COMMAND ')
395
+ output.write(gyp.common.EncodePOSIXShellList(rule['action']))
396
+ output.write('\n')
397
+
398
+ output.write(' DEPENDS ')
399
+ WriteVariable(output, inputs_name)
400
+ output.write(' ')
401
+ output.write(NormjoinPath(path_to_gyp, rule_source))
402
+ output.write('\n')
403
+
404
+ # CMAKE_SOURCE_DIR is where the CMakeLists.txt lives.
405
+ # The cwd is the current build directory.
406
+ output.write(' WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/')
407
+ output.write(path_to_gyp)
408
+ output.write('\n')
409
+
410
+ output.write(' COMMENT ')
411
+ if 'message' in rule:
412
+ output.write(rule['message'])
413
+ else:
414
+ output.write(action_name)
415
+ output.write('\n')
416
+
417
+ output.write(' VERBATIM\n')
418
+ output.write(')\n')
419
+
420
+ UnsetVariable(output, 'RULE_INPUT_PATH')
421
+ UnsetVariable(output, 'RULE_INPUT_DIRNAME')
422
+ UnsetVariable(output, 'RULE_INPUT_NAME')
423
+ UnsetVariable(output, 'RULE_INPUT_ROOT')
424
+ UnsetVariable(output, 'RULE_INPUT_EXT')
425
+
426
+ # add_custom_target
427
+ output.write('add_custom_target(')
428
+ output.write(rule_name)
429
+ output.write(' DEPENDS\n')
430
+ for out in var_outputs:
431
+ output.write(' ')
432
+ output.write(out)
433
+ output.write('\n')
434
+ output.write('SOURCES ')
435
+ WriteVariable(output, inputs_name)
436
+ output.write('\n')
437
+ for rule_source in rule.get('rule_sources', []):
438
+ output.write(' ')
439
+ output.write(NormjoinPath(path_to_gyp, rule_source))
440
+ output.write('\n')
441
+ output.write(')\n')
442
+
443
+ extra_deps.append(rule_name)
444
+
445
+
446
+ def WriteCopies(target_name, copies, extra_deps, path_to_gyp, output):
447
+ """Write CMake for the 'copies' in the target.
448
+
449
+ Args:
450
+ target_name: the name of the CMake target being generated.
451
+ actions: the Gyp 'actions' dict for this target.
452
+ extra_deps: [<cmake_taget>] to append with generated targets.
453
+ path_to_gyp: relative path from CMakeLists.txt being generated to
454
+ the Gyp file in which the target being generated is defined.
455
+ """
456
+ copy_name = target_name + '__copies'
457
+
458
+ # CMake gets upset with custom targets with OUTPUT which specify no output.
459
+ have_copies = any(copy['files'] for copy in copies)
460
+ if not have_copies:
461
+ output.write('add_custom_target(')
462
+ output.write(copy_name)
463
+ output.write(')\n')
464
+ extra_deps.append(copy_name)
465
+ return
466
+
467
+ class Copy:
468
+ def __init__(self, ext, command):
469
+ self.cmake_inputs = []
470
+ self.cmake_outputs = []
471
+ self.gyp_inputs = []
472
+ self.gyp_outputs = []
473
+ self.ext = ext
474
+ self.inputs_name = None
475
+ self.outputs_name = None
476
+ self.command = command
477
+
478
+ file_copy = Copy('', 'copy')
479
+ dir_copy = Copy('_dirs', 'copy_directory')
480
+
481
+ for copy in copies:
482
+ files = copy['files']
483
+ destination = copy['destination']
484
+ for src in files:
485
+ path = os.path.normpath(src)
486
+ basename = os.path.split(path)[1]
487
+ dst = os.path.join(destination, basename)
488
+
489
+ copy = file_copy if os.path.basename(src) else dir_copy
490
+
491
+ copy.cmake_inputs.append(NormjoinPath(path_to_gyp, src))
492
+ copy.cmake_outputs.append(NormjoinPathForceCMakeSource(path_to_gyp, dst))
493
+ copy.gyp_inputs.append(src)
494
+ copy.gyp_outputs.append(dst)
495
+
496
+ for copy in (file_copy, dir_copy):
497
+ if copy.cmake_inputs:
498
+ copy.inputs_name = copy_name + '__input' + copy.ext
499
+ SetVariableList(output, copy.inputs_name, copy.cmake_inputs)
500
+
501
+ copy.outputs_name = copy_name + '__output' + copy.ext
502
+ SetVariableList(output, copy.outputs_name, copy.cmake_outputs)
503
+
504
+ # add_custom_command
505
+ output.write('add_custom_command(\n')
506
+
507
+ output.write('OUTPUT')
508
+ for copy in (file_copy, dir_copy):
509
+ if copy.outputs_name:
510
+ WriteVariable(output, copy.outputs_name, ' ')
511
+ output.write('\n')
512
+
513
+ for copy in (file_copy, dir_copy):
514
+ for src, dst in zip(copy.gyp_inputs, copy.gyp_outputs):
515
+ # 'cmake -E copy src dst' will create the 'dst' directory if needed.
516
+ output.write('COMMAND ${CMAKE_COMMAND} -E %s ' % copy.command)
517
+ output.write(src)
518
+ output.write(' ')
519
+ output.write(dst)
520
+ output.write("\n")
521
+
522
+ output.write('DEPENDS')
523
+ for copy in (file_copy, dir_copy):
524
+ if copy.inputs_name:
525
+ WriteVariable(output, copy.inputs_name, ' ')
526
+ output.write('\n')
527
+
528
+ output.write('WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/')
529
+ output.write(path_to_gyp)
530
+ output.write('\n')
531
+
532
+ output.write('COMMENT Copying for ')
533
+ output.write(target_name)
534
+ output.write('\n')
535
+
536
+ output.write('VERBATIM\n')
537
+ output.write(')\n')
538
+
539
+ # add_custom_target
540
+ output.write('add_custom_target(')
541
+ output.write(copy_name)
542
+ output.write('\n DEPENDS')
543
+ for copy in (file_copy, dir_copy):
544
+ if copy.outputs_name:
545
+ WriteVariable(output, copy.outputs_name, ' ')
546
+ output.write('\n SOURCES')
547
+ if file_copy.inputs_name:
548
+ WriteVariable(output, file_copy.inputs_name, ' ')
549
+ output.write('\n)\n')
550
+
551
+ extra_deps.append(copy_name)
552
+
553
+
554
+ def CreateCMakeTargetBaseName(qualified_target):
555
+ """This is the name we would like the target to have."""
556
+ _, gyp_target_name, gyp_target_toolset = (
557
+ gyp.common.ParseQualifiedTarget(qualified_target))
558
+ cmake_target_base_name = gyp_target_name
559
+ if gyp_target_toolset and gyp_target_toolset != 'target':
560
+ cmake_target_base_name += '_' + gyp_target_toolset
561
+ return StringToCMakeTargetName(cmake_target_base_name)
562
+
563
+
564
+ def CreateCMakeTargetFullName(qualified_target):
565
+ """An unambiguous name for the target."""
566
+ gyp_file, gyp_target_name, gyp_target_toolset = (
567
+ gyp.common.ParseQualifiedTarget(qualified_target))
568
+ cmake_target_full_name = gyp_file + ':' + gyp_target_name
569
+ if gyp_target_toolset and gyp_target_toolset != 'target':
570
+ cmake_target_full_name += '_' + gyp_target_toolset
571
+ return StringToCMakeTargetName(cmake_target_full_name)
572
+
573
+
574
+ class CMakeNamer(object):
575
+ """Converts Gyp target names into CMake target names.
576
+
577
+ CMake requires that target names be globally unique. One way to ensure
578
+ this is to fully qualify the names of the targets. Unfortunatly, this
579
+ ends up with all targets looking like "chrome_chrome_gyp_chrome" instead
580
+ of just "chrome". If this generator were only interested in building, it
581
+ would be possible to fully qualify all target names, then create
582
+ unqualified target names which depend on all qualified targets which
583
+ should have had that name. This is more or less what the 'make' generator
584
+ does with aliases. However, one goal of this generator is to create CMake
585
+ files for use with IDEs, and fully qualified names are not as user
586
+ friendly.
587
+
588
+ Since target name collision is rare, we do the above only when required.
589
+
590
+ Toolset variants are always qualified from the base, as this is required for
591
+ building. However, it also makes sense for an IDE, as it is possible for
592
+ defines to be different.
593
+ """
594
+ def __init__(self, target_list):
595
+ self.cmake_target_base_names_conficting = set()
596
+
597
+ cmake_target_base_names_seen = set()
598
+ for qualified_target in target_list:
599
+ cmake_target_base_name = CreateCMakeTargetBaseName(qualified_target)
600
+
601
+ if cmake_target_base_name not in cmake_target_base_names_seen:
602
+ cmake_target_base_names_seen.add(cmake_target_base_name)
603
+ else:
604
+ self.cmake_target_base_names_conficting.add(cmake_target_base_name)
605
+
606
+ def CreateCMakeTargetName(self, qualified_target):
607
+ base_name = CreateCMakeTargetBaseName(qualified_target)
608
+ if base_name in self.cmake_target_base_names_conficting:
609
+ return CreateCMakeTargetFullName(qualified_target)
610
+ return base_name
611
+
612
+
613
+ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
614
+ options, generator_flags, all_qualified_targets, output):
615
+
616
+ # The make generator does this always.
617
+ # TODO: It would be nice to be able to tell CMake all dependencies.
618
+ circular_libs = generator_flags.get('circular', True)
619
+
620
+ if not generator_flags.get('standalone', False):
621
+ output.write('\n#')
622
+ output.write(qualified_target)
623
+ output.write('\n')
624
+
625
+ gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target)
626
+ rel_gyp_file = gyp.common.RelativePath(gyp_file, options.toplevel_dir)
627
+ rel_gyp_dir = os.path.dirname(rel_gyp_file)
628
+
629
+ # Relative path from build dir to top dir.
630
+ build_to_top = gyp.common.InvertRelativePath(build_dir, options.toplevel_dir)
631
+ # Relative path from build dir to gyp dir.
632
+ build_to_gyp = os.path.join(build_to_top, rel_gyp_dir)
633
+
634
+ path_from_cmakelists_to_gyp = build_to_gyp
635
+
636
+ spec = target_dicts.get(qualified_target, {})
637
+ config = spec.get('configurations', {}).get(config_to_use, {})
638
+
639
+ target_name = spec.get('target_name', '<missing target name>')
640
+ target_type = spec.get('type', '<missing target type>')
641
+ target_toolset = spec.get('toolset')
642
+
643
+ SetVariable(output, 'TARGET', target_name)
644
+ SetVariable(output, 'TOOLSET', target_toolset)
645
+
646
+ cmake_target_name = namer.CreateCMakeTargetName(qualified_target)
647
+
648
+ extra_sources = []
649
+ extra_deps = []
650
+
651
+ # Actions must come first, since they can generate more OBJs for use below.
652
+ if 'actions' in spec:
653
+ WriteActions(cmake_target_name, spec['actions'], extra_sources, extra_deps,
654
+ path_from_cmakelists_to_gyp, output)
655
+
656
+ # Rules must be early like actions.
657
+ if 'rules' in spec:
658
+ WriteRules(cmake_target_name, spec['rules'], extra_sources, extra_deps,
659
+ path_from_cmakelists_to_gyp, output)
660
+
661
+ # Copies
662
+ if 'copies' in spec:
663
+ WriteCopies(cmake_target_name, spec['copies'], extra_deps,
664
+ path_from_cmakelists_to_gyp, output)
665
+
666
+ # Target and sources
667
+ srcs = spec.get('sources', [])
668
+
669
+ # Gyp separates the sheep from the goats based on file extensions.
670
+ def partition(l, p):
671
+ return reduce(lambda x, e: x[not p(e)].append(e) or x, l, ([], []))
672
+ compilable_srcs, other_srcs = partition(srcs, Compilable)
673
+
674
+ # CMake gets upset when executable targets provide no sources.
675
+ if target_type == 'executable' and not compilable_srcs and not extra_sources:
676
+ print ('Executable %s has no complilable sources, treating as "none".' %
677
+ target_name )
678
+ target_type = 'none'
679
+
680
+ cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type)
681
+ if cmake_target_type is None:
682
+ print ('Target %s has unknown target type %s, skipping.' %
683
+ ( target_name, target_type ) )
684
+ return
685
+
686
+ other_srcs_name = None
687
+ if other_srcs:
688
+ other_srcs_name = cmake_target_name + '__other_srcs'
689
+ SetVariableList(output, other_srcs_name,
690
+ [NormjoinPath(path_from_cmakelists_to_gyp, src) for src in other_srcs])
691
+
692
+ # CMake is opposed to setting linker directories and considers the practice
693
+ # of setting linker directories dangerous. Instead, it favors the use of
694
+ # find_library and passing absolute paths to target_link_libraries.
695
+ # However, CMake does provide the command link_directories, which adds
696
+ # link directories to targets defined after it is called.
697
+ # As a result, link_directories must come before the target definition.
698
+ # CMake unfortunately has no means of removing entries from LINK_DIRECTORIES.
699
+ library_dirs = config.get('library_dirs')
700
+ if library_dirs is not None:
701
+ output.write('link_directories(')
702
+ for library_dir in library_dirs:
703
+ output.write(' ')
704
+ output.write(NormjoinPath(path_from_cmakelists_to_gyp, library_dir))
705
+ output.write('\n')
706
+ output.write(')\n')
707
+
708
+ output.write(cmake_target_type.command)
709
+ output.write('(')
710
+ output.write(cmake_target_name)
711
+
712
+ if cmake_target_type.modifier is not None:
713
+ output.write(' ')
714
+ output.write(cmake_target_type.modifier)
715
+
716
+ if other_srcs_name:
717
+ WriteVariable(output, other_srcs_name, ' ')
718
+
719
+ output.write('\n')
720
+
721
+ for src in compilable_srcs:
722
+ output.write(' ')
723
+ output.write(NormjoinPath(path_from_cmakelists_to_gyp, src))
724
+ output.write('\n')
725
+ for extra_source in extra_sources:
726
+ output.write(' ')
727
+ src, _ = extra_source
728
+ output.write(NormjoinPath(path_from_cmakelists_to_gyp, src))
729
+ output.write('\n')
730
+
731
+ output.write(')\n')
732
+
733
+ # Output name and location.
734
+ if target_type != 'none':
735
+ # Mark uncompiled sources as uncompiled.
736
+ if other_srcs_name:
737
+ output.write('set_source_files_properties(')
738
+ WriteVariable(output, other_srcs_name, '')
739
+ output.write(' PROPERTIES HEADER_FILE_ONLY "TRUE")\n')
740
+
741
+ # Output directory
742
+ target_output_directory = spec.get('product_dir')
743
+ if target_output_directory is None:
744
+ if target_type in ('executable', 'loadable_module'):
745
+ target_output_directory = generator_default_variables['PRODUCT_DIR']
746
+ elif target_type in ('shared_library'):
747
+ target_output_directory = '${builddir}/lib.${TOOLSET}'
748
+ elif spec.get('standalone_static_library', False):
749
+ target_output_directory = generator_default_variables['PRODUCT_DIR']
750
+ else:
751
+ base_path = gyp.common.RelativePath(os.path.dirname(gyp_file),
752
+ options.toplevel_dir)
753
+ target_output_directory = '${obj}.${TOOLSET}'
754
+ target_output_directory = (
755
+ os.path.join(target_output_directory, base_path))
756
+
757
+ cmake_target_output_directory = NormjoinPathForceCMakeSource(
758
+ path_from_cmakelists_to_gyp,
759
+ target_output_directory)
760
+ SetTargetProperty(output,
761
+ cmake_target_name,
762
+ cmake_target_type.property_modifier + '_OUTPUT_DIRECTORY',
763
+ cmake_target_output_directory)
764
+
765
+ # Output name
766
+ default_product_prefix = ''
767
+ default_product_name = target_name
768
+ default_product_ext = ''
769
+ if target_type == 'static_library':
770
+ static_library_prefix = generator_default_variables['STATIC_LIB_PREFIX']
771
+ default_product_name = RemovePrefix(default_product_name,
772
+ static_library_prefix)
773
+ default_product_prefix = static_library_prefix
774
+ default_product_ext = generator_default_variables['STATIC_LIB_SUFFIX']
775
+
776
+ elif target_type in ('loadable_module', 'shared_library'):
777
+ shared_library_prefix = generator_default_variables['SHARED_LIB_PREFIX']
778
+ default_product_name = RemovePrefix(default_product_name,
779
+ shared_library_prefix)
780
+ default_product_prefix = shared_library_prefix
781
+ default_product_ext = generator_default_variables['SHARED_LIB_SUFFIX']
782
+
783
+ elif target_type != 'executable':
784
+ print ('ERROR: What output file should be generated?',
785
+ 'type', target_type, 'target', target_name)
786
+
787
+ product_prefix = spec.get('product_prefix', default_product_prefix)
788
+ product_name = spec.get('product_name', default_product_name)
789
+ product_ext = spec.get('product_extension')
790
+ if product_ext:
791
+ product_ext = '.' + product_ext
792
+ else:
793
+ product_ext = default_product_ext
794
+
795
+ SetTargetProperty(output, cmake_target_name, 'PREFIX', product_prefix)
796
+ SetTargetProperty(output, cmake_target_name,
797
+ cmake_target_type.property_modifier + '_OUTPUT_NAME',
798
+ product_name)
799
+ SetTargetProperty(output, cmake_target_name, 'SUFFIX', product_ext)
800
+
801
+ # Make the output of this target referenceable as a source.
802
+ cmake_target_output_basename = product_prefix + product_name + product_ext
803
+ cmake_target_output = os.path.join(cmake_target_output_directory,
804
+ cmake_target_output_basename)
805
+ SetFileProperty(output, cmake_target_output, 'GENERATED', ['TRUE'], '')
806
+
807
+ # Let CMake know if the 'all' target should depend on this target.
808
+ exclude_from_all = ('TRUE' if qualified_target not in all_qualified_targets
809
+ else 'FALSE')
810
+ SetTargetProperty(output, cmake_target_name,
811
+ 'EXCLUDE_FROM_ALL', exclude_from_all)
812
+ for extra_target_name in extra_deps:
813
+ SetTargetProperty(output, extra_target_name,
814
+ 'EXCLUDE_FROM_ALL', exclude_from_all)
815
+
816
+ # Includes
817
+ includes = config.get('include_dirs')
818
+ if includes:
819
+ # This (target include directories) is what requires CMake 2.8.8
820
+ includes_name = cmake_target_name + '__include_dirs'
821
+ SetVariableList(output, includes_name,
822
+ [NormjoinPathForceCMakeSource(path_from_cmakelists_to_gyp, include)
823
+ for include in includes])
824
+ output.write('set_property(TARGET ')
825
+ output.write(cmake_target_name)
826
+ output.write(' APPEND PROPERTY INCLUDE_DIRECTORIES ')
827
+ WriteVariable(output, includes_name, '')
828
+ output.write(')\n')
829
+
830
+ # Defines
831
+ defines = config.get('defines')
832
+ if defines is not None:
833
+ SetTargetProperty(output,
834
+ cmake_target_name,
835
+ 'COMPILE_DEFINITIONS',
836
+ defines,
837
+ ';')
838
+
839
+ # Compile Flags - http://www.cmake.org/Bug/view.php?id=6493
840
+ # CMake currently does not have target C and CXX flags.
841
+ # So, instead of doing...
842
+
843
+ # cflags_c = config.get('cflags_c')
844
+ # if cflags_c is not None:
845
+ # SetTargetProperty(output, cmake_target_name,
846
+ # 'C_COMPILE_FLAGS', cflags_c, ' ')
847
+
848
+ # cflags_cc = config.get('cflags_cc')
849
+ # if cflags_cc is not None:
850
+ # SetTargetProperty(output, cmake_target_name,
851
+ # 'CXX_COMPILE_FLAGS', cflags_cc, ' ')
852
+
853
+ # Instead we must...
854
+ s_sources = []
855
+ c_sources = []
856
+ cxx_sources = []
857
+ for src in srcs:
858
+ _, ext = os.path.splitext(src)
859
+ src_type = COMPILABLE_EXTENSIONS.get(ext, None)
860
+
861
+ if src_type == 's':
862
+ s_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src))
863
+
864
+ if src_type == 'cc':
865
+ c_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src))
866
+
867
+ if src_type == 'cxx':
868
+ cxx_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src))
869
+
870
+ for extra_source in extra_sources:
871
+ src, real_source = extra_source
872
+ _, ext = os.path.splitext(real_source)
873
+ src_type = COMPILABLE_EXTENSIONS.get(ext, None)
874
+
875
+ if src_type == 's':
876
+ s_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src))
877
+
878
+ if src_type == 'cc':
879
+ c_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src))
880
+
881
+ if src_type == 'cxx':
882
+ cxx_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src))
883
+
884
+ cflags = config.get('cflags', [])
885
+ cflags_c = config.get('cflags_c', [])
886
+ cflags_cxx = config.get('cflags_cc', [])
887
+ if c_sources and not (s_sources or cxx_sources):
888
+ flags = []
889
+ flags.extend(cflags)
890
+ flags.extend(cflags_c)
891
+ SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ')
892
+
893
+ elif cxx_sources and not (s_sources or c_sources):
894
+ flags = []
895
+ flags.extend(cflags)
896
+ flags.extend(cflags_cxx)
897
+ SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ')
898
+
899
+ else:
900
+ if s_sources and cflags:
901
+ SetFilesProperty(output, s_sources, 'COMPILE_FLAGS', cflags, ' ')
902
+
903
+ if c_sources and (cflags or cflags_c):
904
+ flags = []
905
+ flags.extend(cflags)
906
+ flags.extend(cflags_c)
907
+ SetFilesProperty(output, c_sources, 'COMPILE_FLAGS', flags, ' ')
908
+
909
+ if cxx_sources and (cflags or cflags_cxx):
910
+ flags = []
911
+ flags.extend(cflags)
912
+ flags.extend(cflags_cxx)
913
+ SetFilesProperty(output, cxx_sources, 'COMPILE_FLAGS', flags, ' ')
914
+
915
+ # Have assembly link as c if there are no other files
916
+ if not c_sources and not cxx_sources and s_sources:
917
+ SetTargetProperty(output, cmake_target_name, 'LINKER_LANGUAGE', ['C'])
918
+
919
+ # Linker flags
920
+ ldflags = config.get('ldflags')
921
+ if ldflags is not None:
922
+ SetTargetProperty(output, cmake_target_name, 'LINK_FLAGS', ldflags, ' ')
923
+
924
+ # Note on Dependencies and Libraries:
925
+ # CMake wants to handle link order, resolving the link line up front.
926
+ # Gyp does not retain or enforce specifying enough information to do so.
927
+ # So do as other gyp generators and use --start-group and --end-group.
928
+ # Give CMake as little information as possible so that it doesn't mess it up.
929
+
930
+ # Dependencies
931
+ rawDeps = spec.get('dependencies', [])
932
+
933
+ static_deps = []
934
+ shared_deps = []
935
+ other_deps = []
936
+ for rawDep in rawDeps:
937
+ dep_cmake_name = namer.CreateCMakeTargetName(rawDep)
938
+ dep_spec = target_dicts.get(rawDep, {})
939
+ dep_target_type = dep_spec.get('type', None)
940
+
941
+ if dep_target_type == 'static_library':
942
+ static_deps.append(dep_cmake_name)
943
+ elif dep_target_type == 'shared_library':
944
+ shared_deps.append(dep_cmake_name)
945
+ else:
946
+ other_deps.append(dep_cmake_name)
947
+
948
+ # ensure all external dependencies are complete before internal dependencies
949
+ # extra_deps currently only depend on their own deps, so otherwise run early
950
+ if static_deps or shared_deps or other_deps:
951
+ for extra_dep in extra_deps:
952
+ output.write('add_dependencies(')
953
+ output.write(extra_dep)
954
+ output.write('\n')
955
+ for deps in (static_deps, shared_deps, other_deps):
956
+ for dep in gyp.common.uniquer(deps):
957
+ output.write(' ')
958
+ output.write(dep)
959
+ output.write('\n')
960
+ output.write(')\n')
961
+
962
+ linkable = target_type in ('executable', 'loadable_module', 'shared_library')
963
+ other_deps.extend(extra_deps)
964
+ if other_deps or (not linkable and (static_deps or shared_deps)):
965
+ output.write('add_dependencies(')
966
+ output.write(cmake_target_name)
967
+ output.write('\n')
968
+ for dep in gyp.common.uniquer(other_deps):
969
+ output.write(' ')
970
+ output.write(dep)
971
+ output.write('\n')
972
+ if not linkable:
973
+ for deps in (static_deps, shared_deps):
974
+ for lib_dep in gyp.common.uniquer(deps):
975
+ output.write(' ')
976
+ output.write(lib_dep)
977
+ output.write('\n')
978
+ output.write(')\n')
979
+
980
+ # Libraries
981
+ if linkable:
982
+ external_libs = [lib for lib in spec.get('libraries', []) if len(lib) > 0]
983
+ if external_libs or static_deps or shared_deps:
984
+ output.write('target_link_libraries(')
985
+ output.write(cmake_target_name)
986
+ output.write('\n')
987
+ if static_deps:
988
+ write_group = circular_libs and len(static_deps) > 1
989
+ if write_group:
990
+ output.write('-Wl,--start-group\n')
991
+ for dep in gyp.common.uniquer(static_deps):
992
+ output.write(' ')
993
+ output.write(dep)
994
+ output.write('\n')
995
+ if write_group:
996
+ output.write('-Wl,--end-group\n')
997
+ if shared_deps:
998
+ for dep in gyp.common.uniquer(shared_deps):
999
+ output.write(' ')
1000
+ output.write(dep)
1001
+ output.write('\n')
1002
+ if external_libs:
1003
+ for lib in gyp.common.uniquer(external_libs):
1004
+ output.write(' ')
1005
+ output.write(lib)
1006
+ output.write('\n')
1007
+
1008
+ output.write(')\n')
1009
+
1010
+ UnsetVariable(output, 'TOOLSET')
1011
+ UnsetVariable(output, 'TARGET')
1012
+
1013
+
1014
+ def GenerateOutputForConfig(target_list, target_dicts, data,
1015
+ params, config_to_use):
1016
+ options = params['options']
1017
+ generator_flags = params['generator_flags']
1018
+
1019
+ # generator_dir: relative path from pwd to where make puts build files.
1020
+ # Makes migrating from make to cmake easier, cmake doesn't put anything here.
1021
+ # Each Gyp configuration creates a different CMakeLists.txt file
1022
+ # to avoid incompatibilities between Gyp and CMake configurations.
1023
+ generator_dir = os.path.relpath(options.generator_output or '.')
1024
+
1025
+ # output_dir: relative path from generator_dir to the build directory.
1026
+ output_dir = generator_flags.get('output_dir', 'out')
1027
+
1028
+ # build_dir: relative path from source root to our output files.
1029
+ # e.g. "out/Debug"
1030
+ build_dir = os.path.normpath(os.path.join(generator_dir,
1031
+ output_dir,
1032
+ config_to_use))
1033
+
1034
+ toplevel_build = os.path.join(options.toplevel_dir, build_dir)
1035
+
1036
+ output_file = os.path.join(toplevel_build, 'CMakeLists.txt')
1037
+ gyp.common.EnsureDirExists(output_file)
1038
+
1039
+ output = open(output_file, 'w')
1040
+ output.write('cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)\n')
1041
+ output.write('cmake_policy(VERSION 2.8.8)\n')
1042
+
1043
+ _, project_target, _ = gyp.common.ParseQualifiedTarget(target_list[-1])
1044
+ output.write('project(')
1045
+ output.write(project_target)
1046
+ output.write(')\n')
1047
+
1048
+ SetVariable(output, 'configuration', config_to_use)
1049
+
1050
+ # The following appears to be as-yet undocumented.
1051
+ # http://public.kitware.com/Bug/view.php?id=8392
1052
+ output.write('enable_language(ASM)\n')
1053
+ # ASM-ATT does not support .S files.
1054
+ # output.write('enable_language(ASM-ATT)\n')
1055
+
1056
+ SetVariable(output, 'builddir', '${CMAKE_BINARY_DIR}')
1057
+ SetVariable(output, 'obj', '${builddir}/obj')
1058
+ output.write('\n')
1059
+
1060
+ # TODO: Undocumented/unsupported (the CMake Java generator depends on it).
1061
+ # CMake by default names the object resulting from foo.c to be foo.c.o.
1062
+ # Gyp traditionally names the object resulting from foo.c foo.o.
1063
+ # This should be irrelevant, but some targets extract .o files from .a
1064
+ # and depend on the name of the extracted .o files.
1065
+ output.write('set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)\n')
1066
+ output.write('set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)\n')
1067
+ output.write('\n')
1068
+
1069
+ namer = CMakeNamer(target_list)
1070
+
1071
+ # The list of targets upon which the 'all' target should depend.
1072
+ # CMake has it's own implicit 'all' target, one is not created explicitly.
1073
+ all_qualified_targets = set()
1074
+ for build_file in params['build_files']:
1075
+ for qualified_target in gyp.common.AllTargets(target_list,
1076
+ target_dicts,
1077
+ os.path.normpath(build_file)):
1078
+ all_qualified_targets.add(qualified_target)
1079
+
1080
+ for qualified_target in target_list:
1081
+ WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
1082
+ options, generator_flags, all_qualified_targets, output)
1083
+
1084
+ output.close()
1085
+
1086
+
1087
+ def PerformBuild(data, configurations, params):
1088
+ options = params['options']
1089
+ generator_flags = params['generator_flags']
1090
+
1091
+ # generator_dir: relative path from pwd to where make puts build files.
1092
+ # Makes migrating from make to cmake easier, cmake doesn't put anything here.
1093
+ generator_dir = os.path.relpath(options.generator_output or '.')
1094
+
1095
+ # output_dir: relative path from generator_dir to the build directory.
1096
+ output_dir = generator_flags.get('output_dir', 'out')
1097
+
1098
+ for config_name in configurations:
1099
+ # build_dir: relative path from source root to our output files.
1100
+ # e.g. "out/Debug"
1101
+ build_dir = os.path.normpath(os.path.join(generator_dir,
1102
+ output_dir,
1103
+ config_name))
1104
+ arguments = ['cmake', '-G', 'Ninja']
1105
+ print 'Generating [%s]: %s' % (config_name, arguments)
1106
+ subprocess.check_call(arguments, cwd=build_dir)
1107
+
1108
+ arguments = ['ninja', '-C', build_dir]
1109
+ print 'Building [%s]: %s' % (config_name, arguments)
1110
+ subprocess.check_call(arguments)
1111
+
1112
+
1113
+ def CallGenerateOutputForConfig(arglist):
1114
+ # Ignore the interrupt signal so that the parent process catches it and
1115
+ # kills all multiprocessing children.
1116
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
1117
+
1118
+ target_list, target_dicts, data, params, config_name = arglist
1119
+ GenerateOutputForConfig(target_list, target_dicts, data, params, config_name)
1120
+
1121
+
1122
+ def GenerateOutput(target_list, target_dicts, data, params):
1123
+ user_config = params.get('generator_flags', {}).get('config', None)
1124
+ if user_config:
1125
+ GenerateOutputForConfig(target_list, target_dicts, data,
1126
+ params, user_config)
1127
+ else:
1128
+ config_names = target_dicts[target_list[0]]['configurations'].keys()
1129
+ if params['parallel']:
1130
+ try:
1131
+ pool = multiprocessing.Pool(len(config_names))
1132
+ arglists = []
1133
+ for config_name in config_names:
1134
+ arglists.append((target_list, target_dicts, data,
1135
+ params, config_name))
1136
+ pool.map(CallGenerateOutputForConfig, arglists)
1137
+ except KeyboardInterrupt, e:
1138
+ pool.terminate()
1139
+ raise e
1140
+ else:
1141
+ for config_name in config_names:
1142
+ GenerateOutputForConfig(target_list, target_dicts, data,
1143
+ params, config_name)