OLD | NEW |
1 # Copyright (c) 2012 Google Inc. All rights reserved. | 1 # Copyright (c) 2012 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 import gyp | 5 import gyp |
6 import gyp.common | 6 import gyp.common |
7 import gyp.system_test | 7 import gyp.system_test |
8 import gyp.xcode_emulation | 8 import gyp.xcode_emulation |
9 import os.path | 9 import os.path |
10 import re | 10 import re |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 """Given a relative path like foo/bar, return the inverse relative path: | 69 """Given a relative path like foo/bar, return the inverse relative path: |
70 the path from the relative path back to the origin dir. | 70 the path from the relative path back to the origin dir. |
71 | 71 |
72 E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path))) | 72 E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path))) |
73 should always produce the empty string.""" | 73 should always produce the empty string.""" |
74 | 74 |
75 if not path: | 75 if not path: |
76 return path | 76 return path |
77 # Only need to handle relative paths into subdirectories for now. | 77 # Only need to handle relative paths into subdirectories for now. |
78 assert '..' not in path, path | 78 assert '..' not in path, path |
79 depth = len(path.split('/')) | 79 depth = len(path.split(os.path.sep)) |
80 return '/'.join(['..'] * depth) | 80 return '/'.join(['..'] * depth) |
81 | 81 |
82 | 82 |
83 class Target: | 83 class Target: |
84 """Target represents the paths used within a single gyp target. | 84 """Target represents the paths used within a single gyp target. |
85 | 85 |
86 Conceptually, building a single target A is a series of steps: | 86 Conceptually, building a single target A is a series of steps: |
87 | 87 |
88 1) actions/rules/copies generates source/resources/etc. | 88 1) actions/rules/copies generates source/resources/etc. |
89 2) compiles generates .o files | 89 2) compiles generates .o files |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 build_dir: path from source root to build output | 173 build_dir: path from source root to build output |
174 abs_build_dir: absolute path to the build directory | 174 abs_build_dir: absolute path to the build directory |
175 """ | 175 """ |
176 | 176 |
177 self.target_outputs = target_outputs | 177 self.target_outputs = target_outputs |
178 self.base_dir = base_dir | 178 self.base_dir = base_dir |
179 self.build_dir = build_dir | 179 self.build_dir = build_dir |
180 self.ninja = ninja_syntax.Writer(output_file) | 180 self.ninja = ninja_syntax.Writer(output_file) |
181 self.flavor = flavor | 181 self.flavor = flavor |
182 self.abs_build_dir = abs_build_dir | 182 self.abs_build_dir = abs_build_dir |
| 183 self.obj_ext = '.obj' if flavor == 'win' else '.o' |
183 | 184 |
184 # Relative path from build output dir to base dir. | 185 # Relative path from build output dir to base dir. |
185 self.build_to_base = os.path.join(InvertRelativePath(build_dir), base_dir) | 186 self.build_to_base = os.path.join(InvertRelativePath(build_dir), base_dir) |
186 # Relative path from base dir to build dir. | 187 # Relative path from base dir to build dir. |
187 self.base_to_build = os.path.join(InvertRelativePath(base_dir), build_dir) | 188 self.base_to_build = os.path.join(InvertRelativePath(base_dir), build_dir) |
188 | 189 |
189 def ExpandSpecial(self, path, product_dir=None): | 190 def ExpandSpecial(self, path, product_dir=None): |
190 """Expand specials like $!PRODUCT_DIR in |path|. | 191 """Expand specials like $!PRODUCT_DIR in |path|. |
191 | 192 |
192 If |product_dir| is None, assumes the cwd is already the product | 193 If |product_dir| is None, assumes the cwd is already the product |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 # Write out the compilation steps, if any. | 342 # Write out the compilation steps, if any. |
342 link_deps = [] | 343 link_deps = [] |
343 sources = spec.get('sources', []) + extra_sources | 344 sources = spec.get('sources', []) + extra_sources |
344 if sources: | 345 if sources: |
345 link_deps = self.WriteSources( | 346 link_deps = self.WriteSources( |
346 config_name, config, sources, compile_depends_stamp, | 347 config_name, config, sources, compile_depends_stamp, |
347 gyp.xcode_emulation.MacPrefixHeader( | 348 gyp.xcode_emulation.MacPrefixHeader( |
348 self.xcode_settings, self.GypPathToNinja, | 349 self.xcode_settings, self.GypPathToNinja, |
349 lambda path, lang: self.GypPathToUniqueOutput(path + '-' + lang))) | 350 lambda path, lang: self.GypPathToUniqueOutput(path + '-' + lang))) |
350 # Some actions/rules output 'sources' that are already object files. | 351 # Some actions/rules output 'sources' that are already object files. |
351 link_deps += [self.GypPathToNinja(f) for f in sources if f.endswith('.o')] | 352 link_deps += [self.GypPathToNinja(f) |
| 353 for f in sources if f.endswith(self.obj_ext)] |
352 | 354 |
353 # Write out a link step, if needed. | 355 # Write out a link step, if needed. |
354 output = None | 356 output = None |
355 if link_deps or self.target.actions_stamp or actions_depends: | 357 if link_deps or self.target.actions_stamp or actions_depends: |
356 output = self.WriteTarget(spec, config_name, config, link_deps, | 358 output = self.WriteTarget(spec, config_name, config, link_deps, |
357 self.target.actions_stamp or actions_depends) | 359 self.target.actions_stamp or actions_depends) |
358 if self.is_mac_bundle: | 360 if self.is_mac_bundle: |
359 mac_bundle_depends.append(output) | 361 mac_bundle_depends.append(output) |
360 | 362 |
361 # Bundle all of the above together, if needed. | 363 # Bundle all of the above together, if needed. |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
620 elif ext in ('c', 's', 'S'): | 622 elif ext in ('c', 's', 'S'): |
621 command = 'cc' | 623 command = 'cc' |
622 elif self.flavor == 'mac' and ext == 'm': | 624 elif self.flavor == 'mac' and ext == 'm': |
623 command = 'objc' | 625 command = 'objc' |
624 elif self.flavor == 'mac' and ext == 'mm': | 626 elif self.flavor == 'mac' and ext == 'mm': |
625 command = 'objcxx' | 627 command = 'objcxx' |
626 else: | 628 else: |
627 # TODO: should we assert here on unexpected extensions? | 629 # TODO: should we assert here on unexpected extensions? |
628 continue | 630 continue |
629 input = self.GypPathToNinja(source) | 631 input = self.GypPathToNinja(source) |
630 output = self.GypPathToUniqueOutput(filename + '.o') | 632 output = self.GypPathToUniqueOutput(filename + self.obj_ext) |
631 implicit = precompiled_header.GetObjDependencies([input], [output]) | 633 implicit = precompiled_header.GetObjDependencies([input], [output]) |
632 self.ninja.build(output, command, input, | 634 self.ninja.build(output, command, input, |
633 implicit=[gch for _, _, gch in implicit], | 635 implicit=[gch for _, _, gch in implicit], |
634 order_only=predepends) | 636 order_only=predepends) |
635 outputs.append(output) | 637 outputs.append(output) |
636 | 638 |
637 self.WritePchTargets(pch_commands) | 639 self.WritePchTargets(pch_commands) |
638 | 640 |
639 self.ninja.newline() | 641 self.ninja.newline() |
640 return outputs | 642 return outputs |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
959 import gyp.generator.xcode as xcode_generator | 961 import gyp.generator.xcode as xcode_generator |
960 global generator_additional_non_configuration_keys | 962 global generator_additional_non_configuration_keys |
961 generator_additional_non_configuration_keys = getattr(xcode_generator, | 963 generator_additional_non_configuration_keys = getattr(xcode_generator, |
962 'generator_additional_non_configuration_keys', []) | 964 'generator_additional_non_configuration_keys', []) |
963 global generator_additional_path_sections | 965 global generator_additional_path_sections |
964 generator_additional_path_sections = getattr(xcode_generator, | 966 generator_additional_path_sections = getattr(xcode_generator, |
965 'generator_additional_path_sections', []) | 967 'generator_additional_path_sections', []) |
966 global generator_extra_sources_for_rules | 968 global generator_extra_sources_for_rules |
967 generator_extra_sources_for_rules = getattr(xcode_generator, | 969 generator_extra_sources_for_rules = getattr(xcode_generator, |
968 'generator_extra_sources_for_rules', []) | 970 'generator_extra_sources_for_rules', []) |
| 971 elif flavor == 'win': |
| 972 default_variables.setdefault('EXECUTABLE_SUFFIX', '.exe') |
| 973 default_variables.setdefault('STATIC_LIB_PREFIX', '') |
| 974 default_variables.setdefault('STATIC_LIB_SUFFIX', '.lib') |
| 975 default_variables.setdefault('SHARED_LIB_PREFIX', '') |
| 976 default_variables.setdefault('SHARED_LIB_SUFFIX', '.dll') |
969 else: | 977 else: |
970 operating_system = flavor | 978 operating_system = flavor |
971 if flavor == 'android': | 979 if flavor == 'android': |
972 operating_system = 'linux' # Keep this legacy behavior for now. | 980 operating_system = 'linux' # Keep this legacy behavior for now. |
973 default_variables.setdefault('OS', operating_system) | 981 default_variables.setdefault('OS', operating_system) |
974 default_variables.setdefault('SHARED_LIB_SUFFIX', '.so') | 982 default_variables.setdefault('SHARED_LIB_SUFFIX', '.so') |
975 default_variables.setdefault('SHARED_LIB_DIR', '$!PRODUCT_DIR/lib') | 983 default_variables.setdefault('SHARED_LIB_DIR', '$!PRODUCT_DIR/lib') |
976 default_variables.setdefault('LIB_DIR', '') | 984 default_variables.setdefault('LIB_DIR', '') |
977 | 985 |
978 | 986 |
(...skipping 18 matching lines...) Expand all Loading... |
997 config_name) | 1005 config_name) |
998 | 1006 |
999 master_ninja = ninja_syntax.Writer( | 1007 master_ninja = ninja_syntax.Writer( |
1000 OpenOutput(os.path.join(options.toplevel_dir, build_dir, 'build.ninja')), | 1008 OpenOutput(os.path.join(options.toplevel_dir, build_dir, 'build.ninja')), |
1001 width=120) | 1009 width=120) |
1002 | 1010 |
1003 # Put build-time support tools in out/{config_name}. | 1011 # Put build-time support tools in out/{config_name}. |
1004 gyp.common.CopyTool(flavor, os.path.join(options.toplevel_dir, build_dir)) | 1012 gyp.common.CopyTool(flavor, os.path.join(options.toplevel_dir, build_dir)) |
1005 | 1013 |
1006 # Grab make settings for CC/CXX. | 1014 # Grab make settings for CC/CXX. |
1007 cc, cxx = 'gcc', 'g++' | 1015 if flavor == 'win': |
| 1016 cc = cxx = 'cl' |
| 1017 else: |
| 1018 cc, cxx = 'gcc', 'g++' |
1008 build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) | 1019 build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) |
1009 make_global_settings = data[build_file].get('make_global_settings', []) | 1020 make_global_settings = data[build_file].get('make_global_settings', []) |
1010 build_to_root = InvertRelativePath(build_dir) | 1021 build_to_root = InvertRelativePath(build_dir) |
1011 for key, value in make_global_settings: | 1022 for key, value in make_global_settings: |
1012 if key == 'CC': cc = os.path.join(build_to_root, value) | 1023 if key == 'CC': cc = os.path.join(build_to_root, value) |
1013 if key == 'CXX': cxx = os.path.join(build_to_root, value) | 1024 if key == 'CXX': cxx = os.path.join(build_to_root, value) |
1014 | 1025 |
1015 flock = 'flock' | 1026 flock = 'flock' |
1016 if flavor == 'mac': | 1027 if flavor == 'mac': |
1017 flock = './gyp-mac-tool flock' | 1028 flock = './gyp-mac-tool flock' |
1018 master_ninja.variable('cc', os.environ.get('CC', cc)) | 1029 master_ninja.variable('cc', os.environ.get('CC', cc)) |
1019 master_ninja.variable('cxx', os.environ.get('CXX', cxx)) | 1030 master_ninja.variable('cxx', os.environ.get('CXX', cxx)) |
1020 master_ninja.variable('ld', flock + ' linker.lock $cxx') | 1031 if flavor == 'win': |
| 1032 master_ninja.variable('ld', 'link') |
| 1033 else: |
| 1034 master_ninja.variable('ld', flock + ' linker.lock $cxx') |
1021 master_ninja.variable('cc_host', '$cc') | 1035 master_ninja.variable('cc_host', '$cc') |
1022 master_ninja.variable('cxx_host', '$cxx') | 1036 master_ninja.variable('cxx_host', '$cxx') |
1023 if flavor == 'mac': | 1037 if flavor == 'mac': |
1024 master_ninja.variable('mac_tool', os.path.join('.', 'gyp-mac-tool')) | 1038 master_ninja.variable('mac_tool', os.path.join('.', 'gyp-mac-tool')) |
1025 master_ninja.newline() | 1039 master_ninja.newline() |
1026 | 1040 |
1027 master_ninja.rule( | 1041 if flavor != 'win': |
1028 'cc', | 1042 master_ninja.rule( |
1029 description='CC $out', | 1043 'cc', |
1030 command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_c ' | 1044 description='CC $out', |
1031 '$cflags_pch_c -c $in -o $out'), | 1045 command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_c ' |
1032 depfile='$out.d') | 1046 '$cflags_pch_c -c $in -o $out'), |
1033 master_ninja.rule( | 1047 depfile='$out.d') |
1034 'cxx', | 1048 master_ninja.rule( |
1035 description='CXX $out', | 1049 'cxx', |
1036 command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc ' | 1050 description='CXX $out', |
1037 '$cflags_pch_cc -c $in -o $out'), | 1051 command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc ' |
1038 depfile='$out.d') | 1052 '$cflags_pch_cc -c $in -o $out'), |
1039 if flavor != 'mac': | 1053 depfile='$out.d') |
| 1054 else: |
| 1055 # TODO(scottmg): Decide how /showIncludes handling should work in ninja. |
| 1056 master_ninja.rule( |
| 1057 'cc', |
| 1058 description='CC $out', |
| 1059 command=('$cc /nologo $defines $includes $cflags $cflags_c ' |
| 1060 '$cflags_pch_c /c $in /Fo$out'), |
| 1061 depfile='$out.d') |
| 1062 master_ninja.rule( |
| 1063 'cxx', |
| 1064 description='CXX $out', |
| 1065 command=('$cxx /nologo $defines $includes $cflags $cflags_cc ' |
| 1066 '$cflags_pch_cc /c $in /Fo$out'), |
| 1067 depfile='$out.d') |
| 1068 |
| 1069 if flavor != 'mac' and flavor != 'win': |
1040 master_ninja.rule( | 1070 master_ninja.rule( |
1041 'alink', | 1071 'alink', |
1042 description='AR $out', | 1072 description='AR $out', |
1043 command='rm -f $out && ar rcsT $out $in') | 1073 command='rm -f $out && ar rcsT $out $in') |
1044 master_ninja.rule( | 1074 master_ninja.rule( |
1045 'solink', | 1075 'solink', |
1046 description='SOLINK $out', | 1076 description='SOLINK $out', |
1047 command=('$ld -shared $ldflags -o $out -Wl,-soname=$soname ' | 1077 command=('$ld -shared $ldflags -o $out -Wl,-soname=$soname ' |
1048 '-Wl,--whole-archive $in -Wl,--no-whole-archive $libs')) | 1078 '-Wl,--whole-archive $in -Wl,--no-whole-archive $libs')) |
1049 master_ninja.rule( | 1079 master_ninja.rule( |
1050 'solink_module', | 1080 'solink_module', |
1051 description='SOLINK(module) $out', | 1081 description='SOLINK(module) $out', |
1052 command=('$ld -shared $ldflags -o $out -Wl,-soname=$soname ' | 1082 command=('$ld -shared $ldflags -o $out -Wl,-soname=$soname ' |
1053 '-Wl,--start-group $in -Wl,--end-group $libs')) | 1083 '-Wl,--start-group $in -Wl,--end-group $libs')) |
1054 master_ninja.rule( | 1084 master_ninja.rule( |
1055 'link', | 1085 'link', |
1056 description='LINK $out', | 1086 description='LINK $out', |
1057 command=('$ld $ldflags -o $out -Wl,-rpath=\$$ORIGIN/lib ' | 1087 command=('$ld $ldflags -o $out -Wl,-rpath=\$$ORIGIN/lib ' |
1058 '-Wl,--start-group $in -Wl,--end-group $libs')) | 1088 '-Wl,--start-group $in -Wl,--end-group $libs')) |
| 1089 elif flavor == 'win': |
| 1090 master_ninja.rule( |
| 1091 'alink', |
| 1092 description='AR $out', |
| 1093 command='lib /nologo /OUT:$out.lib $in') |
| 1094 master_ninja.rule( |
| 1095 'solink', |
| 1096 description='SOLINK $out', |
| 1097 command=('$ld /nologo /DLL $ldflags /OUT:$out.dll $in $libs')) |
| 1098 master_ninja.rule( |
| 1099 'solink_module', |
| 1100 description='SOLINK(module) $out', |
| 1101 command=('$ld /nologo /DLL $ldflags /OUT:$out.dll $in $libs')) |
| 1102 master_ninja.rule( |
| 1103 'link', |
| 1104 description='LINK $out', |
| 1105 command=('$ld /nologo $ldflags /OUT:$out.exe $in $libs')) |
1059 else: | 1106 else: |
1060 master_ninja.rule( | 1107 master_ninja.rule( |
1061 'objc', | 1108 'objc', |
1062 description='OBJC $out', | 1109 description='OBJC $out', |
1063 command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_objc ' | 1110 command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_objc ' |
1064 '$cflags_pch_objc -c $in -o $out'), | 1111 '$cflags_pch_objc -c $in -o $out'), |
1065 depfile='$out.d') | 1112 depfile='$out.d') |
1066 master_ninja.rule( | 1113 master_ninja.rule( |
1067 'objcxx', | 1114 'objcxx', |
1068 description='OBJCXX $out', | 1115 description='OBJCXX $out', |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1103 command='$env $mac_tool $mactool_cmd $in $out') | 1150 command='$env $mac_tool $mactool_cmd $in $out') |
1104 master_ninja.rule( | 1151 master_ninja.rule( |
1105 'package_framework', | 1152 'package_framework', |
1106 description='PACKAGE FRAMEWORK $out, POSTBUILDS', | 1153 description='PACKAGE FRAMEWORK $out, POSTBUILDS', |
1107 command='$mac_tool package-framework $out $version$postbuilds ' | 1154 command='$mac_tool package-framework $out $version$postbuilds ' |
1108 '&& touch $out') | 1155 '&& touch $out') |
1109 master_ninja.rule( | 1156 master_ninja.rule( |
1110 'stamp', | 1157 'stamp', |
1111 description='STAMP $out', | 1158 description='STAMP $out', |
1112 command='${postbuilds}touch $out') | 1159 command='${postbuilds}touch $out') |
1113 master_ninja.rule( | 1160 if flavor == 'win': |
1114 'copy', | 1161 # TODO(scottmg): Copy fallback? |
1115 description='COPY $in $out', | 1162 master_ninja.rule( |
1116 command='ln -f $in $out 2>/dev/null || (rm -rf $out && cp -af $in $out)') | 1163 'copy', |
| 1164 description='COPY $in $out', |
| 1165 command='mklink /h $out $in >nul') |
| 1166 else: |
| 1167 master_ninja.rule( |
| 1168 'copy', |
| 1169 description='COPY $in $out', |
| 1170 command='ln -f $in $out 2>/dev/null || (rm -rf $out && cp -af $in $out)') |
1117 master_ninja.newline() | 1171 master_ninja.newline() |
1118 | 1172 |
1119 all_targets = set() | 1173 all_targets = set() |
1120 for build_file in params['build_files']: | 1174 for build_file in params['build_files']: |
1121 for target in gyp.common.AllTargets(target_list, target_dicts, build_file): | 1175 for target in gyp.common.AllTargets(target_list, target_dicts, build_file): |
1122 all_targets.add(target) | 1176 all_targets.add(target) |
1123 all_outputs = set() | 1177 all_outputs = set() |
1124 | 1178 |
1125 # target_outputs is a map from qualified target name to a Target object. | 1179 # target_outputs is a map from qualified target name to a Target object. |
1126 target_outputs = {} | 1180 target_outputs = {} |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1169 | 1223 |
1170 user_config = params.get('generator_flags', {}).get('config', None) | 1224 user_config = params.get('generator_flags', {}).get('config', None) |
1171 if user_config: | 1225 if user_config: |
1172 GenerateOutputForConfig(target_list, target_dicts, data, params, | 1226 GenerateOutputForConfig(target_list, target_dicts, data, params, |
1173 user_config) | 1227 user_config) |
1174 else: | 1228 else: |
1175 config_names = target_dicts[target_list[0]]['configurations'].keys() | 1229 config_names = target_dicts[target_list[0]]['configurations'].keys() |
1176 for config_name in config_names: | 1230 for config_name in config_names: |
1177 GenerateOutputForConfig(target_list, target_dicts, data, params, | 1231 GenerateOutputForConfig(target_list, target_dicts, data, params, |
1178 config_name) | 1232 config_name) |
OLD | NEW |