Chromium Code Reviews| Index: pylib/gyp/generator/cmake.py |
| diff --git a/pylib/gyp/generator/cmake.py b/pylib/gyp/generator/cmake.py |
| index 8f5feddee1cb353147cb9df51ddb2c81684a0975..cd6f46260f92867a7c5c17dd6bab02227aed709d 100644 |
| --- a/pylib/gyp/generator/cmake.py |
| +++ b/pylib/gyp/generator/cmake.py |
| @@ -150,20 +150,17 @@ def SetFileProperty(output, source_name, property_name, values, sep): |
| output.write('")\n') |
| -def SetFilesProperty(output, source_names, property_name, values, sep): |
| +def SetFilesProperty(output, variable, property_name, values, sep): |
| """Given a set of source files, sets the given property on them.""" |
| - output.write('set_source_files_properties(\n') |
| - for source_name in source_names: |
| - output.write(' ') |
| - output.write(source_name) |
| - output.write('\n') |
| - output.write(' PROPERTIES\n ') |
| + output.write('set_source_files_properties(') |
| + WriteVariable(output, variable) |
| + output.write(' PROPERTIES ') |
| output.write(property_name) |
| output.write(' "') |
| for value in values: |
| output.write(CMakeStringEscape(value)) |
| output.write(sep) |
| - output.write('"\n)\n') |
| + output.write('")\n') |
| def SetTargetProperty(output, target_name, property_name, values, sep=''): |
| @@ -236,11 +233,11 @@ def StringToCMakeTargetName(a): |
| """Converts the given string 'a' to a valid CMake target name. |
| All invalid characters are replaced by '_'. |
| - Invalid for cmake: ' ', '/', '(', ')' |
| + Invalid for cmake: ' ', '/', '(', ')', '"' |
| Invalid for make: ':' |
| Invalid for unknown reasons but cause failures: '.' |
| """ |
| - return a.translate(string.maketrans(' /():.', '______')) |
| + return a.translate(string.maketrans(' /():."', '_______')) |
| def WriteActions(target_name, actions, extra_sources, extra_deps, |
| @@ -640,6 +637,12 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, |
| target_type = spec.get('type', '<missing target type>') |
| target_toolset = spec.get('toolset') |
| + cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type) |
| + if cmake_target_type is None: |
| + print ('Target %s has unknown target type %s, skipping.' % |
| + ( target_name, target_type ) ) |
| + return |
| + |
| SetVariable(output, 'TARGET', target_name) |
| SetVariable(output, 'TOOLSET', target_toolset) |
| @@ -667,27 +670,78 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, |
| srcs = spec.get('sources', []) |
| # Gyp separates the sheep from the goats based on file extensions. |
| - def partition(l, p): |
| - return reduce(lambda x, e: x[not p(e)].append(e) or x, l, ([], [])) |
| - compilable_srcs, other_srcs = partition(srcs, Compilable) |
| + # A full separation is done here because of flag handing (see below). |
| + s_sources = [] |
| + c_sources = [] |
| + cxx_sources = [] |
| + other_sources = [] |
| + for src in srcs: |
| + _, ext = os.path.splitext(src) |
| + src_type = COMPILABLE_EXTENSIONS.get(ext, None) |
| + src_norm_path = NormjoinPath(path_from_cmakelists_to_gyp, src); |
| - # CMake gets upset when executable targets provide no sources. |
| - if target_type == 'executable' and not compilable_srcs and not extra_sources: |
| - print ('Executable %s has no complilable sources, treating as "none".' % |
| - target_name ) |
| - target_type = 'none' |
| + if src_type == 's': |
| + s_sources.append(src_norm_path) |
| + elif src_type == 'cc': |
| + c_sources.append(src_norm_path) |
| + elif src_type == 'cxx': |
| + cxx_sources.append(src_norm_path) |
| + else: |
| + other_sources.append(src_norm_path) |
| - cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type) |
| - if cmake_target_type is None: |
| - print ('Target %s has unknown target type %s, skipping.' % |
| - ( target_name, target_type ) ) |
| - return |
| + for extra_source in extra_sources: |
| + src, real_source = extra_source |
| + _, ext = os.path.splitext(real_source) |
| + src_type = COMPILABLE_EXTENSIONS.get(ext, None) |
| + |
| + if src_type == 's': |
| + s_sources.append(src) |
| + elif src_type == 'cc': |
| + c_sources.append(src) |
| + elif src_type == 'cxx': |
| + cxx_sources.append(src) |
| + else: |
| + other_sources.append(src) |
| + |
| + s_sources_name = None |
| + if s_sources: |
| + s_sources_name = cmake_target_name + '__asm_srcs' |
| + SetVariableList(output, s_sources_name, s_sources) |
| + |
| + c_sources_name = None |
| + if c_sources: |
| + c_sources_name = cmake_target_name + '__c_srcs' |
| + SetVariableList(output, c_sources_name, c_sources) |
| + |
| + cxx_sources_name = None |
| + if cxx_sources: |
| + cxx_sources_name = cmake_target_name + '__cxx_srcs' |
| + SetVariableList(output, cxx_sources_name, cxx_sources) |
| + |
| + other_sources_name = None |
| + if other_sources: |
| + other_sources_name = cmake_target_name + '__other_srcs' |
| + SetVariableList(output, other_sources_name, other_sources) |
| + |
| + # CMake gets upset when executable targets provide no sources. |
| + # http://www.cmake.org/pipermail/cmake/2010-July/038461.html |
| + dummy_sources_name = None |
| + has_sources = (s_sources_name or |
| + c_sources_name or |
| + cxx_sources_name or |
| + other_sources_name) |
| + if target_type == 'executable' and not has_sources: |
|
Nico
2015/05/27 20:11:49
Does this ever happen? I'd expect other generators
|
| + dummy_sources_name = cmake_target_name + '__dummy_srcs' |
| + SetVariable(output, dummy_sources_name, |
| + "${obj}.${TOOLSET}/${TARGET}/genc/dummy.c") |
| + output.write('if(NOT EXISTS "') |
| + WriteVariable(output, dummy_sources_name) |
| + output.write('")\n') |
| + output.write(' file(WRITE "') |
| + WriteVariable(output, dummy_sources_name) |
| + output.write('" "")\n') |
| + output.write("endif()\n") |
| - other_srcs_name = None |
| - if other_srcs: |
| - other_srcs_name = cmake_target_name + '__other_srcs' |
| - SetVariableList(output, other_srcs_name, |
| - [NormjoinPath(path_from_cmakelists_to_gyp, src) for src in other_srcs]) |
| # CMake is opposed to setting linker directories and considers the practice |
| # of setting linker directories dangerous. Instead, it favors the use of |
| @@ -713,29 +767,25 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, |
| output.write(' ') |
| output.write(cmake_target_type.modifier) |
| - if other_srcs_name: |
| - WriteVariable(output, other_srcs_name, ' ') |
| - |
| - output.write('\n') |
| - |
| - for src in compilable_srcs: |
| - output.write(' ') |
| - output.write(NormjoinPath(path_from_cmakelists_to_gyp, src)) |
| - output.write('\n') |
| - for extra_source in extra_sources: |
| - output.write(' ') |
| - src, _ = extra_source |
| - output.write(NormjoinPath(path_from_cmakelists_to_gyp, src)) |
| - output.write('\n') |
| + if s_sources_name: |
| + WriteVariable(output, s_sources_name, ' ') |
| + if c_sources_name: |
| + WriteVariable(output, c_sources_name, ' ') |
| + if cxx_sources_name: |
| + WriteVariable(output, cxx_sources_name, ' ') |
| + if other_sources_name: |
| + WriteVariable(output, other_sources_name, ' ') |
| + if dummy_sources_name: |
| + WriteVariable(output, dummy_sources_name, ' ') |
| output.write(')\n') |
| # Output name and location. |
| if target_type != 'none': |
| # Mark uncompiled sources as uncompiled. |
| - if other_srcs_name: |
| + if other_sources_name: |
| output.write('set_source_files_properties(') |
| - WriteVariable(output, other_srcs_name, '') |
| + WriteVariable(output, other_sources_name, '') |
| output.write(' PROPERTIES HEADER_FILE_ONLY "TRUE")\n') |
| # Output directory |
| @@ -851,40 +901,13 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, |
| # 'CXX_COMPILE_FLAGS', cflags_cc, ' ') |
| # Instead we must... |
| - s_sources = [] |
| - c_sources = [] |
| - cxx_sources = [] |
| - for src in srcs: |
| - _, ext = os.path.splitext(src) |
| - src_type = COMPILABLE_EXTENSIONS.get(ext, None) |
| - |
| - if src_type == 's': |
| - s_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) |
| - |
| - if src_type == 'cc': |
| - c_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) |
| - |
| - if src_type == 'cxx': |
| - cxx_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) |
| - |
| - for extra_source in extra_sources: |
| - src, real_source = extra_source |
| - _, ext = os.path.splitext(real_source) |
| - src_type = COMPILABLE_EXTENSIONS.get(ext, None) |
| - |
| - if src_type == 's': |
| - s_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) |
| - |
| - if src_type == 'cc': |
| - c_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) |
| - |
| - if src_type == 'cxx': |
| - cxx_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) |
| - |
| cflags = config.get('cflags', []) |
| cflags_c = config.get('cflags_c', []) |
| cflags_cxx = config.get('cflags_cc', []) |
| - if c_sources and not (s_sources or cxx_sources): |
| + if (not cflags_c or not c_sources) and (not cflags_cxx or not cxx_sources): |
| + SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', cflags, ' ') |
| + |
| + elif c_sources and not (s_sources or cxx_sources): |
| flags = [] |
| flags.extend(cflags) |
| flags.extend(cflags_c) |
| @@ -898,22 +921,22 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, |
| else: |
| if s_sources and cflags: |
| - SetFilesProperty(output, s_sources, 'COMPILE_FLAGS', cflags, ' ') |
| + SetFilesProperty(output, s_sources_name, 'COMPILE_FLAGS', cflags, ' ') |
| if c_sources and (cflags or cflags_c): |
| flags = [] |
| flags.extend(cflags) |
| flags.extend(cflags_c) |
| - SetFilesProperty(output, c_sources, 'COMPILE_FLAGS', flags, ' ') |
| + SetFilesProperty(output, c_sources_name, 'COMPILE_FLAGS', flags, ' ') |
| if cxx_sources and (cflags or cflags_cxx): |
| flags = [] |
| flags.extend(cflags) |
| flags.extend(cflags_cxx) |
| - SetFilesProperty(output, cxx_sources, 'COMPILE_FLAGS', flags, ' ') |
| + SetFilesProperty(output, cxx_sources_name, 'COMPILE_FLAGS', flags, ' ') |
| - # Have assembly link as c if there are no other files |
| - if not c_sources and not cxx_sources and s_sources: |
| + # Link as 'C' if there are no other files |
| + if not c_sources and not cxx_sources: |
| SetTargetProperty(output, cmake_target_name, 'LINKER_LANGUAGE', ['C']) |
| # Linker flags |
| @@ -1047,12 +1070,32 @@ def GenerateOutputForConfig(target_list, target_dicts, data, |
| SetVariable(output, 'configuration', config_to_use) |
| + cc = None |
| + cxx = None |
| + ar = None |
| + |
| + #TODO: support make_global_settings |
| + |
| + cc = gyp.common.GetEnvironFallback(['CC_target', 'CC'], cc) |
| + cxx = gyp.common.GetEnvironFallback(['CXX_target', 'CXX'], cxx) |
| + ar = gyp.common.GetEnvironFallback(['AR_target', 'AR'], ar) |
| + |
| + if cc: |
| + SetVariable(output, 'CMAKE_C_COMPILER', cc) |
| + if cxx: |
| + SetVariable(output, 'CMAKE_CXX_COMPILER', cxx) |
| + if ar: |
| + SetVariable(output, 'CMAKE_AR', ar) |
| + |
| # The following appears to be as-yet undocumented. |
| # http://public.kitware.com/Bug/view.php?id=8392 |
| output.write('enable_language(ASM)\n') |
| # ASM-ATT does not support .S files. |
| # output.write('enable_language(ASM-ATT)\n') |
| + if cc: |
| + SetVariable(output, 'CMAKE_ASM_COMPILER', cc) |
| + |
| SetVariable(output, 'builddir', '${CMAKE_BINARY_DIR}') |
| SetVariable(output, 'obj', '${builddir}/obj') |
| output.write('\n') |