OLD | NEW |
1 # Copyright (c) 2013 Google Inc. All rights reserved. | 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 | 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 """cmake output module | 5 """cmake output module |
6 | 6 |
7 This module is under development and should be considered experimental. | 7 This module is under development and should be considered experimental. |
8 | 8 |
9 This module produces cmake (2.8.8+) input as its output. One CMakeLists.txt is | 9 This module produces cmake (2.8.8+) input as its output. One CMakeLists.txt is |
10 created for each configuration. | 10 created for each configuration. |
(...skipping 16 matching lines...) Expand all Loading... |
27 not be able to find the header file directories described in the generated | 27 not be able to find the header file directories described in the generated |
28 CMakeLists.txt file. | 28 CMakeLists.txt file. |
29 """ | 29 """ |
30 | 30 |
31 import multiprocessing | 31 import multiprocessing |
32 import os | 32 import os |
33 import signal | 33 import signal |
34 import string | 34 import string |
35 import subprocess | 35 import subprocess |
36 import gyp.common | 36 import gyp.common |
| 37 import gyp.xcode_emulation |
37 | 38 |
38 generator_default_variables = { | 39 generator_default_variables = { |
39 'EXECUTABLE_PREFIX': '', | 40 'EXECUTABLE_PREFIX': '', |
40 'EXECUTABLE_SUFFIX': '', | 41 'EXECUTABLE_SUFFIX': '', |
41 'STATIC_LIB_PREFIX': 'lib', | 42 'STATIC_LIB_PREFIX': 'lib', |
42 'STATIC_LIB_SUFFIX': '.a', | 43 'STATIC_LIB_SUFFIX': '.a', |
43 'SHARED_LIB_PREFIX': 'lib', | 44 'SHARED_LIB_PREFIX': 'lib', |
44 'SHARED_LIB_SUFFIX': '.so', | 45 'SHARED_LIB_SUFFIX': '.so', |
45 'SHARED_LIB_DIR': '${builddir}/lib.${TOOLSET}', | 46 'SHARED_LIB_DIR': '${builddir}/lib.${TOOLSET}', |
46 'LIB_DIR': '${obj}.${TOOLSET}', | 47 'LIB_DIR': '${obj}.${TOOLSET}', |
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
601 self.cmake_target_base_names_conficting.add(cmake_target_base_name) | 602 self.cmake_target_base_names_conficting.add(cmake_target_base_name) |
602 | 603 |
603 def CreateCMakeTargetName(self, qualified_target): | 604 def CreateCMakeTargetName(self, qualified_target): |
604 base_name = CreateCMakeTargetBaseName(qualified_target) | 605 base_name = CreateCMakeTargetBaseName(qualified_target) |
605 if base_name in self.cmake_target_base_names_conficting: | 606 if base_name in self.cmake_target_base_names_conficting: |
606 return CreateCMakeTargetFullName(qualified_target) | 607 return CreateCMakeTargetFullName(qualified_target) |
607 return base_name | 608 return base_name |
608 | 609 |
609 | 610 |
610 def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, | 611 def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, |
611 options, generator_flags, all_qualified_targets, output): | 612 options, generator_flags, all_qualified_targets, flavor, |
612 | 613 output): |
613 # The make generator does this always. | 614 # The make generator does this always. |
614 # TODO: It would be nice to be able to tell CMake all dependencies. | 615 # TODO: It would be nice to be able to tell CMake all dependencies. |
615 circular_libs = generator_flags.get('circular', True) | 616 circular_libs = generator_flags.get('circular', True) |
616 | 617 |
617 if not generator_flags.get('standalone', False): | 618 if not generator_flags.get('standalone', False): |
618 output.write('\n#') | 619 output.write('\n#') |
619 output.write(qualified_target) | 620 output.write(qualified_target) |
620 output.write('\n') | 621 output.write('\n') |
621 | 622 |
622 gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target) | 623 gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target) |
623 rel_gyp_file = gyp.common.RelativePath(gyp_file, options.toplevel_dir) | 624 rel_gyp_file = gyp.common.RelativePath(gyp_file, options.toplevel_dir) |
624 rel_gyp_dir = os.path.dirname(rel_gyp_file) | 625 rel_gyp_dir = os.path.dirname(rel_gyp_file) |
625 | 626 |
626 # Relative path from build dir to top dir. | 627 # Relative path from build dir to top dir. |
627 build_to_top = gyp.common.InvertRelativePath(build_dir, options.toplevel_dir) | 628 build_to_top = gyp.common.InvertRelativePath(build_dir, options.toplevel_dir) |
628 # Relative path from build dir to gyp dir. | 629 # Relative path from build dir to gyp dir. |
629 build_to_gyp = os.path.join(build_to_top, rel_gyp_dir) | 630 build_to_gyp = os.path.join(build_to_top, rel_gyp_dir) |
630 | 631 |
631 path_from_cmakelists_to_gyp = build_to_gyp | 632 path_from_cmakelists_to_gyp = build_to_gyp |
632 | 633 |
633 spec = target_dicts.get(qualified_target, {}) | 634 spec = target_dicts.get(qualified_target, {}) |
634 config = spec.get('configurations', {}).get(config_to_use, {}) | 635 config = spec.get('configurations', {}).get(config_to_use, {}) |
635 | 636 |
| 637 xcode_settings = None |
| 638 if flavor == 'mac': |
| 639 xcode_settings = gyp.xcode_emulation.XcodeSettings(spec) |
| 640 |
636 target_name = spec.get('target_name', '<missing target name>') | 641 target_name = spec.get('target_name', '<missing target name>') |
637 target_type = spec.get('type', '<missing target type>') | 642 target_type = spec.get('type', '<missing target type>') |
638 target_toolset = spec.get('toolset') | 643 target_toolset = spec.get('toolset') |
639 | 644 |
640 cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type) | 645 cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type) |
641 if cmake_target_type is None: | 646 if cmake_target_type is None: |
642 print ('Target %s has unknown target type %s, skipping.' % | 647 print ('Target %s has unknown target type %s, skipping.' % |
643 ( target_name, target_type ) ) | 648 ( target_name, target_type ) ) |
644 return | 649 return |
645 | 650 |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
897 output.write('set_property(TARGET ') | 902 output.write('set_property(TARGET ') |
898 output.write(cmake_target_name) | 903 output.write(cmake_target_name) |
899 output.write(' APPEND PROPERTY INCLUDE_DIRECTORIES ') | 904 output.write(' APPEND PROPERTY INCLUDE_DIRECTORIES ') |
900 WriteVariable(output, includes_name, '') | 905 WriteVariable(output, includes_name, '') |
901 output.write(')\n') | 906 output.write(')\n') |
902 | 907 |
903 # Defines | 908 # Defines |
904 defines = config.get('defines') | 909 defines = config.get('defines') |
905 if defines is not None: | 910 if defines is not None: |
906 SetTargetProperty(output, | 911 SetTargetProperty(output, |
907 cmake_target_name, | 912 cmake_target_name, |
908 'COMPILE_DEFINITIONS', | 913 'COMPILE_DEFINITIONS', |
909 defines, | 914 defines, |
910 ';') | 915 ';') |
911 | 916 |
912 # Compile Flags - http://www.cmake.org/Bug/view.php?id=6493 | 917 # Compile Flags - http://www.cmake.org/Bug/view.php?id=6493 |
913 # CMake currently does not have target C and CXX flags. | 918 # CMake currently does not have target C and CXX flags. |
914 # So, instead of doing... | 919 # So, instead of doing... |
915 | 920 |
916 # cflags_c = config.get('cflags_c') | 921 # cflags_c = config.get('cflags_c') |
917 # if cflags_c is not None: | 922 # if cflags_c is not None: |
918 # SetTargetProperty(output, cmake_target_name, | 923 # SetTargetProperty(output, cmake_target_name, |
919 # 'C_COMPILE_FLAGS', cflags_c, ' ') | 924 # 'C_COMPILE_FLAGS', cflags_c, ' ') |
920 | 925 |
921 # cflags_cc = config.get('cflags_cc') | 926 # cflags_cc = config.get('cflags_cc') |
922 # if cflags_cc is not None: | 927 # if cflags_cc is not None: |
923 # SetTargetProperty(output, cmake_target_name, | 928 # SetTargetProperty(output, cmake_target_name, |
924 # 'CXX_COMPILE_FLAGS', cflags_cc, ' ') | 929 # 'CXX_COMPILE_FLAGS', cflags_cc, ' ') |
925 | 930 |
926 # Instead we must... | 931 # Instead we must... |
927 cflags = config.get('cflags', []) | 932 cflags = config.get('cflags', []) |
928 cflags_c = config.get('cflags_c', []) | 933 cflags_c = config.get('cflags_c', []) |
929 cflags_cxx = config.get('cflags_cc', []) | 934 cflags_cxx = config.get('cflags_cc', []) |
| 935 if xcode_settings: |
| 936 cflags = xcode_settings.GetCflags(config_to_use) |
| 937 cflags_c = xcode_settings.GetCflagsC(config_to_use) |
| 938 cflags_cxx = xcode_settings.GetCflagsCC(config_to_use) |
| 939 #cflags_objc = xcode_settings.GetCflagsObjC(config_to_use) |
| 940 #cflags_objcc = xcode_settings.GetCflagsObjCC(config_to_use) |
| 941 |
930 if (not cflags_c or not c_sources) and (not cflags_cxx or not cxx_sources): | 942 if (not cflags_c or not c_sources) and (not cflags_cxx or not cxx_sources): |
931 SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', cflags, ' ') | 943 SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', cflags, ' ') |
932 | 944 |
933 elif c_sources and not (s_sources or cxx_sources): | 945 elif c_sources and not (s_sources or cxx_sources): |
934 flags = [] | 946 flags = [] |
935 flags.extend(cflags) | 947 flags.extend(cflags) |
936 flags.extend(cflags_c) | 948 flags.extend(cflags_c) |
937 SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ') | 949 SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ') |
938 | 950 |
939 elif cxx_sources and not (s_sources or c_sources): | 951 elif cxx_sources and not (s_sources or c_sources): |
(...skipping 18 matching lines...) Expand all Loading... |
958 flags = [] | 970 flags = [] |
959 flags.extend(cflags) | 971 flags.extend(cflags) |
960 flags.extend(cflags_cxx) | 972 flags.extend(cflags_cxx) |
961 SetFilesProperty(output, cxx_sources_name, 'COMPILE_FLAGS', flags, ' ') | 973 SetFilesProperty(output, cxx_sources_name, 'COMPILE_FLAGS', flags, ' ') |
962 | 974 |
963 # Linker flags | 975 # Linker flags |
964 ldflags = config.get('ldflags') | 976 ldflags = config.get('ldflags') |
965 if ldflags is not None: | 977 if ldflags is not None: |
966 SetTargetProperty(output, cmake_target_name, 'LINK_FLAGS', ldflags, ' ') | 978 SetTargetProperty(output, cmake_target_name, 'LINK_FLAGS', ldflags, ' ') |
967 | 979 |
| 980 # XCode settings |
| 981 xcode_settings = config.get('xcode_settings', {}) |
| 982 for xcode_setting, xcode_value in xcode_settings.viewitems(): |
| 983 SetTargetProperty(output, cmake_target_name, |
| 984 "XCODE_ATTRIBUTE_%s" % xcode_setting, xcode_value, |
| 985 '' if isinstance(xcode_value, str) else ' ') |
| 986 |
968 # Note on Dependencies and Libraries: | 987 # Note on Dependencies and Libraries: |
969 # CMake wants to handle link order, resolving the link line up front. | 988 # CMake wants to handle link order, resolving the link line up front. |
970 # Gyp does not retain or enforce specifying enough information to do so. | 989 # Gyp does not retain or enforce specifying enough information to do so. |
971 # So do as other gyp generators and use --start-group and --end-group. | 990 # So do as other gyp generators and use --start-group and --end-group. |
972 # Give CMake as little information as possible so that it doesn't mess it up. | 991 # Give CMake as little information as possible so that it doesn't mess it up. |
973 | 992 |
974 # Dependencies | 993 # Dependencies |
975 rawDeps = spec.get('dependencies', []) | 994 rawDeps = spec.get('dependencies', []) |
976 | 995 |
977 static_deps = [] | 996 static_deps = [] |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1022 output.write(')\n') | 1041 output.write(')\n') |
1023 | 1042 |
1024 # Libraries | 1043 # Libraries |
1025 if linkable: | 1044 if linkable: |
1026 external_libs = [lib for lib in spec.get('libraries', []) if len(lib) > 0] | 1045 external_libs = [lib for lib in spec.get('libraries', []) if len(lib) > 0] |
1027 if external_libs or static_deps or shared_deps: | 1046 if external_libs or static_deps or shared_deps: |
1028 output.write('target_link_libraries(') | 1047 output.write('target_link_libraries(') |
1029 output.write(cmake_target_name) | 1048 output.write(cmake_target_name) |
1030 output.write('\n') | 1049 output.write('\n') |
1031 if static_deps: | 1050 if static_deps: |
1032 write_group = circular_libs and len(static_deps) > 1 | 1051 write_group = circular_libs and len(static_deps) > 1 and flavor != 'mac' |
1033 if write_group: | 1052 if write_group: |
1034 output.write('-Wl,--start-group\n') | 1053 output.write('-Wl,--start-group\n') |
1035 for dep in gyp.common.uniquer(static_deps): | 1054 for dep in gyp.common.uniquer(static_deps): |
1036 output.write(' ') | 1055 output.write(' ') |
1037 output.write(dep) | 1056 output.write(dep) |
1038 output.write('\n') | 1057 output.write('\n') |
1039 if write_group: | 1058 if write_group: |
1040 output.write('-Wl,--end-group\n') | 1059 output.write('-Wl,--end-group\n') |
1041 if shared_deps: | 1060 if shared_deps: |
1042 for dep in gyp.common.uniquer(shared_deps): | 1061 for dep in gyp.common.uniquer(shared_deps): |
1043 output.write(' ') | 1062 output.write(' ') |
1044 output.write(dep) | 1063 output.write(dep) |
1045 output.write('\n') | 1064 output.write('\n') |
1046 if external_libs: | 1065 if external_libs: |
1047 for lib in gyp.common.uniquer(external_libs): | 1066 for lib in gyp.common.uniquer(external_libs): |
1048 output.write(' ') | 1067 output.write(' "') |
1049 output.write(lib) | 1068 output.write(RemovePrefix(lib, "$(SDKROOT)")) |
1050 output.write('\n') | 1069 output.write('"\n') |
1051 | 1070 |
1052 output.write(')\n') | 1071 output.write(')\n') |
1053 | 1072 |
1054 UnsetVariable(output, 'TOOLSET') | 1073 UnsetVariable(output, 'TOOLSET') |
1055 UnsetVariable(output, 'TARGET') | 1074 UnsetVariable(output, 'TARGET') |
1056 | 1075 |
1057 | 1076 |
1058 def GenerateOutputForConfig(target_list, target_dicts, data, | 1077 def GenerateOutputForConfig(target_list, target_dicts, data, |
1059 params, config_to_use): | 1078 params, config_to_use): |
1060 options = params['options'] | 1079 options = params['options'] |
1061 generator_flags = params['generator_flags'] | 1080 generator_flags = params['generator_flags'] |
| 1081 flavor = gyp.common.GetFlavor(params) |
1062 | 1082 |
1063 # generator_dir: relative path from pwd to where make puts build files. | 1083 # generator_dir: relative path from pwd to where make puts build files. |
1064 # Makes migrating from make to cmake easier, cmake doesn't put anything here. | 1084 # Makes migrating from make to cmake easier, cmake doesn't put anything here. |
1065 # Each Gyp configuration creates a different CMakeLists.txt file | 1085 # Each Gyp configuration creates a different CMakeLists.txt file |
1066 # to avoid incompatibilities between Gyp and CMake configurations. | 1086 # to avoid incompatibilities between Gyp and CMake configurations. |
1067 generator_dir = os.path.relpath(options.generator_output or '.') | 1087 generator_dir = os.path.relpath(options.generator_output or '.') |
1068 | 1088 |
1069 # output_dir: relative path from generator_dir to the build directory. | 1089 # output_dir: relative path from generator_dir to the build directory. |
1070 output_dir = generator_flags.get('output_dir', 'out') | 1090 output_dir = generator_flags.get('output_dir', 'out') |
1071 | 1091 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1134 # CMake by default names the object resulting from foo.c to be foo.c.o. | 1154 # CMake by default names the object resulting from foo.c to be foo.c.o. |
1135 # Gyp traditionally names the object resulting from foo.c foo.o. | 1155 # Gyp traditionally names the object resulting from foo.c foo.o. |
1136 # This should be irrelevant, but some targets extract .o files from .a | 1156 # This should be irrelevant, but some targets extract .o files from .a |
1137 # and depend on the name of the extracted .o files. | 1157 # and depend on the name of the extracted .o files. |
1138 output.write('set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)\n') | 1158 output.write('set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)\n') |
1139 output.write('set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)\n') | 1159 output.write('set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)\n') |
1140 output.write('\n') | 1160 output.write('\n') |
1141 | 1161 |
1142 # Force ninja to use rsp files. Otherwise link and ar lines can get too long, | 1162 # Force ninja to use rsp files. Otherwise link and ar lines can get too long, |
1143 # resulting in 'Argument list too long' errors. | 1163 # resulting in 'Argument list too long' errors. |
1144 output.write('set(CMAKE_NINJA_FORCE_RESPONSE_FILE 1)\n') | 1164 # However, rsp files don't work correctly on Mac. |
| 1165 if flavor != 'mac': |
| 1166 output.write('set(CMAKE_NINJA_FORCE_RESPONSE_FILE 1)\n') |
1145 output.write('\n') | 1167 output.write('\n') |
1146 | 1168 |
1147 namer = CMakeNamer(target_list) | 1169 namer = CMakeNamer(target_list) |
1148 | 1170 |
1149 # The list of targets upon which the 'all' target should depend. | 1171 # The list of targets upon which the 'all' target should depend. |
1150 # CMake has it's own implicit 'all' target, one is not created explicitly. | 1172 # CMake has it's own implicit 'all' target, one is not created explicitly. |
1151 all_qualified_targets = set() | 1173 all_qualified_targets = set() |
1152 for build_file in params['build_files']: | 1174 for build_file in params['build_files']: |
1153 for qualified_target in gyp.common.AllTargets(target_list, | 1175 for qualified_target in gyp.common.AllTargets(target_list, |
1154 target_dicts, | 1176 target_dicts, |
1155 os.path.normpath(build_file)): | 1177 os.path.normpath(build_file)): |
1156 all_qualified_targets.add(qualified_target) | 1178 all_qualified_targets.add(qualified_target) |
1157 | 1179 |
1158 for qualified_target in target_list: | 1180 for qualified_target in target_list: |
| 1181 if flavor == 'mac': |
| 1182 gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target) |
| 1183 spec = target_dicts[qualified_target] |
| 1184 gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[gyp_file], spec) |
| 1185 |
1159 WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, | 1186 WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, |
1160 options, generator_flags, all_qualified_targets, output) | 1187 options, generator_flags, all_qualified_targets, flavor, output) |
1161 | 1188 |
1162 output.close() | 1189 output.close() |
1163 | 1190 |
1164 | 1191 |
1165 def PerformBuild(data, configurations, params): | 1192 def PerformBuild(data, configurations, params): |
1166 options = params['options'] | 1193 options = params['options'] |
1167 generator_flags = params['generator_flags'] | 1194 generator_flags = params['generator_flags'] |
1168 | 1195 |
1169 # generator_dir: relative path from pwd to where make puts build files. | 1196 # generator_dir: relative path from pwd to where make puts build files. |
1170 # Makes migrating from make to cmake easier, cmake doesn't put anything here. | 1197 # Makes migrating from make to cmake easier, cmake doesn't put anything here. |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1212 arglists.append((target_list, target_dicts, data, | 1239 arglists.append((target_list, target_dicts, data, |
1213 params, config_name)) | 1240 params, config_name)) |
1214 pool.map(CallGenerateOutputForConfig, arglists) | 1241 pool.map(CallGenerateOutputForConfig, arglists) |
1215 except KeyboardInterrupt, e: | 1242 except KeyboardInterrupt, e: |
1216 pool.terminate() | 1243 pool.terminate() |
1217 raise e | 1244 raise e |
1218 else: | 1245 else: |
1219 for config_name in config_names: | 1246 for config_name in config_names: |
1220 GenerateOutputForConfig(target_list, target_dicts, data, | 1247 GenerateOutputForConfig(target_list, target_dicts, data, |
1221 params, config_name) | 1248 params, config_name) |
OLD | NEW |