bundle gyp
authorPatrick Ohly <patrick.ohly@intel.com>
Fri, 19 Sep 2014 10:04:47 +0000 (12:04 +0200)
committerPatrick Ohly <patrick.ohly@intel.com>
Fri, 19 Sep 2014 10:13:21 +0000 (12:13 +0200)
This is the same approach as used in other Crosswalk projects.
Could be replaced with a Tizen gyp package if someone was willing
to maintain it.

1369 files changed:
gyp/AUTHORS [new file with mode: 0644]
gyp/DEPS [new file with mode: 0644]
gyp/LICENSE [new file with mode: 0644]
gyp/OWNERS [new file with mode: 0644]
gyp/PRESUBMIT.py [new file with mode: 0644]
gyp/buildbot/buildbot_run.py [new file with mode: 0755]
gyp/codereview.settings [new file with mode: 0644]
gyp/data/win/large-pdb-shim.cc [new file with mode: 0644]
gyp/gyp [new file with mode: 0755]
gyp/gyp.bat [new file with mode: 0755]
gyp/gyp_main.py [new file with mode: 0755]
gyp/gyptest.py [new file with mode: 0755]
gyp/pylib/gyp/MSVSNew.py [new file with mode: 0644]
gyp/pylib/gyp/MSVSProject.py [new file with mode: 0644]
gyp/pylib/gyp/MSVSSettings.py [new file with mode: 0644]
gyp/pylib/gyp/MSVSSettings_test.py [new file with mode: 0755]
gyp/pylib/gyp/MSVSToolFile.py [new file with mode: 0644]
gyp/pylib/gyp/MSVSUserFile.py [new file with mode: 0644]
gyp/pylib/gyp/MSVSUtil.py [new file with mode: 0644]
gyp/pylib/gyp/MSVSVersion.py [new file with mode: 0644]
gyp/pylib/gyp/__init__.py [new file with mode: 0755]
gyp/pylib/gyp/common.py [new file with mode: 0644]
gyp/pylib/gyp/common_test.py [new file with mode: 0755]
gyp/pylib/gyp/easy_xml.py [new file with mode: 0644]
gyp/pylib/gyp/easy_xml_test.py [new file with mode: 0755]
gyp/pylib/gyp/flock_tool.py [new file with mode: 0755]
gyp/pylib/gyp/generator/__init__.py [new file with mode: 0644]
gyp/pylib/gyp/generator/analyzer.py [new file with mode: 0644]
gyp/pylib/gyp/generator/android.py [new file with mode: 0644]
gyp/pylib/gyp/generator/cmake.py [new file with mode: 0644]
gyp/pylib/gyp/generator/dump_dependency_json.py [new file with mode: 0644]
gyp/pylib/gyp/generator/eclipse.py [new file with mode: 0644]
gyp/pylib/gyp/generator/gypd.py [new file with mode: 0644]
gyp/pylib/gyp/generator/gypsh.py [new file with mode: 0644]
gyp/pylib/gyp/generator/make.py [new file with mode: 0644]
gyp/pylib/gyp/generator/msvs.py [new file with mode: 0644]
gyp/pylib/gyp/generator/msvs_test.py [new file with mode: 0755]
gyp/pylib/gyp/generator/ninja.py [new file with mode: 0644]
gyp/pylib/gyp/generator/ninja_test.py [new file with mode: 0644]
gyp/pylib/gyp/generator/xcode.py [new file with mode: 0644]
gyp/pylib/gyp/generator/xcode_test.py [new file with mode: 0644]
gyp/pylib/gyp/input.py [new file with mode: 0644]
gyp/pylib/gyp/input_test.py [new file with mode: 0755]
gyp/pylib/gyp/mac_tool.py [new file with mode: 0755]
gyp/pylib/gyp/msvs_emulation.py [new file with mode: 0644]
gyp/pylib/gyp/ninja_syntax.py [new file with mode: 0644]
gyp/pylib/gyp/ordered_dict.py [new file with mode: 0644]
gyp/pylib/gyp/simple_copy.py [new file with mode: 0644]
gyp/pylib/gyp/win_tool.py [new file with mode: 0755]
gyp/pylib/gyp/xcode_emulation.py [new file with mode: 0644]
gyp/pylib/gyp/xcode_ninja.py [new file with mode: 0644]
gyp/pylib/gyp/xcodeproj_file.py [new file with mode: 0644]
gyp/pylib/gyp/xml_fix.py [new file with mode: 0644]
gyp/samples/samples [new file with mode: 0755]
gyp/samples/samples.bat [new file with mode: 0644]
gyp/setup.py [new file with mode: 0755]
gyp/test/actions-bare/gyptest-bare.py [new file with mode: 0755]
gyp/test/actions-bare/src/bare.gyp [new file with mode: 0644]
gyp/test/actions-bare/src/bare.py [new file with mode: 0755]
gyp/test/actions-multiple/gyptest-all.py [new file with mode: 0755]
gyp/test/actions-multiple/src/actions.gyp [new file with mode: 0644]
gyp/test/actions-multiple/src/copy.py [new file with mode: 0755]
gyp/test/actions-multiple/src/filter.py [new file with mode: 0755]
gyp/test/actions-multiple/src/foo.c [new file with mode: 0644]
gyp/test/actions-multiple/src/input.txt [new file with mode: 0644]
gyp/test/actions-multiple/src/main.c [new file with mode: 0644]
gyp/test/actions-none/gyptest-none.py [new file with mode: 0755]
gyp/test/actions-none/src/fake_cross.py [new file with mode: 0644]
gyp/test/actions-none/src/foo.cc [new file with mode: 0644]
gyp/test/actions-none/src/none_with_source_files.gyp [new file with mode: 0644]
gyp/test/actions-subdir/gyptest-action.py [new file with mode: 0755]
gyp/test/actions-subdir/src/make-file.py [new file with mode: 0755]
gyp/test/actions-subdir/src/none.gyp [new file with mode: 0644]
gyp/test/actions-subdir/src/subdir/make-subdir-file.py [new file with mode: 0755]
gyp/test/actions-subdir/src/subdir/subdir.gyp [new file with mode: 0644]
gyp/test/actions/generated-header/action.py [new file with mode: 0644]
gyp/test/actions/generated-header/main.cc [new file with mode: 0644]
gyp/test/actions/generated-header/test.gyp [new file with mode: 0644]
gyp/test/actions/gyptest-all.py [new file with mode: 0755]
gyp/test/actions/gyptest-default.py [new file with mode: 0755]
gyp/test/actions/gyptest-errors.py [new file with mode: 0755]
gyp/test/actions/gyptest-generated-header.py [new file with mode: 0644]
gyp/test/actions/src/action_missing_name.gyp [new file with mode: 0644]
gyp/test/actions/src/actions.gyp [new file with mode: 0644]
gyp/test/actions/src/confirm-dep-files.py [new file with mode: 0755]
gyp/test/actions/src/subdir1/counter.py [new file with mode: 0755]
gyp/test/actions/src/subdir1/executable.gyp [new file with mode: 0644]
gyp/test/actions/src/subdir1/make-prog1.py [new file with mode: 0755]
gyp/test/actions/src/subdir1/make-prog2.py [new file with mode: 0755]
gyp/test/actions/src/subdir1/program.c [new file with mode: 0644]
gyp/test/actions/src/subdir2/make-file.py [new file with mode: 0755]
gyp/test/actions/src/subdir2/none.gyp [new file with mode: 0644]
gyp/test/actions/src/subdir3/generate_main.py [new file with mode: 0755]
gyp/test/actions/src/subdir3/null_input.gyp [new file with mode: 0644]
gyp/test/additional-targets/gyptest-additional.py [new file with mode: 0755]
gyp/test/additional-targets/src/all.gyp [new file with mode: 0644]
gyp/test/additional-targets/src/dir1/actions.gyp [new file with mode: 0644]
gyp/test/additional-targets/src/dir1/emit.py [new file with mode: 0755]
gyp/test/additional-targets/src/dir1/lib1.c [new file with mode: 0644]
gyp/test/analyzer/common.gypi [new file with mode: 0644]
gyp/test/analyzer/gyptest-analyzer.new.py [new file with mode: 0644]
gyp/test/analyzer/gyptest-analyzer.py [new file with mode: 0644]
gyp/test/analyzer/subdir/subdir.gyp [new file with mode: 0644]
gyp/test/analyzer/subdir/subdir2/subdir2.gyp [new file with mode: 0644]
gyp/test/analyzer/subdir2/subdir.gyp [new file with mode: 0644]
gyp/test/analyzer/subdir2/subdir.includes.gypi [new file with mode: 0644]
gyp/test/analyzer/test.gyp [new file with mode: 0644]
gyp/test/analyzer/test2.gyp [new file with mode: 0644]
gyp/test/analyzer/test2.includes.gypi [new file with mode: 0644]
gyp/test/analyzer/test2.includes.includes.gypi [new file with mode: 0644]
gyp/test/analyzer/test2.toplevel_includes.gypi [new file with mode: 0644]
gyp/test/android/file.in [new file with mode: 0644]
gyp/test/android/gyptest-make-functions.py [new file with mode: 0755]
gyp/test/android/gyptest-noalias.py [new file with mode: 0755]
gyp/test/android/gyptest-space-filenames.py [new file with mode: 0755]
gyp/test/android/hello.c [new file with mode: 0644]
gyp/test/android/hello.gyp [new file with mode: 0644]
gyp/test/android/make_functions.gyp [new file with mode: 0644]
gyp/test/android/space_filenames.gyp [new file with mode: 0644]
gyp/test/assembly/gyptest-assembly.py [new file with mode: 0755]
gyp/test/assembly/gyptest-override.py [new file with mode: 0644]
gyp/test/assembly/src/as.bat [new file with mode: 0644]
gyp/test/assembly/src/assembly.gyp [new file with mode: 0644]
gyp/test/assembly/src/lib1.S [new file with mode: 0644]
gyp/test/assembly/src/lib1.c [new file with mode: 0644]
gyp/test/assembly/src/override.gyp [new file with mode: 0644]
gyp/test/assembly/src/override_asm.asm [new file with mode: 0644]
gyp/test/assembly/src/program.c [new file with mode: 0644]
gyp/test/build-option/gyptest-build.py [new file with mode: 0755]
gyp/test/build-option/hello.c [new file with mode: 0644]
gyp/test/build-option/hello.gyp [new file with mode: 0644]
gyp/test/builddir/gyptest-all.py [new file with mode: 0755]
gyp/test/builddir/gyptest-default.py [new file with mode: 0755]
gyp/test/builddir/src/builddir.gypi [new file with mode: 0644]
gyp/test/builddir/src/func1.c [new file with mode: 0644]
gyp/test/builddir/src/func2.c [new file with mode: 0644]
gyp/test/builddir/src/func3.c [new file with mode: 0644]
gyp/test/builddir/src/func4.c [new file with mode: 0644]
gyp/test/builddir/src/func5.c [new file with mode: 0644]
gyp/test/builddir/src/prog1.c [new file with mode: 0644]
gyp/test/builddir/src/prog1.gyp [new file with mode: 0644]
gyp/test/builddir/src/subdir2/prog2.c [new file with mode: 0644]
gyp/test/builddir/src/subdir2/prog2.gyp [new file with mode: 0644]
gyp/test/builddir/src/subdir2/subdir3/prog3.c [new file with mode: 0644]
gyp/test/builddir/src/subdir2/subdir3/prog3.gyp [new file with mode: 0644]
gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c [new file with mode: 0644]
gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.gyp [new file with mode: 0644]
gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c [new file with mode: 0644]
gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.gyp [new file with mode: 0644]
gyp/test/cflags/cflags.c [new file with mode: 0644]
gyp/test/cflags/cflags.gyp [new file with mode: 0644]
gyp/test/cflags/gyptest-cflags.py [new file with mode: 0755]
gyp/test/compilable/gyptest-headers.py [new file with mode: 0755]
gyp/test/compilable/src/headers.gyp [new file with mode: 0644]
gyp/test/compilable/src/lib1.cpp [new file with mode: 0644]
gyp/test/compilable/src/lib1.hpp [new file with mode: 0644]
gyp/test/compilable/src/program.cpp [new file with mode: 0644]
gyp/test/compiler-override/compiler-global-settings.gyp.in [new file with mode: 0644]
gyp/test/compiler-override/compiler-host.gyp [new file with mode: 0644]
gyp/test/compiler-override/compiler.gyp [new file with mode: 0644]
gyp/test/compiler-override/cxxtest.cc [new file with mode: 0644]
gyp/test/compiler-override/gyptest-compiler-env.py [new file with mode: 0755]
gyp/test/compiler-override/gyptest-compiler-global-settings.py [new file with mode: 0755]
gyp/test/compiler-override/my_cc.py [new file with mode: 0755]
gyp/test/compiler-override/my_cxx.py [new file with mode: 0755]
gyp/test/compiler-override/my_ld.py [new file with mode: 0755]
gyp/test/compiler-override/test.c [new file with mode: 0644]
gyp/test/configurations/basics/configurations.c [new file with mode: 0644]
gyp/test/configurations/basics/configurations.gyp [new file with mode: 0644]
gyp/test/configurations/basics/gyptest-configurations.py [new file with mode: 0755]
gyp/test/configurations/inheritance/configurations.c [new file with mode: 0644]
gyp/test/configurations/inheritance/configurations.gyp [new file with mode: 0644]
gyp/test/configurations/inheritance/duplicates.gyp [new file with mode: 0644]
gyp/test/configurations/inheritance/duplicates.gypd.golden [new file with mode: 0644]
gyp/test/configurations/inheritance/gyptest-duplicates.py [new file with mode: 0755]
gyp/test/configurations/inheritance/gyptest-inheritance.py [new file with mode: 0755]
gyp/test/configurations/invalid/actions.gyp [new file with mode: 0644]
gyp/test/configurations/invalid/all_dependent_settings.gyp [new file with mode: 0644]
gyp/test/configurations/invalid/configurations.gyp [new file with mode: 0644]
gyp/test/configurations/invalid/dependencies.gyp [new file with mode: 0644]
gyp/test/configurations/invalid/direct_dependent_settings.gyp [new file with mode: 0644]
gyp/test/configurations/invalid/gyptest-configurations.py [new file with mode: 0755]
gyp/test/configurations/invalid/libraries.gyp [new file with mode: 0644]
gyp/test/configurations/invalid/link_settings.gyp [new file with mode: 0644]
gyp/test/configurations/invalid/sources.gyp [new file with mode: 0644]
gyp/test/configurations/invalid/standalone_static_library.gyp [new file with mode: 0644]
gyp/test/configurations/invalid/target_name.gyp [new file with mode: 0644]
gyp/test/configurations/invalid/type.gyp [new file with mode: 0644]
gyp/test/configurations/target_platform/configurations.gyp [new file with mode: 0644]
gyp/test/configurations/target_platform/front.c [new file with mode: 0644]
gyp/test/configurations/target_platform/gyptest-target_platform.py [new file with mode: 0755]
gyp/test/configurations/target_platform/left.c [new file with mode: 0644]
gyp/test/configurations/target_platform/right.c [new file with mode: 0644]
gyp/test/configurations/x64/configurations.c [new file with mode: 0644]
gyp/test/configurations/x64/configurations.gyp [new file with mode: 0644]
gyp/test/configurations/x64/gyptest-x86.py [new file with mode: 0755]
gyp/test/copies/gyptest-all.py [new file with mode: 0755]
gyp/test/copies/gyptest-attribs.py [new file with mode: 0644]
gyp/test/copies/gyptest-default.py [new file with mode: 0755]
gyp/test/copies/gyptest-samedir.py [new file with mode: 0755]
gyp/test/copies/gyptest-slash.py [new file with mode: 0755]
gyp/test/copies/gyptest-updir.py [new file with mode: 0755]
gyp/test/copies/src/copies-attribs.gyp [new file with mode: 0644]
gyp/test/copies/src/copies-samedir.gyp [new file with mode: 0644]
gyp/test/copies/src/copies-slash.gyp [new file with mode: 0644]
gyp/test/copies/src/copies-updir.gyp [new file with mode: 0644]
gyp/test/copies/src/copies.gyp [new file with mode: 0644]
gyp/test/copies/src/directory/file3 [new file with mode: 0644]
gyp/test/copies/src/directory/file4 [new file with mode: 0644]
gyp/test/copies/src/directory/subdir/file5 [new file with mode: 0644]
gyp/test/copies/src/executable-file.sh [new file with mode: 0755]
gyp/test/copies/src/file1 [new file with mode: 0644]
gyp/test/copies/src/file2 [new file with mode: 0644]
gyp/test/copies/src/parentdir/subdir/file6 [new file with mode: 0644]
gyp/test/custom-generator/gyptest-custom-generator.py [new file with mode: 0755]
gyp/test/custom-generator/mygenerator.py [new file with mode: 0644]
gyp/test/custom-generator/test.gyp [new file with mode: 0644]
gyp/test/cxxflags/cxxflags.cc [new file with mode: 0644]
gyp/test/cxxflags/cxxflags.gyp [new file with mode: 0644]
gyp/test/cxxflags/gyptest-cxxflags.py [new file with mode: 0755]
gyp/test/defines-escaping/defines-escaping.c [new file with mode: 0644]
gyp/test/defines-escaping/defines-escaping.gyp [new file with mode: 0644]
gyp/test/defines-escaping/gyptest-defines-escaping.py [new file with mode: 0755]
gyp/test/defines/defines-env.gyp [new file with mode: 0644]
gyp/test/defines/defines.c [new file with mode: 0644]
gyp/test/defines/defines.gyp [new file with mode: 0644]
gyp/test/defines/gyptest-define-override.py [new file with mode: 0755]
gyp/test/defines/gyptest-defines-env-regyp.py [new file with mode: 0755]
gyp/test/defines/gyptest-defines-env.py [new file with mode: 0755]
gyp/test/defines/gyptest-defines.py [new file with mode: 0755]
gyp/test/dependencies/a.c [new file with mode: 0755]
gyp/test/dependencies/b/b.c [new file with mode: 0755]
gyp/test/dependencies/b/b.gyp [new file with mode: 0755]
gyp/test/dependencies/b/b3.c [new file with mode: 0755]
gyp/test/dependencies/c/c.c [new file with mode: 0644]
gyp/test/dependencies/c/c.gyp [new file with mode: 0644]
gyp/test/dependencies/c/d.c [new file with mode: 0644]
gyp/test/dependencies/double_dependency.gyp [new file with mode: 0644]
gyp/test/dependencies/double_dependent.gyp [new file with mode: 0644]
gyp/test/dependencies/extra_targets.gyp [new file with mode: 0644]
gyp/test/dependencies/gyptest-double-dependency.py [new file with mode: 0644]
gyp/test/dependencies/gyptest-extra-targets.py [new file with mode: 0755]
gyp/test/dependencies/gyptest-lib-only.py [new file with mode: 0755]
gyp/test/dependencies/gyptest-none-traversal.py [new file with mode: 0755]
gyp/test/dependencies/gyptest-sharedlib-linksettings.py [new file with mode: 0644]
gyp/test/dependencies/lib_only.gyp [new file with mode: 0755]
gyp/test/dependencies/main.c [new file with mode: 0644]
gyp/test/dependencies/none_traversal.gyp [new file with mode: 0755]
gyp/test/dependencies/sharedlib-linksettings/program.c [new file with mode: 0644]
gyp/test/dependencies/sharedlib-linksettings/sharedlib.c [new file with mode: 0644]
gyp/test/dependencies/sharedlib-linksettings/staticlib.c [new file with mode: 0644]
gyp/test/dependencies/sharedlib-linksettings/test.gyp [new file with mode: 0644]
gyp/test/dependency-copy/gyptest-copy.py [new file with mode: 0755]
gyp/test/dependency-copy/src/copies.gyp [new file with mode: 0644]
gyp/test/dependency-copy/src/file1.c [new file with mode: 0644]
gyp/test/dependency-copy/src/file2.c [new file with mode: 0644]
gyp/test/errors/duplicate_basenames.gyp [new file with mode: 0644]
gyp/test/errors/duplicate_node.gyp [new file with mode: 0644]
gyp/test/errors/duplicate_rule.gyp [new file with mode: 0644]
gyp/test/errors/duplicate_targets.gyp [new file with mode: 0644]
gyp/test/errors/gyptest-errors.py [new file with mode: 0755]
gyp/test/errors/missing_dep.gyp [new file with mode: 0644]
gyp/test/errors/missing_targets.gyp [new file with mode: 0644]
gyp/test/escaping/colon/test.gyp [new file with mode: 0644]
gyp/test/escaping/gyptest-colon.py [new file with mode: 0644]
gyp/test/exclusion/exclusion.gyp [new file with mode: 0644]
gyp/test/exclusion/gyptest-exclusion.py [new file with mode: 0755]
gyp/test/exclusion/hello.c [new file with mode: 0644]
gyp/test/external-cross-compile/gyptest-cross.py [new file with mode: 0755]
gyp/test/external-cross-compile/src/bogus1.cc [new file with mode: 0644]
gyp/test/external-cross-compile/src/bogus2.c [new file with mode: 0644]
gyp/test/external-cross-compile/src/cross.gyp [new file with mode: 0644]
gyp/test/external-cross-compile/src/cross_compile.gypi [new file with mode: 0644]
gyp/test/external-cross-compile/src/fake_cross.py [new file with mode: 0644]
gyp/test/external-cross-compile/src/program.cc [new file with mode: 0644]
gyp/test/external-cross-compile/src/test1.cc [new file with mode: 0644]
gyp/test/external-cross-compile/src/test2.c [new file with mode: 0644]
gyp/test/external-cross-compile/src/test3.cc [new file with mode: 0644]
gyp/test/external-cross-compile/src/test4.c [new file with mode: 0644]
gyp/test/external-cross-compile/src/tochar.py [new file with mode: 0644]
gyp/test/generator-output/actions/actions.gyp [new file with mode: 0644]
gyp/test/generator-output/actions/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/actions/subdir1/actions-out/README.txt [new file with mode: 0644]
gyp/test/generator-output/actions/subdir1/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/actions/subdir1/executable.gyp [new file with mode: 0644]
gyp/test/generator-output/actions/subdir1/make-prog1.py [new file with mode: 0755]
gyp/test/generator-output/actions/subdir1/make-prog2.py [new file with mode: 0755]
gyp/test/generator-output/actions/subdir1/program.c [new file with mode: 0644]
gyp/test/generator-output/actions/subdir2/actions-out/README.txt [new file with mode: 0644]
gyp/test/generator-output/actions/subdir2/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/actions/subdir2/make-file.py [new file with mode: 0755]
gyp/test/generator-output/actions/subdir2/none.gyp [new file with mode: 0644]
gyp/test/generator-output/copies/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/copies/copies-out/README.txt [new file with mode: 0644]
gyp/test/generator-output/copies/copies.gyp [new file with mode: 0644]
gyp/test/generator-output/copies/file1 [new file with mode: 0644]
gyp/test/generator-output/copies/file2 [new file with mode: 0644]
gyp/test/generator-output/copies/subdir/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/copies/subdir/copies-out/README.txt [new file with mode: 0644]
gyp/test/generator-output/copies/subdir/file3 [new file with mode: 0644]
gyp/test/generator-output/copies/subdir/file4 [new file with mode: 0644]
gyp/test/generator-output/copies/subdir/subdir.gyp [new file with mode: 0644]
gyp/test/generator-output/gyptest-actions.py [new file with mode: 0755]
gyp/test/generator-output/gyptest-copies.py [new file with mode: 0755]
gyp/test/generator-output/gyptest-depth.py [new file with mode: 0755]
gyp/test/generator-output/gyptest-mac-bundle.py [new file with mode: 0644]
gyp/test/generator-output/gyptest-relocate.py [new file with mode: 0755]
gyp/test/generator-output/gyptest-rules.py [new file with mode: 0755]
gyp/test/generator-output/gyptest-subdir2-deep.py [new file with mode: 0755]
gyp/test/generator-output/gyptest-symlink.py [new file with mode: 0755]
gyp/test/generator-output/gyptest-top-all.py [new file with mode: 0755]
gyp/test/generator-output/mac-bundle/Info.plist [new file with mode: 0644]
gyp/test/generator-output/mac-bundle/app.order [new file with mode: 0644]
gyp/test/generator-output/mac-bundle/header.h [new file with mode: 0644]
gyp/test/generator-output/mac-bundle/main.c [new file with mode: 0644]
gyp/test/generator-output/mac-bundle/resource.sb [new file with mode: 0644]
gyp/test/generator-output/mac-bundle/test.gyp [new file with mode: 0644]
gyp/test/generator-output/rules/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/rules/copy-file.py [new file with mode: 0755]
gyp/test/generator-output/rules/rules.gyp [new file with mode: 0644]
gyp/test/generator-output/rules/subdir1/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/rules/subdir1/define3.in0 [new file with mode: 0644]
gyp/test/generator-output/rules/subdir1/define4.in0 [new file with mode: 0644]
gyp/test/generator-output/rules/subdir1/executable.gyp [new file with mode: 0644]
gyp/test/generator-output/rules/subdir1/function1.in1 [new file with mode: 0644]
gyp/test/generator-output/rules/subdir1/function2.in1 [new file with mode: 0644]
gyp/test/generator-output/rules/subdir1/program.c [new file with mode: 0644]
gyp/test/generator-output/rules/subdir2/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/rules/subdir2/file1.in0 [new file with mode: 0644]
gyp/test/generator-output/rules/subdir2/file2.in0 [new file with mode: 0644]
gyp/test/generator-output/rules/subdir2/file3.in1 [new file with mode: 0644]
gyp/test/generator-output/rules/subdir2/file4.in1 [new file with mode: 0644]
gyp/test/generator-output/rules/subdir2/none.gyp [new file with mode: 0644]
gyp/test/generator-output/rules/subdir2/rules-out/README.txt [new file with mode: 0644]
gyp/test/generator-output/src/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/src/inc.h [new file with mode: 0644]
gyp/test/generator-output/src/inc1/include1.h [new file with mode: 0644]
gyp/test/generator-output/src/prog1.c [new file with mode: 0644]
gyp/test/generator-output/src/prog1.gyp [new file with mode: 0644]
gyp/test/generator-output/src/subdir2/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/src/subdir2/deeper/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/src/subdir2/deeper/deeper.c [new file with mode: 0644]
gyp/test/generator-output/src/subdir2/deeper/deeper.gyp [new file with mode: 0644]
gyp/test/generator-output/src/subdir2/deeper/deeper.h [new file with mode: 0644]
gyp/test/generator-output/src/subdir2/inc2/include2.h [new file with mode: 0644]
gyp/test/generator-output/src/subdir2/prog2.c [new file with mode: 0644]
gyp/test/generator-output/src/subdir2/prog2.gyp [new file with mode: 0644]
gyp/test/generator-output/src/subdir3/build/README.txt [new file with mode: 0644]
gyp/test/generator-output/src/subdir3/inc3/include3.h [new file with mode: 0644]
gyp/test/generator-output/src/subdir3/prog3.c [new file with mode: 0644]
gyp/test/generator-output/src/subdir3/prog3.gyp [new file with mode: 0644]
gyp/test/generator-output/src/symroot.gypi [new file with mode: 0644]
gyp/test/gyp-defines/defines.gyp [new file with mode: 0644]
gyp/test/gyp-defines/echo.py [new file with mode: 0644]
gyp/test/gyp-defines/gyptest-multiple-values.py [new file with mode: 0644]
gyp/test/gyp-defines/gyptest-regyp.py [new file with mode: 0644]
gyp/test/hard_dependency/gyptest-exported-hard-dependency.py [new file with mode: 0755]
gyp/test/hard_dependency/gyptest-no-exported-hard-dependency.py [new file with mode: 0755]
gyp/test/hard_dependency/src/a.c [new file with mode: 0644]
gyp/test/hard_dependency/src/a.h [new file with mode: 0644]
gyp/test/hard_dependency/src/b.c [new file with mode: 0644]
gyp/test/hard_dependency/src/b.h [new file with mode: 0644]
gyp/test/hard_dependency/src/c.c [new file with mode: 0644]
gyp/test/hard_dependency/src/c.h [new file with mode: 0644]
gyp/test/hard_dependency/src/d.c [new file with mode: 0644]
gyp/test/hard_dependency/src/emit.py [new file with mode: 0755]
gyp/test/hard_dependency/src/hard_dependency.gyp [new file with mode: 0644]
gyp/test/hello/gyptest-all.py [new file with mode: 0755]
gyp/test/hello/gyptest-default.py [new file with mode: 0755]
gyp/test/hello/gyptest-disable-regyp.py [new file with mode: 0755]
gyp/test/hello/gyptest-regyp-output.py [new file with mode: 0644]
gyp/test/hello/gyptest-regyp.py [new file with mode: 0755]
gyp/test/hello/gyptest-target.py [new file with mode: 0755]
gyp/test/hello/hello.c [new file with mode: 0644]
gyp/test/hello/hello.gyp [new file with mode: 0644]
gyp/test/hello/hello2.c [new file with mode: 0644]
gyp/test/hello/hello2.gyp [new file with mode: 0644]
gyp/test/home_dot_gyp/gyptest-home-includes-config-arg.py [new file with mode: 0755]
gyp/test/home_dot_gyp/gyptest-home-includes-config-env.py [new file with mode: 0755]
gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py [new file with mode: 0755]
gyp/test/home_dot_gyp/gyptest-home-includes.py [new file with mode: 0755]
gyp/test/home_dot_gyp/home/.gyp/include.gypi [new file with mode: 0644]
gyp/test/home_dot_gyp/home2/.gyp/include.gypi [new file with mode: 0644]
gyp/test/home_dot_gyp/home2/.gyp_new/include.gypi [new file with mode: 0644]
gyp/test/home_dot_gyp/src/all.gyp [new file with mode: 0644]
gyp/test/home_dot_gyp/src/printfoo.c [new file with mode: 0644]
gyp/test/include_dirs/gyptest-all.py [new file with mode: 0755]
gyp/test/include_dirs/gyptest-default.py [new file with mode: 0755]
gyp/test/include_dirs/src/inc.h [new file with mode: 0644]
gyp/test/include_dirs/src/inc1/include1.h [new file with mode: 0644]
gyp/test/include_dirs/src/includes.c [new file with mode: 0644]
gyp/test/include_dirs/src/includes.gyp [new file with mode: 0644]
gyp/test/include_dirs/src/shadow1/shadow.h [new file with mode: 0644]
gyp/test/include_dirs/src/shadow2/shadow.h [new file with mode: 0644]
gyp/test/include_dirs/src/subdir/inc.h [new file with mode: 0644]
gyp/test/include_dirs/src/subdir/inc2/include2.h [new file with mode: 0644]
gyp/test/include_dirs/src/subdir/subdir_includes.c [new file with mode: 0644]
gyp/test/include_dirs/src/subdir/subdir_includes.gyp [new file with mode: 0644]
gyp/test/intermediate_dir/gyptest-intermediate-dir.py [new file with mode: 0755]
gyp/test/intermediate_dir/src/script.py [new file with mode: 0755]
gyp/test/intermediate_dir/src/shared_infile.txt [new file with mode: 0644]
gyp/test/intermediate_dir/src/test.gyp [new file with mode: 0644]
gyp/test/intermediate_dir/src/test2.gyp [new file with mode: 0644]
gyp/test/ios/app-bundle/TestApp/English.lproj/InfoPlist-error.strings [new file with mode: 0644]
gyp/test/ios/app-bundle/TestApp/English.lproj/InfoPlist.strings [new file with mode: 0644]
gyp/test/ios/app-bundle/TestApp/English.lproj/MainMenu.xib [new file with mode: 0644]
gyp/test/ios/app-bundle/TestApp/English.lproj/Main_iPhone.storyboard [new file with mode: 0644]
gyp/test/ios/app-bundle/TestApp/TestApp-Info.plist [new file with mode: 0644]
gyp/test/ios/app-bundle/TestApp/check_no_signature.py [new file with mode: 0644]
gyp/test/ios/app-bundle/TestApp/main.m [new file with mode: 0644]
gyp/test/ios/app-bundle/TestApp/only-compile-in-32-bits.m [new file with mode: 0644]
gyp/test/ios/app-bundle/TestApp/only-compile-in-64-bits.m [new file with mode: 0644]
gyp/test/ios/app-bundle/test-archs.gyp [new file with mode: 0644]
gyp/test/ios/app-bundle/test-crosscompile.gyp [new file with mode: 0644]
gyp/test/ios/app-bundle/test-device.gyp [new file with mode: 0644]
gyp/test/ios/app-bundle/test.gyp [new file with mode: 0644]
gyp/test/ios/app-bundle/tool_main.cc [new file with mode: 0644]
gyp/test/ios/deployment-target/check-version-min.c [new file with mode: 0644]
gyp/test/ios/deployment-target/deployment-target.gyp [new file with mode: 0644]
gyp/test/ios/extension/ActionExtension/ActionViewController.h [new file with mode: 0644]
gyp/test/ios/extension/ActionExtension/ActionViewController.m [new file with mode: 0644]
gyp/test/ios/extension/ActionExtension/Info.plist [new file with mode: 0644]
gyp/test/ios/extension/ActionExtension/MainInterface.storyboard [new file with mode: 0644]
gyp/test/ios/extension/ExtensionContainer/AppDelegate.h [new file with mode: 0644]
gyp/test/ios/extension/ExtensionContainer/AppDelegate.m [new file with mode: 0644]
gyp/test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard [new file with mode: 0644]
gyp/test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json [new file with mode: 0644]
gyp/test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json [new file with mode: 0644]
gyp/test/ios/extension/ExtensionContainer/Info.plist [new file with mode: 0644]
gyp/test/ios/extension/ExtensionContainer/ViewController.h [new file with mode: 0644]
gyp/test/ios/extension/ExtensionContainer/ViewController.m [new file with mode: 0644]
gyp/test/ios/extension/ExtensionContainer/main.m [new file with mode: 0644]
gyp/test/ios/extension/extension.gyp [new file with mode: 0644]
gyp/test/ios/gyptest-app-ios.py [new file with mode: 0755]
gyp/test/ios/gyptest-archs.py [new file with mode: 0644]
gyp/test/ios/gyptest-crosscompile.py [new file with mode: 0644]
gyp/test/ios/gyptest-deployment-target.py [new file with mode: 0644]
gyp/test/ios/gyptest-extension.py [new file with mode: 0755]
gyp/test/ios/gyptest-per-config-settings.py [new file with mode: 0644]
gyp/test/ios/gyptest-xcode-ninja.py [new file with mode: 0644]
gyp/test/lib/README.txt [new file with mode: 0644]
gyp/test/lib/TestCmd.py [new file with mode: 0644]
gyp/test/lib/TestCommon.py [new file with mode: 0644]
gyp/test/lib/TestGyp.py [new file with mode: 0644]
gyp/test/lib/TestMac.py [new file with mode: 0644]
gyp/test/lib/TestWin.py [new file with mode: 0644]
gyp/test/library/gyptest-shared-obj-install-path.py [new file with mode: 0755]
gyp/test/library/gyptest-shared.py [new file with mode: 0755]
gyp/test/library/gyptest-static.py [new file with mode: 0755]
gyp/test/library/src/lib1.c [new file with mode: 0644]
gyp/test/library/src/lib1_moveable.c [new file with mode: 0644]
gyp/test/library/src/lib2.c [new file with mode: 0644]
gyp/test/library/src/lib2_moveable.c [new file with mode: 0644]
gyp/test/library/src/library.gyp [new file with mode: 0644]
gyp/test/library/src/program.c [new file with mode: 0644]
gyp/test/library/src/shared_dependency.gyp [new file with mode: 0644]
gyp/test/library_dirs/gyptest-library-dirs.py [new file with mode: 0644]
gyp/test/library_dirs/subdir/README.txt [new file with mode: 0644]
gyp/test/library_dirs/subdir/hello.cc [new file with mode: 0644]
gyp/test/library_dirs/subdir/mylib.cc [new file with mode: 0644]
gyp/test/library_dirs/subdir/mylib.h [new file with mode: 0644]
gyp/test/library_dirs/subdir/test-win.gyp [new file with mode: 0644]
gyp/test/library_dirs/subdir/test.gyp [new file with mode: 0644]
gyp/test/link-dependency/gyptest-link-dependency.py [new file with mode: 0755]
gyp/test/link-dependency/main.c [new file with mode: 0644]
gyp/test/link-dependency/mymalloc.c [new file with mode: 0644]
gyp/test/link-dependency/test.gyp [new file with mode: 0644]
gyp/test/link-objects/base.c [new file with mode: 0644]
gyp/test/link-objects/extra.c [new file with mode: 0644]
gyp/test/link-objects/gyptest-all.py [new file with mode: 0755]
gyp/test/link-objects/link-objects.gyp [new file with mode: 0644]
gyp/test/linux/gyptest-implicit-rpath.py [new file with mode: 0644]
gyp/test/linux/implicit-rpath/file.c [new file with mode: 0644]
gyp/test/linux/implicit-rpath/main.c [new file with mode: 0644]
gyp/test/linux/implicit-rpath/test.gyp [new file with mode: 0644]
gyp/test/mac/action-envvars/action/action.gyp [new file with mode: 0644]
gyp/test/mac/action-envvars/action/action.sh [new file with mode: 0755]
gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist-error.strings [new file with mode: 0644]
gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist.strings [new file with mode: 0644]
gyp/test/mac/app-bundle/TestApp/English.lproj/MainMenu.xib [new file with mode: 0644]
gyp/test/mac/app-bundle/TestApp/English.lproj/utf-16be.strings [new file with mode: 0644]
gyp/test/mac/app-bundle/TestApp/English.lproj/utf-16le.strings [new file with mode: 0644]
gyp/test/mac/app-bundle/TestApp/TestApp-Info.plist [new file with mode: 0644]
gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.h [new file with mode: 0644]
gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.m [new file with mode: 0644]
gyp/test/mac/app-bundle/TestApp/main.m [new file with mode: 0644]
gyp/test/mac/app-bundle/empty.c [new file with mode: 0644]
gyp/test/mac/app-bundle/test-error.gyp [new file with mode: 0644]
gyp/test/mac/app-bundle/test.gyp [new file with mode: 0644]
gyp/test/mac/archs/empty_main.cc [new file with mode: 0644]
gyp/test/mac/archs/file.mm [new file with mode: 0644]
gyp/test/mac/archs/header.h [new file with mode: 0644]
gyp/test/mac/archs/my_file.cc [new file with mode: 0644]
gyp/test/mac/archs/my_main_file.cc [new file with mode: 0644]
gyp/test/mac/archs/test-archs-multiarch.gyp [new file with mode: 0644]
gyp/test/mac/archs/test-archs-x86_64.gyp [new file with mode: 0644]
gyp/test/mac/archs/test-no-archs.gyp [new file with mode: 0644]
gyp/test/mac/archs/test-valid-archs.gyp [new file with mode: 0644]
gyp/test/mac/bundle-resources/change.sh [new file with mode: 0755]
gyp/test/mac/bundle-resources/executable-file.sh [new file with mode: 0755]
gyp/test/mac/bundle-resources/secret.txt [new file with mode: 0644]
gyp/test/mac/bundle-resources/test.gyp [new file with mode: 0644]
gyp/test/mac/cflags/ccfile.cc [new file with mode: 0644]
gyp/test/mac/cflags/ccfile_withcflags.cc [new file with mode: 0644]
gyp/test/mac/cflags/cfile.c [new file with mode: 0644]
gyp/test/mac/cflags/cppfile.cpp [new file with mode: 0644]
gyp/test/mac/cflags/cppfile_withcflags.cpp [new file with mode: 0644]
gyp/test/mac/cflags/cxxfile.cxx [new file with mode: 0644]
gyp/test/mac/cflags/cxxfile_withcflags.cxx [new file with mode: 0644]
gyp/test/mac/cflags/mfile.m [new file with mode: 0644]
gyp/test/mac/cflags/mmfile.mm [new file with mode: 0644]
gyp/test/mac/cflags/mmfile_withcflags.mm [new file with mode: 0644]
gyp/test/mac/cflags/test.gyp [new file with mode: 0644]
gyp/test/mac/clang-cxx-language-standard/c++11.cc [new file with mode: 0644]
gyp/test/mac/clang-cxx-language-standard/c++98.cc [new file with mode: 0644]
gyp/test/mac/clang-cxx-language-standard/clang-cxx-language-standard.gyp [new file with mode: 0644]
gyp/test/mac/clang-cxx-library/clang-cxx-library.gyp [new file with mode: 0644]
gyp/test/mac/clang-cxx-library/libc++.cc [new file with mode: 0644]
gyp/test/mac/clang-cxx-library/libstdc++.cc [new file with mode: 0644]
gyp/test/mac/copy-dylib/empty.c [new file with mode: 0644]
gyp/test/mac/copy-dylib/test.gyp [new file with mode: 0644]
gyp/test/mac/debuginfo/file.c [new file with mode: 0644]
gyp/test/mac/debuginfo/test.gyp [new file with mode: 0644]
gyp/test/mac/depend-on-bundle/English.lproj/InfoPlist.strings [new file with mode: 0644]
gyp/test/mac/depend-on-bundle/Info.plist [new file with mode: 0644]
gyp/test/mac/depend-on-bundle/bundle.c [new file with mode: 0644]
gyp/test/mac/depend-on-bundle/executable.c [new file with mode: 0644]
gyp/test/mac/depend-on-bundle/test.gyp [new file with mode: 0644]
gyp/test/mac/deployment-target/check-version-min.c [new file with mode: 0644]
gyp/test/mac/deployment-target/deployment-target.gyp [new file with mode: 0644]
gyp/test/mac/framework-dirs/calculate.c [new file with mode: 0644]
gyp/test/mac/framework-dirs/framework-dirs.gyp [new file with mode: 0644]
gyp/test/mac/framework-headers/myframework.h [new file with mode: 0644]
gyp/test/mac/framework-headers/myframework.m [new file with mode: 0644]
gyp/test/mac/framework-headers/test.gyp [new file with mode: 0644]
gyp/test/mac/framework/TestFramework/English.lproj/InfoPlist.strings [new file with mode: 0644]
gyp/test/mac/framework/TestFramework/Info.plist [new file with mode: 0644]
gyp/test/mac/framework/TestFramework/ObjCVector.h [new file with mode: 0644]
gyp/test/mac/framework/TestFramework/ObjCVector.mm [new file with mode: 0644]
gyp/test/mac/framework/TestFramework/ObjCVectorInternal.h [new file with mode: 0644]
gyp/test/mac/framework/TestFramework/TestFramework_Prefix.pch [new file with mode: 0644]
gyp/test/mac/framework/empty.c [new file with mode: 0644]
gyp/test/mac/framework/framework.gyp [new file with mode: 0644]
gyp/test/mac/global-settings/src/dir1/dir1.gyp [new file with mode: 0644]
gyp/test/mac/global-settings/src/dir2/dir2.gyp [new file with mode: 0644]
gyp/test/mac/global-settings/src/dir2/file.txt [new file with mode: 0644]
gyp/test/mac/gyptest-action-envvars.py [new file with mode: 0644]
gyp/test/mac/gyptest-app-error.py [new file with mode: 0755]
gyp/test/mac/gyptest-app.py [new file with mode: 0755]
gyp/test/mac/gyptest-archs.py [new file with mode: 0644]
gyp/test/mac/gyptest-bundle-resources.py [new file with mode: 0644]
gyp/test/mac/gyptest-cflags.py [new file with mode: 0644]
gyp/test/mac/gyptest-clang-cxx-language-standard.py [new file with mode: 0644]
gyp/test/mac/gyptest-clang-cxx-library.py [new file with mode: 0644]
gyp/test/mac/gyptest-copies.py [new file with mode: 0755]
gyp/test/mac/gyptest-copy-dylib.py [new file with mode: 0644]
gyp/test/mac/gyptest-debuginfo.py [new file with mode: 0755]
gyp/test/mac/gyptest-depend-on-bundle.py [new file with mode: 0644]
gyp/test/mac/gyptest-deployment-target.py [new file with mode: 0644]
gyp/test/mac/gyptest-framework-dirs.py [new file with mode: 0644]
gyp/test/mac/gyptest-framework-headers.py [new file with mode: 0644]
gyp/test/mac/gyptest-framework.py [new file with mode: 0755]
gyp/test/mac/gyptest-global-settings.py [new file with mode: 0644]
gyp/test/mac/gyptest-infoplist-process.py [new file with mode: 0755]
gyp/test/mac/gyptest-installname.py [new file with mode: 0644]
gyp/test/mac/gyptest-ldflags-passed-to-libtool.py [new file with mode: 0644]
gyp/test/mac/gyptest-ldflags.py [new file with mode: 0644]
gyp/test/mac/gyptest-libraries.py [new file with mode: 0755]
gyp/test/mac/gyptest-loadable-module-bundle-product-extension.py [new file with mode: 0644]
gyp/test/mac/gyptest-loadable-module.py [new file with mode: 0755]
gyp/test/mac/gyptest-missing-cfbundlesignature.py [new file with mode: 0644]
gyp/test/mac/gyptest-non-strs-flattened-to-env.py [new file with mode: 0644]
gyp/test/mac/gyptest-objc-arc.py [new file with mode: 0755]
gyp/test/mac/gyptest-objc-gc.py [new file with mode: 0644]
gyp/test/mac/gyptest-postbuild-copy-bundle.py [new file with mode: 0644]
gyp/test/mac/gyptest-postbuild-defaults.py [new file with mode: 0644]
gyp/test/mac/gyptest-postbuild-fail.py [new file with mode: 0755]
gyp/test/mac/gyptest-postbuild-multiple-configurations.py [new file with mode: 0644]
gyp/test/mac/gyptest-postbuild-static-library.py [new file with mode: 0644]
gyp/test/mac/gyptest-postbuild.py [new file with mode: 0755]
gyp/test/mac/gyptest-prefixheader.py [new file with mode: 0755]
gyp/test/mac/gyptest-rebuild.py [new file with mode: 0755]
gyp/test/mac/gyptest-rpath.py [new file with mode: 0644]
gyp/test/mac/gyptest-sdkroot.py [new file with mode: 0644]
gyp/test/mac/gyptest-sourceless-module.py [new file with mode: 0644]
gyp/test/mac/gyptest-strip-default.py [new file with mode: 0644]
gyp/test/mac/gyptest-strip.py [new file with mode: 0755]
gyp/test/mac/gyptest-type-envvars.py [new file with mode: 0755]
gyp/test/mac/gyptest-unicode-settings.py [new file with mode: 0644]
gyp/test/mac/gyptest-xcode-env-order.py [new file with mode: 0755]
gyp/test/mac/gyptest-xcode-gcc-clang.py [new file with mode: 0644]
gyp/test/mac/gyptest-xcode-gcc.py [new file with mode: 0644]
gyp/test/mac/gyptest-xcode-support-actions.py [new file with mode: 0755]
gyp/test/mac/gyptest-xctest.py [new file with mode: 0644]
gyp/test/mac/infoplist-process/Info.plist [new file with mode: 0644]
gyp/test/mac/infoplist-process/main.c [new file with mode: 0644]
gyp/test/mac/infoplist-process/test1.gyp [new file with mode: 0644]
gyp/test/mac/infoplist-process/test2.gyp [new file with mode: 0644]
gyp/test/mac/infoplist-process/test3.gyp [new file with mode: 0644]
gyp/test/mac/installname/Info.plist [new file with mode: 0644]
gyp/test/mac/installname/file.c [new file with mode: 0644]
gyp/test/mac/installname/main.c [new file with mode: 0644]
gyp/test/mac/installname/test.gyp [new file with mode: 0644]
gyp/test/mac/ldflags-libtool/file.c [new file with mode: 0644]
gyp/test/mac/ldflags-libtool/test.gyp [new file with mode: 0644]
gyp/test/mac/ldflags/subdirectory/Info.plist [new file with mode: 0644]
gyp/test/mac/ldflags/subdirectory/file.c [new file with mode: 0644]
gyp/test/mac/ldflags/subdirectory/symbol_list.def [new file with mode: 0644]
gyp/test/mac/ldflags/subdirectory/test.gyp [new file with mode: 0644]
gyp/test/mac/libraries/subdir/README.txt [new file with mode: 0644]
gyp/test/mac/libraries/subdir/hello.cc [new file with mode: 0644]
gyp/test/mac/libraries/subdir/mylib.c [new file with mode: 0644]
gyp/test/mac/libraries/subdir/test.gyp [new file with mode: 0644]
gyp/test/mac/loadable-module-bundle-product-extension/src.cc [new file with mode: 0644]
gyp/test/mac/loadable-module-bundle-product-extension/test.gyp [new file with mode: 0644]
gyp/test/mac/loadable-module/Info.plist [new file with mode: 0644]
gyp/test/mac/loadable-module/module.c [new file with mode: 0644]
gyp/test/mac/loadable-module/test.gyp [new file with mode: 0644]
gyp/test/mac/missing-cfbundlesignature/Info.plist [new file with mode: 0644]
gyp/test/mac/missing-cfbundlesignature/Other-Info.plist [new file with mode: 0644]
gyp/test/mac/missing-cfbundlesignature/Third-Info.plist [new file with mode: 0644]
gyp/test/mac/missing-cfbundlesignature/file.c [new file with mode: 0644]
gyp/test/mac/missing-cfbundlesignature/test.gyp [new file with mode: 0644]
gyp/test/mac/non-strs-flattened-to-env/Info.plist [new file with mode: 0644]
gyp/test/mac/non-strs-flattened-to-env/main.c [new file with mode: 0644]
gyp/test/mac/non-strs-flattened-to-env/test.gyp [new file with mode: 0644]
gyp/test/mac/objc-arc/c-file.c [new file with mode: 0644]
gyp/test/mac/objc-arc/cc-file.cc [new file with mode: 0644]
gyp/test/mac/objc-arc/m-file-no-arc.m [new file with mode: 0644]
gyp/test/mac/objc-arc/m-file.m [new file with mode: 0644]
gyp/test/mac/objc-arc/mm-file-no-arc.mm [new file with mode: 0644]
gyp/test/mac/objc-arc/mm-file.mm [new file with mode: 0644]
gyp/test/mac/objc-arc/test.gyp [new file with mode: 0644]
gyp/test/mac/objc-gc/c-file.c [new file with mode: 0644]
gyp/test/mac/objc-gc/cc-file.cc [new file with mode: 0644]
gyp/test/mac/objc-gc/main.m [new file with mode: 0644]
gyp/test/mac/objc-gc/needs-gc-mm.mm [new file with mode: 0644]
gyp/test/mac/objc-gc/needs-gc.m [new file with mode: 0644]
gyp/test/mac/objc-gc/test.gyp [new file with mode: 0644]
gyp/test/mac/postbuild-copy-bundle/Framework-Info.plist [new file with mode: 0644]
gyp/test/mac/postbuild-copy-bundle/TestApp-Info.plist [new file with mode: 0644]
gyp/test/mac/postbuild-copy-bundle/copied.txt [new file with mode: 0644]
gyp/test/mac/postbuild-copy-bundle/empty.c [new file with mode: 0644]
gyp/test/mac/postbuild-copy-bundle/main.c [new file with mode: 0644]
gyp/test/mac/postbuild-copy-bundle/postbuild-copy-framework.sh [new file with mode: 0755]
gyp/test/mac/postbuild-copy-bundle/resource_file.sb [new file with mode: 0644]
gyp/test/mac/postbuild-copy-bundle/test.gyp [new file with mode: 0644]
gyp/test/mac/postbuild-defaults/Info.plist [new file with mode: 0644]
gyp/test/mac/postbuild-defaults/main.c [new file with mode: 0644]
gyp/test/mac/postbuild-defaults/postbuild-defaults.sh [new file with mode: 0755]
gyp/test/mac/postbuild-defaults/test.gyp [new file with mode: 0644]
gyp/test/mac/postbuild-fail/file.c [new file with mode: 0644]
gyp/test/mac/postbuild-fail/postbuild-fail.sh [new file with mode: 0755]
gyp/test/mac/postbuild-fail/test.gyp [new file with mode: 0644]
gyp/test/mac/postbuild-fail/touch-dynamic.sh [new file with mode: 0755]
gyp/test/mac/postbuild-fail/touch-static.sh [new file with mode: 0755]
gyp/test/mac/postbuild-multiple-configurations/main.c [new file with mode: 0644]
gyp/test/mac/postbuild-multiple-configurations/postbuild-touch-file.sh [new file with mode: 0755]
gyp/test/mac/postbuild-multiple-configurations/test.gyp [new file with mode: 0644]
gyp/test/mac/postbuild-static-library/empty.c [new file with mode: 0644]
gyp/test/mac/postbuild-static-library/postbuild-touch-file.sh [new file with mode: 0755]
gyp/test/mac/postbuild-static-library/test.gyp [new file with mode: 0644]
gyp/test/mac/postbuilds/copy.sh [new file with mode: 0755]
gyp/test/mac/postbuilds/file.c [new file with mode: 0644]
gyp/test/mac/postbuilds/file_g.c [new file with mode: 0644]
gyp/test/mac/postbuilds/file_h.c [new file with mode: 0644]
gyp/test/mac/postbuilds/script/shared_library_postbuild.sh [new file with mode: 0755]
gyp/test/mac/postbuilds/script/static_library_postbuild.sh [new file with mode: 0755]
gyp/test/mac/postbuilds/subdirectory/copied_file.txt [new file with mode: 0644]
gyp/test/mac/postbuilds/subdirectory/nested_target.gyp [new file with mode: 0644]
gyp/test/mac/postbuilds/test.gyp [new file with mode: 0644]
gyp/test/mac/prefixheader/file.c [new file with mode: 0644]
gyp/test/mac/prefixheader/file.cc [new file with mode: 0644]
gyp/test/mac/prefixheader/file.m [new file with mode: 0644]
gyp/test/mac/prefixheader/file.mm [new file with mode: 0644]
gyp/test/mac/prefixheader/header.h [new file with mode: 0644]
gyp/test/mac/prefixheader/test.gyp [new file with mode: 0644]
gyp/test/mac/rebuild/TestApp-Info.plist [new file with mode: 0644]
gyp/test/mac/rebuild/delay-touch.sh [new file with mode: 0755]
gyp/test/mac/rebuild/empty.c [new file with mode: 0644]
gyp/test/mac/rebuild/main.c [new file with mode: 0644]
gyp/test/mac/rebuild/test.gyp [new file with mode: 0644]
gyp/test/mac/rpath/file.c [new file with mode: 0644]
gyp/test/mac/rpath/main.c [new file with mode: 0644]
gyp/test/mac/rpath/test.gyp [new file with mode: 0644]
gyp/test/mac/sdkroot/file.cc [new file with mode: 0644]
gyp/test/mac/sdkroot/test.gyp [new file with mode: 0644]
gyp/test/mac/sdkroot/test_shorthand.sh [new file with mode: 0755]
gyp/test/mac/sourceless-module/empty.c [new file with mode: 0644]
gyp/test/mac/sourceless-module/empty.txt [new file with mode: 0644]
gyp/test/mac/sourceless-module/fun.c [new file with mode: 0644]
gyp/test/mac/sourceless-module/test.gyp [new file with mode: 0644]
gyp/test/mac/strip/file.c [new file with mode: 0644]
gyp/test/mac/strip/main.c [new file with mode: 0644]
gyp/test/mac/strip/strip.saves [new file with mode: 0644]
gyp/test/mac/strip/subdirectory/nested_file.c [new file with mode: 0644]
gyp/test/mac/strip/subdirectory/nested_strip.saves [new file with mode: 0644]
gyp/test/mac/strip/subdirectory/subdirectory.gyp [new file with mode: 0644]
gyp/test/mac/strip/subdirectory/test_reading_save_file_from_postbuild.sh [new file with mode: 0755]
gyp/test/mac/strip/test-defaults.gyp [new file with mode: 0644]
gyp/test/mac/strip/test.gyp [new file with mode: 0644]
gyp/test/mac/type_envvars/file.c [new file with mode: 0644]
gyp/test/mac/type_envvars/test.gyp [new file with mode: 0644]
gyp/test/mac/type_envvars/test_bundle_executable.sh [new file with mode: 0755]
gyp/test/mac/type_envvars/test_bundle_loadable_module.sh [new file with mode: 0755]
gyp/test/mac/type_envvars/test_bundle_shared_library.sh [new file with mode: 0755]
gyp/test/mac/type_envvars/test_check_sdkroot.sh [new file with mode: 0755]
gyp/test/mac/type_envvars/test_nonbundle_executable.sh [new file with mode: 0755]
gyp/test/mac/type_envvars/test_nonbundle_loadable_module.sh [new file with mode: 0755]
gyp/test/mac/type_envvars/test_nonbundle_none.sh [new file with mode: 0755]
gyp/test/mac/type_envvars/test_nonbundle_shared_library.sh [new file with mode: 0755]
gyp/test/mac/type_envvars/test_nonbundle_static_library.sh [new file with mode: 0755]
gyp/test/mac/unicode-settings/file.cc [new file with mode: 0644]
gyp/test/mac/unicode-settings/test.gyp [new file with mode: 0644]
gyp/test/mac/unicode-settings/test_bundle_display_name.sh [new file with mode: 0755]
gyp/test/mac/xcode-env-order/Info.plist [new file with mode: 0644]
gyp/test/mac/xcode-env-order/file.ext1 [new file with mode: 0644]
gyp/test/mac/xcode-env-order/file.ext2 [new file with mode: 0644]
gyp/test/mac/xcode-env-order/file.ext3 [new file with mode: 0644]
gyp/test/mac/xcode-env-order/main.c [new file with mode: 0644]
gyp/test/mac/xcode-env-order/test.gyp [new file with mode: 0644]
gyp/test/mac/xcode-gcc/aliasing.cc [new file with mode: 0644]
gyp/test/mac/xcode-gcc/test-clang.gyp [new file with mode: 0644]
gyp/test/mac/xcode-gcc/test.gyp [new file with mode: 0644]
gyp/test/mac/xcode-gcc/valid_c.c [new file with mode: 0644]
gyp/test/mac/xcode-gcc/valid_cc.cc [new file with mode: 0644]
gyp/test/mac/xcode-gcc/valid_m.m [new file with mode: 0644]
gyp/test/mac/xcode-gcc/valid_mm.mm [new file with mode: 0644]
gyp/test/mac/xcode-gcc/warn_about_invalid_offsetof_macro.cc [new file with mode: 0644]
gyp/test/mac/xcode-gcc/warn_about_missing_newline.c [new file with mode: 0644]
gyp/test/mac/xcode-support-actions/source.c [new file with mode: 0644]
gyp/test/mac/xcode-support-actions/test.gyp [new file with mode: 0644]
gyp/test/mac/xctest/MyClass.h [new file with mode: 0644]
gyp/test/mac/xctest/MyClass.m [new file with mode: 0644]
gyp/test/mac/xctest/TestCase.m [new file with mode: 0644]
gyp/test/mac/xctest/resource.txt [new file with mode: 0644]
gyp/test/mac/xctest/test.gyp [new file with mode: 0644]
gyp/test/mac/xctest/test.xcodeproj/xcshareddata/xcschemes/classes.xcscheme [new file with mode: 0644]
gyp/test/make/dependencies.gyp [new file with mode: 0644]
gyp/test/make/gyptest-dependencies.py [new file with mode: 0755]
gyp/test/make/gyptest-noload.py [new file with mode: 0755]
gyp/test/make/main.cc [new file with mode: 0644]
gyp/test/make/main.h [new file with mode: 0644]
gyp/test/make/noload/all.gyp [new file with mode: 0644]
gyp/test/make/noload/lib/shared.c [new file with mode: 0644]
gyp/test/make/noload/lib/shared.gyp [new file with mode: 0644]
gyp/test/make/noload/lib/shared.h [new file with mode: 0644]
gyp/test/make/noload/main.c [new file with mode: 0644]
gyp/test/make_global_settings/ar/gyptest-make_global_settings_ar.py [new file with mode: 0644]
gyp/test/make_global_settings/ar/make_global_settings_ar.gyp [new file with mode: 0644]
gyp/test/make_global_settings/basics/gyptest-make_global_settings.py [new file with mode: 0644]
gyp/test/make_global_settings/basics/make_global_settings.gyp [new file with mode: 0644]
gyp/test/make_global_settings/env-wrapper/gyptest-wrapper.py [new file with mode: 0644]
gyp/test/make_global_settings/env-wrapper/wrapper.gyp [new file with mode: 0644]
gyp/test/make_global_settings/ld/gyptest-make_global_settings_ld.py [new file with mode: 0644]
gyp/test/make_global_settings/ld/make_global_settings_ld.gyp [new file with mode: 0644]
gyp/test/make_global_settings/wrapper/gyptest-wrapper.py [new file with mode: 0644]
gyp/test/make_global_settings/wrapper/wrapper.gyp [new file with mode: 0644]
gyp/test/many-actions/file0 [new file with mode: 0644]
gyp/test/many-actions/file1 [new file with mode: 0644]
gyp/test/many-actions/file2 [new file with mode: 0644]
gyp/test/many-actions/file3 [new file with mode: 0644]
gyp/test/many-actions/file4 [new file with mode: 0644]
gyp/test/many-actions/gyptest-many-actions-unsorted.py [new file with mode: 0644]
gyp/test/many-actions/gyptest-many-actions.py [new file with mode: 0644]
gyp/test/many-actions/many-actions-unsorted.gyp [new file with mode: 0644]
gyp/test/many-actions/many-actions.gyp [new file with mode: 0644]
gyp/test/module/gyptest-default.py [new file with mode: 0755]
gyp/test/module/src/lib1.c [new file with mode: 0644]
gyp/test/module/src/lib2.c [new file with mode: 0644]
gyp/test/module/src/module.gyp [new file with mode: 0644]
gyp/test/module/src/program.c [new file with mode: 0644]
gyp/test/msvs/buildevents/buildevents.gyp [new file with mode: 0644]
gyp/test/msvs/buildevents/gyptest-msbuild-supports-prepostbuild.py [new file with mode: 0755]
gyp/test/msvs/buildevents/gyptest-ninja-warnings.py [new file with mode: 0755]
gyp/test/msvs/buildevents/main.cc [new file with mode: 0644]
gyp/test/msvs/config_attrs/gyptest-config_attrs.py [new file with mode: 0644]
gyp/test/msvs/config_attrs/hello.c [new file with mode: 0644]
gyp/test/msvs/config_attrs/hello.gyp [new file with mode: 0644]
gyp/test/msvs/express/base/base.gyp [new file with mode: 0644]
gyp/test/msvs/express/express.gyp [new file with mode: 0644]
gyp/test/msvs/express/gyptest-express.py [new file with mode: 0755]
gyp/test/msvs/external_builder/external.gyp [new file with mode: 0644]
gyp/test/msvs/external_builder/external_builder.py [new file with mode: 0644]
gyp/test/msvs/external_builder/gyptest-all.py [new file with mode: 0644]
gyp/test/msvs/external_builder/hello.cpp [new file with mode: 0644]
gyp/test/msvs/external_builder/hello.z [new file with mode: 0644]
gyp/test/msvs/external_builder/msbuild_action.py [new file with mode: 0644]
gyp/test/msvs/external_builder/msbuild_rule.py [new file with mode: 0644]
gyp/test/msvs/filters/filters.gyp [new file with mode: 0644]
gyp/test/msvs/filters/gyptest-filters-2008.py [new file with mode: 0644]
gyp/test/msvs/filters/gyptest-filters-2010.py [new file with mode: 0644]
gyp/test/msvs/list_excluded/gyptest-all.py [new file with mode: 0644]
gyp/test/msvs/list_excluded/hello.cpp [new file with mode: 0644]
gyp/test/msvs/list_excluded/hello_exclude.gyp [new file with mode: 0644]
gyp/test/msvs/list_excluded/hello_mac.cpp [new file with mode: 0644]
gyp/test/msvs/missing_sources/gyptest-missing.py [new file with mode: 0644]
gyp/test/msvs/missing_sources/hello_missing.gyp [new file with mode: 0644]
gyp/test/msvs/multiple_actions_error_handling/action_fail.py [new file with mode: 0644]
gyp/test/msvs/multiple_actions_error_handling/action_succeed.py [new file with mode: 0644]
gyp/test/msvs/multiple_actions_error_handling/actions.gyp [new file with mode: 0644]
gyp/test/msvs/multiple_actions_error_handling/gyptest.py [new file with mode: 0644]
gyp/test/msvs/props/AppName.props [new file with mode: 0644]
gyp/test/msvs/props/AppName.vsprops [new file with mode: 0644]
gyp/test/msvs/props/gyptest-props.py [new file with mode: 0644]
gyp/test/msvs/props/hello.c [new file with mode: 0644]
gyp/test/msvs/props/hello.gyp [new file with mode: 0644]
gyp/test/msvs/shared_output/common.gypi [new file with mode: 0644]
gyp/test/msvs/shared_output/gyptest-shared_output.py [new file with mode: 0644]
gyp/test/msvs/shared_output/hello.c [new file with mode: 0644]
gyp/test/msvs/shared_output/hello.gyp [new file with mode: 0644]
gyp/test/msvs/shared_output/there/there.c [new file with mode: 0644]
gyp/test/msvs/shared_output/there/there.gyp [new file with mode: 0644]
gyp/test/msvs/uldi2010/gyptest-all.py [new file with mode: 0644]
gyp/test/msvs/uldi2010/hello.c [new file with mode: 0644]
gyp/test/msvs/uldi2010/hello.gyp [new file with mode: 0644]
gyp/test/msvs/uldi2010/hello2.c [new file with mode: 0644]
gyp/test/multiple-targets/gyptest-all.py [new file with mode: 0755]
gyp/test/multiple-targets/gyptest-default.py [new file with mode: 0755]
gyp/test/multiple-targets/src/common.c [new file with mode: 0644]
gyp/test/multiple-targets/src/multiple.gyp [new file with mode: 0644]
gyp/test/multiple-targets/src/prog1.c [new file with mode: 0644]
gyp/test/multiple-targets/src/prog2.c [new file with mode: 0644]
gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py [new file with mode: 0755]
gyp/test/ninja/action_dependencies/src/a.c [new file with mode: 0644]
gyp/test/ninja/action_dependencies/src/a.h [new file with mode: 0644]
gyp/test/ninja/action_dependencies/src/action_dependencies.gyp [new file with mode: 0644]
gyp/test/ninja/action_dependencies/src/b.c [new file with mode: 0644]
gyp/test/ninja/action_dependencies/src/b.h [new file with mode: 0644]
gyp/test/ninja/action_dependencies/src/c.c [new file with mode: 0644]
gyp/test/ninja/action_dependencies/src/c.h [new file with mode: 0644]
gyp/test/ninja/action_dependencies/src/emit.py [new file with mode: 0755]
gyp/test/ninja/chained-dependency/chained-dependency.gyp [new file with mode: 0644]
gyp/test/ninja/chained-dependency/chained.c [new file with mode: 0644]
gyp/test/ninja/chained-dependency/gyptest-chained-dependency.py [new file with mode: 0755]
gyp/test/ninja/normalize-paths-win/gyptest-normalize-paths.py [new file with mode: 0644]
gyp/test/ninja/normalize-paths-win/hello.cc [new file with mode: 0644]
gyp/test/ninja/normalize-paths-win/normalize-paths.gyp [new file with mode: 0644]
gyp/test/ninja/s-needs-no-depfiles/empty.s [new file with mode: 0644]
gyp/test/ninja/s-needs-no-depfiles/gyptest-s-needs-no-depfiles.py [new file with mode: 0755]
gyp/test/ninja/s-needs-no-depfiles/s-needs-no-depfiles.gyp [new file with mode: 0644]
gyp/test/ninja/solibs_avoid_relinking/gyptest-solibs-avoid-relinking.py [new file with mode: 0755]
gyp/test/ninja/solibs_avoid_relinking/main.cc [new file with mode: 0644]
gyp/test/ninja/solibs_avoid_relinking/solib.cc [new file with mode: 0644]
gyp/test/ninja/solibs_avoid_relinking/solibs_avoid_relinking.gyp [new file with mode: 0644]
gyp/test/ninja/use-console/foo.bar [new file with mode: 0644]
gyp/test/ninja/use-console/gyptest-use-console.py [new file with mode: 0644]
gyp/test/ninja/use-console/use-console.gyp [new file with mode: 0644]
gyp/test/ninja/use-custom-environment-files/gyptest-use-custom-environment-files.py [new file with mode: 0644]
gyp/test/ninja/use-custom-environment-files/use-custom-environment-files.cc [new file with mode: 0644]
gyp/test/ninja/use-custom-environment-files/use-custom-environment-files.gyp [new file with mode: 0644]
gyp/test/no-cpp/gyptest-no-cpp.py [new file with mode: 0644]
gyp/test/no-cpp/src/call-f-main.c [new file with mode: 0644]
gyp/test/no-cpp/src/empty-main.c [new file with mode: 0644]
gyp/test/no-cpp/src/f.cc [new file with mode: 0644]
gyp/test/no-cpp/src/test.gyp [new file with mode: 0644]
gyp/test/no-output/gyptest-no-output.py [new file with mode: 0755]
gyp/test/no-output/src/nooutput.gyp [new file with mode: 0644]
gyp/test/product/gyptest-product.py [new file with mode: 0755]
gyp/test/product/hello.c [new file with mode: 0644]
gyp/test/product/product.gyp [new file with mode: 0644]
gyp/test/prune_targets/gyptest-prune-targets.py [new file with mode: 0644]
gyp/test/prune_targets/lib1.cc [new file with mode: 0644]
gyp/test/prune_targets/lib2.cc [new file with mode: 0644]
gyp/test/prune_targets/lib3.cc [new file with mode: 0644]
gyp/test/prune_targets/lib_indirect.cc [new file with mode: 0644]
gyp/test/prune_targets/program.cc [new file with mode: 0644]
gyp/test/prune_targets/test1.gyp [new file with mode: 0644]
gyp/test/prune_targets/test2.gyp [new file with mode: 0644]
gyp/test/relative/foo/a/a.cc [new file with mode: 0644]
gyp/test/relative/foo/a/a.gyp [new file with mode: 0644]
gyp/test/relative/foo/a/c/c.cc [new file with mode: 0644]
gyp/test/relative/foo/a/c/c.gyp [new file with mode: 0644]
gyp/test/relative/foo/b/b.cc [new file with mode: 0644]
gyp/test/relative/foo/b/b.gyp [new file with mode: 0644]
gyp/test/relative/gyptest-default.py [new file with mode: 0755]
gyp/test/rename/filecase/file.c [new file with mode: 0644]
gyp/test/rename/filecase/test-casesensitive.gyp [new file with mode: 0644]
gyp/test/rename/filecase/test.gyp [new file with mode: 0644]
gyp/test/rename/gyptest-filecase.py [new file with mode: 0644]
gyp/test/restat/gyptest-restat.py [new file with mode: 0644]
gyp/test/restat/src/create_intermediate.py [new file with mode: 0644]
gyp/test/restat/src/restat.gyp [new file with mode: 0644]
gyp/test/restat/src/touch.py [new file with mode: 0644]
gyp/test/rules-dirname/gyptest-dirname.py [new file with mode: 0755]
gyp/test/rules-dirname/src/actions.gyp [new file with mode: 0644]
gyp/test/rules-dirname/src/copy-file.py [new file with mode: 0755]
gyp/test/rules-dirname/src/subdir/a/b/c.gencc [new file with mode: 0644]
gyp/test/rules-dirname/src/subdir/a/b/c.printvars [new file with mode: 0644]
gyp/test/rules-dirname/src/subdir/foo/bar/baz.gencc [new file with mode: 0644]
gyp/test/rules-dirname/src/subdir/foo/bar/baz.printvars [new file with mode: 0644]
gyp/test/rules-dirname/src/subdir/input-rule-dirname.gyp [new file with mode: 0644]
gyp/test/rules-dirname/src/subdir/main.cc [new file with mode: 0644]
gyp/test/rules-dirname/src/subdir/nodir.gencc [new file with mode: 0644]
gyp/test/rules-dirname/src/subdir/printvars.py [new file with mode: 0755]
gyp/test/rules-rebuild/gyptest-all.py [new file with mode: 0755]
gyp/test/rules-rebuild/gyptest-default.py [new file with mode: 0755]
gyp/test/rules-rebuild/src/main.c [new file with mode: 0644]
gyp/test/rules-rebuild/src/make-sources.py [new file with mode: 0755]
gyp/test/rules-rebuild/src/prog1.in [new file with mode: 0644]
gyp/test/rules-rebuild/src/prog2.in [new file with mode: 0644]
gyp/test/rules-rebuild/src/same_target.gyp [new file with mode: 0644]
gyp/test/rules-use-built-dependencies/gyptest-use-built-dependencies.py [new file with mode: 0755]
gyp/test/rules-use-built-dependencies/src/main.cc [new file with mode: 0644]
gyp/test/rules-use-built-dependencies/src/use-built-dependencies-rule.gyp [new file with mode: 0644]
gyp/test/rules-variables/gyptest-rules-variables.py [new file with mode: 0755]
gyp/test/rules-variables/src/input_ext.c [new file with mode: 0644]
gyp/test/rules-variables/src/input_name/test.c [new file with mode: 0644]
gyp/test/rules-variables/src/input_path/subdir/test.c [new file with mode: 0644]
gyp/test/rules-variables/src/subdir/input_dirname.c [new file with mode: 0644]
gyp/test/rules-variables/src/subdir/test.c [new file with mode: 0644]
gyp/test/rules-variables/src/test.input_root.c [new file with mode: 0644]
gyp/test/rules-variables/src/variables.gyp [new file with mode: 0644]
gyp/test/rules/gyptest-all.py [new file with mode: 0755]
gyp/test/rules/gyptest-default.py [new file with mode: 0755]
gyp/test/rules/gyptest-input-root.py [new file with mode: 0755]
gyp/test/rules/gyptest-special-variables.py [new file with mode: 0644]
gyp/test/rules/src/actions.gyp [new file with mode: 0644]
gyp/test/rules/src/an_asm.S [new file with mode: 0644]
gyp/test/rules/src/as.bat [new file with mode: 0644]
gyp/test/rules/src/copy-file.py [new file with mode: 0755]
gyp/test/rules/src/external/external.gyp [new file with mode: 0644]
gyp/test/rules/src/external/file1.in [new file with mode: 0644]
gyp/test/rules/src/external/file2.in [new file with mode: 0644]
gyp/test/rules/src/input-root.gyp [new file with mode: 0644]
gyp/test/rules/src/noaction/file1.in [new file with mode: 0644]
gyp/test/rules/src/noaction/no_action_with_rules_fails.gyp [new file with mode: 0644]
gyp/test/rules/src/rule.py [new file with mode: 0755]
gyp/test/rules/src/somefile.ext [new file with mode: 0644]
gyp/test/rules/src/special-variables.gyp [new file with mode: 0644]
gyp/test/rules/src/subdir1/executable.gyp [new file with mode: 0644]
gyp/test/rules/src/subdir1/function1.in [new file with mode: 0644]
gyp/test/rules/src/subdir1/function2.in [new file with mode: 0644]
gyp/test/rules/src/subdir1/program.c [new file with mode: 0644]
gyp/test/rules/src/subdir2/both_rule_and_action_input.gyp [new file with mode: 0644]
gyp/test/rules/src/subdir2/file1.in [new file with mode: 0644]
gyp/test/rules/src/subdir2/file2.in [new file with mode: 0644]
gyp/test/rules/src/subdir2/never_used.gyp [new file with mode: 0644]
gyp/test/rules/src/subdir2/no_action.gyp [new file with mode: 0644]
gyp/test/rules/src/subdir2/no_inputs.gyp [new file with mode: 0644]
gyp/test/rules/src/subdir2/none.gyp [new file with mode: 0644]
gyp/test/rules/src/subdir2/program.c [new file with mode: 0644]
gyp/test/rules/src/subdir3/executable2.gyp [new file with mode: 0644]
gyp/test/rules/src/subdir3/function3.in [new file with mode: 0644]
gyp/test/rules/src/subdir3/program.c [new file with mode: 0644]
gyp/test/rules/src/subdir4/asm-function.assem [new file with mode: 0644]
gyp/test/rules/src/subdir4/build-asm.gyp [new file with mode: 0644]
gyp/test/rules/src/subdir4/program.c [new file with mode: 0644]
gyp/test/same-gyp-name/gyptest-all.py [new file with mode: 0755]
gyp/test/same-gyp-name/gyptest-default.py [new file with mode: 0755]
gyp/test/same-gyp-name/gyptest-library.py [new file with mode: 0644]
gyp/test/same-gyp-name/library/one/sub.gyp [new file with mode: 0644]
gyp/test/same-gyp-name/library/test.gyp [new file with mode: 0644]
gyp/test/same-gyp-name/library/two/sub.gyp [new file with mode: 0644]
gyp/test/same-gyp-name/src/all.gyp [new file with mode: 0644]
gyp/test/same-gyp-name/src/subdir1/executable.gyp [new file with mode: 0644]
gyp/test/same-gyp-name/src/subdir1/main1.cc [new file with mode: 0644]
gyp/test/same-gyp-name/src/subdir2/executable.gyp [new file with mode: 0644]
gyp/test/same-gyp-name/src/subdir2/main2.cc [new file with mode: 0644]
gyp/test/same-rule-output-file-name/gyptest-all.py [new file with mode: 0644]
gyp/test/same-rule-output-file-name/src/subdir1/subdir1.gyp [new file with mode: 0644]
gyp/test/same-rule-output-file-name/src/subdir2/subdir2.gyp [new file with mode: 0644]
gyp/test/same-rule-output-file-name/src/subdirs.gyp [new file with mode: 0644]
gyp/test/same-rule-output-file-name/src/touch.py [new file with mode: 0644]
gyp/test/same-source-file-name/gyptest-all.py [new file with mode: 0755]
gyp/test/same-source-file-name/gyptest-default.py [new file with mode: 0755]
gyp/test/same-source-file-name/gyptest-pass-executable.py [new file with mode: 0755]
gyp/test/same-source-file-name/gyptest-shared.py [new file with mode: 0755]
gyp/test/same-source-file-name/gyptest-static.py [new file with mode: 0755]
gyp/test/same-source-file-name/src/all.gyp [new file with mode: 0644]
gyp/test/same-source-file-name/src/double-executable.gyp [new file with mode: 0644]
gyp/test/same-source-file-name/src/double-shared.gyp [new file with mode: 0644]
gyp/test/same-source-file-name/src/double-static.gyp [new file with mode: 0644]
gyp/test/same-source-file-name/src/func.c [new file with mode: 0644]
gyp/test/same-source-file-name/src/prog1.c [new file with mode: 0644]
gyp/test/same-source-file-name/src/prog2.c [new file with mode: 0644]
gyp/test/same-source-file-name/src/prog3.c [new file with mode: 0644]
gyp/test/same-source-file-name/src/subdir1/func.c [new file with mode: 0644]
gyp/test/same-source-file-name/src/subdir2/func.c [new file with mode: 0644]
gyp/test/same-target-name-different-directory/gyptest-all.py [new file with mode: 0644]
gyp/test/same-target-name-different-directory/src/subdir1/subdir1.gyp [new file with mode: 0644]
gyp/test/same-target-name-different-directory/src/subdir2/subdir2.gyp [new file with mode: 0644]
gyp/test/same-target-name-different-directory/src/subdirs.gyp [new file with mode: 0644]
gyp/test/same-target-name-different-directory/src/touch.py [new file with mode: 0644]
gyp/test/same-target-name/gyptest-same-target-name.py [new file with mode: 0755]
gyp/test/same-target-name/src/all.gyp [new file with mode: 0644]
gyp/test/same-target-name/src/executable1.gyp [new file with mode: 0644]
gyp/test/same-target-name/src/executable2.gyp [new file with mode: 0644]
gyp/test/sanitize-rule-names/blah.S [new file with mode: 0644]
gyp/test/sanitize-rule-names/gyptest-sanitize-rule-names.py [new file with mode: 0644]
gyp/test/sanitize-rule-names/hello.cc [new file with mode: 0644]
gyp/test/sanitize-rule-names/sanitize-rule-names.gyp [new file with mode: 0644]
gyp/test/sanitize-rule-names/script.py [new file with mode: 0644]
gyp/test/self-dependency/common.gypi [new file with mode: 0644]
gyp/test/self-dependency/dep.gyp [new file with mode: 0644]
gyp/test/self-dependency/gyptest-self-dependency.py [new file with mode: 0755]
gyp/test/self-dependency/self_dependency.gyp [new file with mode: 0644]
gyp/test/sibling/gyptest-all.py [new file with mode: 0755]
gyp/test/sibling/gyptest-relocate.py [new file with mode: 0755]
gyp/test/sibling/src/build/all.gyp [new file with mode: 0644]
gyp/test/sibling/src/prog1/prog1.c [new file with mode: 0644]
gyp/test/sibling/src/prog1/prog1.gyp [new file with mode: 0644]
gyp/test/sibling/src/prog2/prog2.c [new file with mode: 0644]
gyp/test/sibling/src/prog2/prog2.gyp [new file with mode: 0644]
gyp/test/small/gyptest-small.py [new file with mode: 0755]
gyp/test/standalone-static-library/gyptest-standalone-static-library.py [new file with mode: 0644]
gyp/test/standalone-static-library/invalid.gyp [new file with mode: 0644]
gyp/test/standalone-static-library/mylib.c [new file with mode: 0644]
gyp/test/standalone-static-library/mylib.gyp [new file with mode: 0644]
gyp/test/standalone-static-library/prog.c [new file with mode: 0644]
gyp/test/standalone/gyptest-standalone.py [new file with mode: 0644]
gyp/test/standalone/standalone.gyp [new file with mode: 0644]
gyp/test/subdirectory/gyptest-SYMROOT-all.py [new file with mode: 0755]
gyp/test/subdirectory/gyptest-SYMROOT-default.py [new file with mode: 0755]
gyp/test/subdirectory/gyptest-subdir-all.py [new file with mode: 0755]
gyp/test/subdirectory/gyptest-subdir-default.py [new file with mode: 0755]
gyp/test/subdirectory/gyptest-subdir2-deep.py [new file with mode: 0755]
gyp/test/subdirectory/gyptest-top-all.py [new file with mode: 0755]
gyp/test/subdirectory/gyptest-top-default.py [new file with mode: 0755]
gyp/test/subdirectory/src/prog1.c [new file with mode: 0644]
gyp/test/subdirectory/src/prog1.gyp [new file with mode: 0644]
gyp/test/subdirectory/src/subdir/prog2.c [new file with mode: 0644]
gyp/test/subdirectory/src/subdir/prog2.gyp [new file with mode: 0644]
gyp/test/subdirectory/src/subdir/subdir2/prog3.c [new file with mode: 0644]
gyp/test/subdirectory/src/subdir/subdir2/prog3.gyp [new file with mode: 0644]
gyp/test/subdirectory/src/symroot.gypi [new file with mode: 0644]
gyp/test/target/gyptest-target.py [new file with mode: 0644]
gyp/test/target/hello.c [new file with mode: 0644]
gyp/test/target/target.gyp [new file with mode: 0644]
gyp/test/toolsets/gyptest-toolsets.py [new file with mode: 0755]
gyp/test/toolsets/main.cc [new file with mode: 0644]
gyp/test/toolsets/toolsets.cc [new file with mode: 0644]
gyp/test/toolsets/toolsets.gyp [new file with mode: 0644]
gyp/test/toolsets/toolsets_shared.cc [new file with mode: 0644]
gyp/test/toplevel-dir/gyptest-toplevel-dir.py [new file with mode: 0755]
gyp/test/toplevel-dir/src/sub1/main.gyp [new file with mode: 0644]
gyp/test/toplevel-dir/src/sub1/prog1.c [new file with mode: 0644]
gyp/test/toplevel-dir/src/sub2/prog2.c [new file with mode: 0644]
gyp/test/toplevel-dir/src/sub2/prog2.gyp [new file with mode: 0644]
gyp/test/variables/commands/commands-repeated.gyp [new file with mode: 0644]
gyp/test/variables/commands/commands-repeated.gyp.stdout [new file with mode: 0644]
gyp/test/variables/commands/commands-repeated.gypd.golden [new file with mode: 0644]
gyp/test/variables/commands/commands.gyp [new file with mode: 0644]
gyp/test/variables/commands/commands.gyp.ignore-env.stdout [new file with mode: 0644]
gyp/test/variables/commands/commands.gyp.stdout [new file with mode: 0644]
gyp/test/variables/commands/commands.gypd.golden [new file with mode: 0644]
gyp/test/variables/commands/commands.gypi [new file with mode: 0644]
gyp/test/variables/commands/gyptest-commands-ignore-env.py [new file with mode: 0755]
gyp/test/variables/commands/gyptest-commands-repeated-multidir.py [new file with mode: 0755]
gyp/test/variables/commands/gyptest-commands-repeated.py [new file with mode: 0755]
gyp/test/variables/commands/gyptest-commands.py [new file with mode: 0755]
gyp/test/variables/commands/repeated_multidir/dir_1/test_1.gyp [new file with mode: 0644]
gyp/test/variables/commands/repeated_multidir/dir_2/test_2.gyp [new file with mode: 0644]
gyp/test/variables/commands/repeated_multidir/main.gyp [new file with mode: 0644]
gyp/test/variables/commands/repeated_multidir/print_cwd_basename.py [new file with mode: 0755]
gyp/test/variables/commands/repeated_multidir/repeated_command_common.gypi [new file with mode: 0644]
gyp/test/variables/commands/test.py [new file with mode: 0644]
gyp/test/variables/commands/update_golden [new file with mode: 0755]
gyp/test/variables/filelist/filelist.gyp.stdout [new file with mode: 0644]
gyp/test/variables/filelist/filelist.gypd.golden [new file with mode: 0644]
gyp/test/variables/filelist/gyptest-filelist-golden.py [new file with mode: 0644]
gyp/test/variables/filelist/gyptest-filelist.py [new file with mode: 0755]
gyp/test/variables/filelist/src/dummy.py [new file with mode: 0644]
gyp/test/variables/filelist/src/filelist.gyp [new file with mode: 0644]
gyp/test/variables/filelist/src/filelist2.gyp [new file with mode: 0644]
gyp/test/variables/filelist/update_golden [new file with mode: 0755]
gyp/test/variables/latelate/gyptest-latelate.py [new file with mode: 0755]
gyp/test/variables/latelate/src/latelate.gyp [new file with mode: 0644]
gyp/test/variables/latelate/src/program.cc [new file with mode: 0644]
gyp/test/variables/variable-in-path/C1/hello.cc [new file with mode: 0644]
gyp/test/variables/variable-in-path/gyptest-variable-in-path.py [new file with mode: 0644]
gyp/test/variables/variable-in-path/variable-in-path.gyp [new file with mode: 0644]
gyp/test/win/asm-files/asm-files.gyp [new file with mode: 0644]
gyp/test/win/asm-files/b.s [new file with mode: 0644]
gyp/test/win/asm-files/c.S [new file with mode: 0644]
gyp/test/win/asm-files/hello.cc [new file with mode: 0644]
gyp/test/win/batch-file-action/batch-file-action.gyp [new file with mode: 0644]
gyp/test/win/batch-file-action/infile [new file with mode: 0644]
gyp/test/win/batch-file-action/somecmd.bat [new file with mode: 0644]
gyp/test/win/command-quote/a.S [new file with mode: 0644]
gyp/test/win/command-quote/bat with spaces.bat [new file with mode: 0644]
gyp/test/win/command-quote/command-quote.gyp [new file with mode: 0644]
gyp/test/win/command-quote/go.bat [new file with mode: 0644]
gyp/test/win/command-quote/subdir/and/another/in-subdir.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/additional-include-dirs.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/additional-include-dirs.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/additional-options.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/additional-options.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/analysis.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/buffer-security-check.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/buffer-security.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/character-set-mbcs.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/character-set-unicode.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/character-set.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/debug-format.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/default-char-is-unsigned.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/default-char-is-unsigned.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/disable-specific-warnings.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/disable-specific-warnings.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/enable-enhanced-instruction-set.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/enable-enhanced-instruction-set.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/exception-handling-on.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/exception-handling.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/force-include-files-with-precompiled.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/force-include-files.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/force-include-files.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/function-level-linking.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/function-level-linking.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/hello.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/optimizations.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/pdbname-override.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/pdbname.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/pdbname.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/precomp.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/rtti-on.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/rtti.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/runtime-checks.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/runtime-checks.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/runtime-library-md.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/runtime-library-mdd.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/runtime-library-mt.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/runtime-library-mtd.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/runtime-library.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/subdir/header.h [new file with mode: 0644]
gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type1.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type2.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/uninit.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/warning-as-error.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/warning-as-error.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/warning-level.gyp [new file with mode: 0644]
gyp/test/win/compiler-flags/warning-level1.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/warning-level2.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/warning-level3.cc [new file with mode: 0644]
gyp/test/win/compiler-flags/warning-level4.cc [new file with mode: 0644]
gyp/test/win/generator-output-different-drive/gyptest-generator-output-different-drive.py [new file with mode: 0644]
gyp/test/win/generator-output-different-drive/prog.c [new file with mode: 0644]
gyp/test/win/generator-output-different-drive/prog.gyp [new file with mode: 0644]
gyp/test/win/gyptest-asm-files.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-additional-include-dirs.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-additional-options.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-analysis.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-buffer-security-check.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-character-set.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-debug-format.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-default-char-is-unsigned.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-disable-specific-warnings.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-enable-enhanced-instruction-set.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-exception-handling.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-force-include-files.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-function-level-linking.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-optimizations.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-pdbname-override.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-pdbname.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-rtti.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-runtime-checks.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-runtime-library.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-treat-wchar-t-as-built-in-type.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-warning-as-error.py [new file with mode: 0644]
gyp/test/win/gyptest-cl-warning-level.py [new file with mode: 0644]
gyp/test/win/gyptest-command-quote.py [new file with mode: 0644]
gyp/test/win/gyptest-lib-ltcg.py [new file with mode: 0644]
gyp/test/win/gyptest-link-additional-deps.py [new file with mode: 0644]
gyp/test/win/gyptest-link-additional-options.py [new file with mode: 0644]
gyp/test/win/gyptest-link-aslr.py [new file with mode: 0644]
gyp/test/win/gyptest-link-base-address.py [new file with mode: 0644]
gyp/test/win/gyptest-link-debug-info.py [new file with mode: 0644]
gyp/test/win/gyptest-link-default-libs.py [new file with mode: 0644]
gyp/test/win/gyptest-link-deffile.py [new file with mode: 0644]
gyp/test/win/gyptest-link-defrelink.py [new file with mode: 0644]
gyp/test/win/gyptest-link-delay-load-dlls.py [new file with mode: 0644]
gyp/test/win/gyptest-link-embed-manifest.py [new file with mode: 0644]
gyp/test/win/gyptest-link-enable-uac.py [new file with mode: 0644]
gyp/test/win/gyptest-link-entrypointsymbol.py [new file with mode: 0644]
gyp/test/win/gyptest-link-fixed-base.py [new file with mode: 0644]
gyp/test/win/gyptest-link-force-symbol-reference.py [new file with mode: 0644]
gyp/test/win/gyptest-link-generate-manifest.py [new file with mode: 0644]
gyp/test/win/gyptest-link-incremental.py [new file with mode: 0644]
gyp/test/win/gyptest-link-large-address-aware.py [new file with mode: 0644]
gyp/test/win/gyptest-link-large-pdb.py [new file with mode: 0644]
gyp/test/win/gyptest-link-library-adjust.py [new file with mode: 0644]
gyp/test/win/gyptest-link-library-directories.py [new file with mode: 0644]
gyp/test/win/gyptest-link-ltcg.py [new file with mode: 0644]
gyp/test/win/gyptest-link-mapfile.py [new file with mode: 0644]
gyp/test/win/gyptest-link-nodefaultlib.py [new file with mode: 0644]
gyp/test/win/gyptest-link-nxcompat.py [new file with mode: 0644]
gyp/test/win/gyptest-link-opt-icf.py [new file with mode: 0644]
gyp/test/win/gyptest-link-opt-ref.py [new file with mode: 0644]
gyp/test/win/gyptest-link-ordering.py [new file with mode: 0644]
gyp/test/win/gyptest-link-outputfile.py [new file with mode: 0644]
gyp/test/win/gyptest-link-pdb-output.py [new file with mode: 0644]
gyp/test/win/gyptest-link-pdb.py [new file with mode: 0644]
gyp/test/win/gyptest-link-pgo.py [new file with mode: 0644]
gyp/test/win/gyptest-link-profile.py [new file with mode: 0644]
gyp/test/win/gyptest-link-restat-importlib.py [new file with mode: 0644]
gyp/test/win/gyptest-link-safeseh.py [new file with mode: 0644]
gyp/test/win/gyptest-link-shard.py [new file with mode: 0644]
gyp/test/win/gyptest-link-subsystem.py [new file with mode: 0644]
gyp/test/win/gyptest-link-target-machine.py [new file with mode: 0644]
gyp/test/win/gyptest-link-tsaware.py [new file with mode: 0644]
gyp/test/win/gyptest-link-uldi.py [new file with mode: 0644]
gyp/test/win/gyptest-link-unsupported-manifest.py [new file with mode: 0644]
gyp/test/win/gyptest-link-update-manifest.py [new file with mode: 0644]
gyp/test/win/gyptest-link-warnings-as-errors.py [new file with mode: 0644]
gyp/test/win/gyptest-long-command-line.py [new file with mode: 0644]
gyp/test/win/gyptest-macro-projectname.py [new file with mode: 0644]
gyp/test/win/gyptest-macro-targetname.py [new file with mode: 0644]
gyp/test/win/gyptest-macro-vcinstalldir.py [new file with mode: 0644]
gyp/test/win/gyptest-macros-containing-gyp.py [new file with mode: 0644]
gyp/test/win/gyptest-macros-in-inputs-and-outputs.py [new file with mode: 0644]
gyp/test/win/gyptest-midl-excluded.py [new file with mode: 0644]
gyp/test/win/gyptest-midl-rules.py [new file with mode: 0644]
gyp/test/win/gyptest-ml-safeseh.py [new file with mode: 0644]
gyp/test/win/gyptest-quoting-commands.py [new file with mode: 0644]
gyp/test/win/gyptest-rc-build.py [new file with mode: 0644]
gyp/test/win/gyptest-system-include.py [new file with mode: 0644]
gyp/test/win/idl-excluded/bad.idl [new file with mode: 0644]
gyp/test/win/idl-excluded/copy-file.py [new file with mode: 0644]
gyp/test/win/idl-excluded/idl-excluded.gyp [new file with mode: 0644]
gyp/test/win/idl-excluded/program.cc [new file with mode: 0644]
gyp/test/win/idl-rules/Window.idl [new file with mode: 0644]
gyp/test/win/idl-rules/basic-idl.gyp [new file with mode: 0644]
gyp/test/win/idl-rules/history_indexer.idl [new file with mode: 0644]
gyp/test/win/idl-rules/history_indexer_user.cc [new file with mode: 0644]
gyp/test/win/idl-rules/idl_compiler.py [new file with mode: 0644]
gyp/test/win/importlib/has-exports.cc [new file with mode: 0644]
gyp/test/win/importlib/hello.cc [new file with mode: 0644]
gyp/test/win/importlib/importlib.gyp [new file with mode: 0644]
gyp/test/win/large-pdb/dllmain.cc [new file with mode: 0644]
gyp/test/win/large-pdb/large-pdb.gyp [new file with mode: 0644]
gyp/test/win/large-pdb/main.cc [new file with mode: 0644]
gyp/test/win/lib-flags/answer.cc [new file with mode: 0644]
gyp/test/win/lib-flags/answer.h [new file with mode: 0644]
gyp/test/win/lib-flags/ltcg.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/a/x.cc [new file with mode: 0644]
gyp/test/win/linker-flags/a/z.cc [new file with mode: 0644]
gyp/test/win/linker-flags/additional-deps.cc [new file with mode: 0644]
gyp/test/win/linker-flags/additional-deps.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/additional-options.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/aslr.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/b/y.cc [new file with mode: 0644]
gyp/test/win/linker-flags/base-address.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/debug-info.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/deffile-multiple.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/deffile.cc [new file with mode: 0644]
gyp/test/win/linker-flags/deffile.def [new file with mode: 0644]
gyp/test/win/linker-flags/deffile.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/delay-load-dlls.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/delay-load.cc [new file with mode: 0644]
gyp/test/win/linker-flags/embed-manifest.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/enable-uac.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/entrypointsymbol.cc [new file with mode: 0644]
gyp/test/win/linker-flags/entrypointsymbol.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/extra.manifest [new file with mode: 0644]
gyp/test/win/linker-flags/extra2.manifest [new file with mode: 0644]
gyp/test/win/linker-flags/fixed-base.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/force-symbol-reference.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/generate-manifest.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/hello.cc [new file with mode: 0644]
gyp/test/win/linker-flags/incremental.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/inline_test.cc [new file with mode: 0644]
gyp/test/win/linker-flags/inline_test.h [new file with mode: 0644]
gyp/test/win/linker-flags/inline_test_main.cc [new file with mode: 0644]
gyp/test/win/linker-flags/large-address-aware.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/library-adjust.cc [new file with mode: 0644]
gyp/test/win/linker-flags/library-adjust.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/library-directories-define.cc [new file with mode: 0644]
gyp/test/win/linker-flags/library-directories-reference.cc [new file with mode: 0644]
gyp/test/win/linker-flags/library-directories.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/link-ordering.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/link-warning.cc [new file with mode: 0644]
gyp/test/win/linker-flags/ltcg.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/main-crt.c [new file with mode: 0644]
gyp/test/win/linker-flags/manifest-in-comment.cc [new file with mode: 0644]
gyp/test/win/linker-flags/mapfile.cc [new file with mode: 0644]
gyp/test/win/linker-flags/mapfile.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/no-default-libs.cc [new file with mode: 0644]
gyp/test/win/linker-flags/no-default-libs.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/nodefaultlib.cc [new file with mode: 0644]
gyp/test/win/linker-flags/nodefaultlib.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/nxcompat.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/opt-icf.cc [new file with mode: 0644]
gyp/test/win/linker-flags/opt-icf.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/opt-ref.cc [new file with mode: 0644]
gyp/test/win/linker-flags/opt-ref.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/outputfile.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/pdb-output.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/pgo.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/profile.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/program-database.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/safeseh.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/safeseh_hello.cc [new file with mode: 0644]
gyp/test/win/linker-flags/safeseh_zero.asm [new file with mode: 0644]
gyp/test/win/linker-flags/subdir/library.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/subsystem-windows.cc [new file with mode: 0644]
gyp/test/win/linker-flags/subsystem.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/target-machine.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/tsaware.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/unsupported-manifest.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/update_pgd.py [new file with mode: 0644]
gyp/test/win/linker-flags/warn-as-error.gyp [new file with mode: 0644]
gyp/test/win/linker-flags/x.cc [new file with mode: 0644]
gyp/test/win/linker-flags/y.cc [new file with mode: 0644]
gyp/test/win/linker-flags/z.cc [new file with mode: 0644]
gyp/test/win/long-command-line/function.cc [new file with mode: 0644]
gyp/test/win/long-command-line/hello.cc [new file with mode: 0644]
gyp/test/win/long-command-line/long-command-line.gyp [new file with mode: 0644]
gyp/test/win/ml-safeseh/a.asm [new file with mode: 0644]
gyp/test/win/ml-safeseh/hello.cc [new file with mode: 0644]
gyp/test/win/ml-safeseh/ml-safeseh.gyp [new file with mode: 0644]
gyp/test/win/precompiled/gyptest-all.py [new file with mode: 0644]
gyp/test/win/precompiled/hello.c [new file with mode: 0644]
gyp/test/win/precompiled/hello.gyp [new file with mode: 0644]
gyp/test/win/precompiled/hello2.c [new file with mode: 0644]
gyp/test/win/precompiled/precomp.c [new file with mode: 0644]
gyp/test/win/rc-build/Resource.h [new file with mode: 0644]
gyp/test/win/rc-build/hello.cpp [new file with mode: 0644]
gyp/test/win/rc-build/hello.gyp [new file with mode: 0644]
gyp/test/win/rc-build/hello.h [new file with mode: 0644]
gyp/test/win/rc-build/hello.ico [new file with mode: 0644]
gyp/test/win/rc-build/hello.rc [new file with mode: 0644]
gyp/test/win/rc-build/hello3.rc [new file with mode: 0644]
gyp/test/win/rc-build/small.ico [new file with mode: 0644]
gyp/test/win/rc-build/subdir/hello2.rc [new file with mode: 0644]
gyp/test/win/rc-build/subdir/include.h [new file with mode: 0644]
gyp/test/win/rc-build/targetver.h [new file with mode: 0644]
gyp/test/win/shard/hello.cc [new file with mode: 0644]
gyp/test/win/shard/hello1.cc [new file with mode: 0644]
gyp/test/win/shard/hello2.cc [new file with mode: 0644]
gyp/test/win/shard/hello3.cc [new file with mode: 0644]
gyp/test/win/shard/hello4.cc [new file with mode: 0644]
gyp/test/win/shard/shard.gyp [new file with mode: 0644]
gyp/test/win/shard/shard_ref.gyp [new file with mode: 0644]
gyp/test/win/system-include/bar/header.h [new file with mode: 0644]
gyp/test/win/system-include/common/commonheader.h [new file with mode: 0644]
gyp/test/win/system-include/foo/header.h [new file with mode: 0644]
gyp/test/win/system-include/main.cc [new file with mode: 0644]
gyp/test/win/system-include/test.gyp [new file with mode: 0644]
gyp/test/win/uldi/a.cc [new file with mode: 0644]
gyp/test/win/uldi/b.cc [new file with mode: 0644]
gyp/test/win/uldi/main.cc [new file with mode: 0644]
gyp/test/win/uldi/uldi.gyp [new file with mode: 0644]
gyp/test/win/vs-macros/as.py [new file with mode: 0644]
gyp/test/win/vs-macros/containing-gyp.gyp [new file with mode: 0644]
gyp/test/win/vs-macros/do_stuff.py [new file with mode: 0644]
gyp/test/win/vs-macros/hello.cc [new file with mode: 0644]
gyp/test/win/vs-macros/input-output-macros.gyp [new file with mode: 0644]
gyp/test/win/vs-macros/input.S [new file with mode: 0644]
gyp/test/win/vs-macros/projectname.gyp [new file with mode: 0644]
gyp/test/win/vs-macros/stuff.blah [new file with mode: 0644]
gyp/test/win/vs-macros/targetname.gyp [new file with mode: 0644]
gyp/test/win/vs-macros/test_exists.py [new file with mode: 0644]
gyp/test/win/vs-macros/vcinstalldir.gyp [new file with mode: 0644]
gyp/test/win/win-tool/copies_readonly_files.gyp [new file with mode: 0644]
gyp/test/win/win-tool/gyptest-win-tool-handles-readonly-files.py [new file with mode: 0644]
gyp/tools/README [new file with mode: 0644]
gyp/tools/Xcode/README [new file with mode: 0644]
gyp/tools/Xcode/Specifications/gyp.pbfilespec [new file with mode: 0644]
gyp/tools/Xcode/Specifications/gyp.xclangspec [new file with mode: 0644]
gyp/tools/emacs/README [new file with mode: 0644]
gyp/tools/emacs/gyp-tests.el [new file with mode: 0644]
gyp/tools/emacs/gyp.el [new file with mode: 0644]
gyp/tools/emacs/run-unit-tests.sh [new file with mode: 0755]
gyp/tools/emacs/testdata/media.gyp [new file with mode: 0644]
gyp/tools/emacs/testdata/media.gyp.fontified [new file with mode: 0644]
gyp/tools/graphviz.py [new file with mode: 0755]
gyp/tools/pretty_gyp.py [new file with mode: 0755]
gyp/tools/pretty_sln.py [new file with mode: 0755]
gyp/tools/pretty_vcproj.py [new file with mode: 0755]

diff --git a/gyp/AUTHORS b/gyp/AUTHORS
new file mode 100644 (file)
index 0000000..9389ca0
--- /dev/null
@@ -0,0 +1,11 @@
+# Names should be added to this file like so:
+# Name or Organization <email address>
+
+Google Inc.
+Bloomberg Finance L.P.
+Yandex LLC
+
+Steven Knight <knight@baldmt.com>
+Ryan Norton <rnorton10@gmail.com>
+David J. Sankel <david@sankelsoftware.com>
+Eric N. Vander Weele <ericvw@gmail.com>
diff --git a/gyp/DEPS b/gyp/DEPS
new file mode 100644 (file)
index 0000000..2e1120f
--- /dev/null
+++ b/gyp/DEPS
@@ -0,0 +1,24 @@
+# DEPS file for gclient use in buildbot execution of gyp tests.
+#
+# (You don't need to use gclient for normal GYP development work.)
+
+vars = {
+  "chrome_trunk": "http://src.chromium.org/svn/trunk",
+  "googlecode_url": "http://%s.googlecode.com/svn",
+}
+
+deps = {
+}
+
+deps_os = {
+  "win": {
+    "third_party/cygwin":
+      Var("chrome_trunk") + "/deps/third_party/cygwin@66844",
+
+    "third_party/python_26":
+      Var("chrome_trunk") + "/tools/third_party/python_26@89111",
+
+    "src/third_party/pefile":
+      (Var("googlecode_url") % "pefile") + "/trunk@63",
+  },
+}
diff --git a/gyp/LICENSE b/gyp/LICENSE
new file mode 100644 (file)
index 0000000..ab6b011
--- /dev/null
@@ -0,0 +1,27 @@
+Copyright (c) 2009 Google Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/gyp/OWNERS b/gyp/OWNERS
new file mode 100644 (file)
index 0000000..72e8ffc
--- /dev/null
@@ -0,0 +1 @@
+*
diff --git a/gyp/PRESUBMIT.py b/gyp/PRESUBMIT.py
new file mode 100644 (file)
index 0000000..b79316a
--- /dev/null
@@ -0,0 +1,118 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+"""Top-level presubmit script for GYP.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into gcl.
+"""
+
+
+PYLINT_BLACKLIST = [
+    # TODO: fix me.
+    # From SCons, not done in google style.
+    'test/lib/TestCmd.py',
+    'test/lib/TestCommon.py',
+    'test/lib/TestGyp.py',
+]
+
+
+PYLINT_DISABLED_WARNINGS = [
+    # TODO: fix me.
+    # Many tests include modules they don't use.
+    'W0611',
+    # Include order doesn't properly include local files?
+    'F0401',
+    # Some use of built-in names.
+    'W0622',
+    # Some unused variables.
+    'W0612',
+    # Operator not preceded/followed by space.
+    'C0323',
+    'C0322',
+    # Unnecessary semicolon.
+    'W0301',
+    # Unused argument.
+    'W0613',
+    # String has no effect (docstring in wrong place).
+    'W0105',
+    # Comma not followed by space.
+    'C0324',
+    # Access to a protected member.
+    'W0212',
+    # Bad indent.
+    'W0311',
+    # Line too long.
+    'C0301',
+    # Undefined variable.
+    'E0602',
+    # Not exception type specified.
+    'W0702',
+    # No member of that name.
+    'E1101',
+    # Dangerous default {}.
+    'W0102',
+    # Others, too many to sort.
+    'W0201', 'W0232', 'E1103', 'W0621', 'W0108', 'W0223', 'W0231',
+    'R0201', 'E0101', 'C0321',
+    # ************* Module copy
+    # W0104:427,12:_test.odict.__setitem__: Statement seems to have no effect
+    'W0104',
+]
+
+
+def CheckChangeOnUpload(input_api, output_api):
+  report = []
+  report.extend(input_api.canned_checks.PanProjectChecks(
+      input_api, output_api))
+  return report
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  report = []
+
+  # Accept any year number from 2009 to the current year.
+  current_year = int(input_api.time.strftime('%Y'))
+  allowed_years = (str(s) for s in reversed(xrange(2009, current_year + 1)))
+  years_re = '(' + '|'.join(allowed_years) + ')'
+
+  # The (c) is deprecated, but tolerate it until it's removed from all files.
+  license = (
+      r'.*? Copyright (\(c\) )?%(year)s Google Inc\. All rights reserved\.\n'
+      r'.*? Use of this source code is governed by a BSD-style license that '
+        r'can be\n'
+      r'.*? found in the LICENSE file\.\n'
+  ) % {
+      'year': years_re,
+  }
+
+  report.extend(input_api.canned_checks.PanProjectChecks(
+      input_api, output_api, license_header=license))
+  report.extend(input_api.canned_checks.CheckTreeIsOpen(
+      input_api, output_api,
+      'http://gyp-status.appspot.com/status',
+      'http://gyp-status.appspot.com/current'))
+
+  import os
+  import sys
+  old_sys_path = sys.path
+  try:
+    sys.path = ['pylib', 'test/lib'] + sys.path
+    blacklist = PYLINT_BLACKLIST
+    if sys.platform == 'win32':
+      blacklist = [os.path.normpath(x).replace('\\', '\\\\')
+                   for x in PYLINT_BLACKLIST]
+    report.extend(input_api.canned_checks.RunPylint(
+        input_api,
+        output_api,
+        black_list=blacklist,
+        disabled_warnings=PYLINT_DISABLED_WARNINGS))
+  finally:
+    sys.path = old_sys_path
+  return report
+
+
+def GetPreferredTrySlaves():
+  return ['gyp-win32', 'gyp-win64', 'gyp-linux', 'gyp-mac', 'gyp-android']
diff --git a/gyp/buildbot/buildbot_run.py b/gyp/buildbot/buildbot_run.py
new file mode 100755 (executable)
index 0000000..b20a424
--- /dev/null
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+"""Argument-less script to select what to run on the buildbots."""
+
+
+import os
+import shutil
+import subprocess
+import sys
+
+
+if sys.platform in ['win32', 'cygwin']:
+  EXE_SUFFIX = '.exe'
+else:
+  EXE_SUFFIX = ''
+
+
+BUILDBOT_DIR = os.path.dirname(os.path.abspath(__file__))
+TRUNK_DIR = os.path.dirname(BUILDBOT_DIR)
+ROOT_DIR = os.path.dirname(TRUNK_DIR)
+ANDROID_DIR = os.path.join(ROOT_DIR, 'android')
+CMAKE_DIR = os.path.join(ROOT_DIR, 'cmake')
+CMAKE_BIN_DIR = os.path.join(CMAKE_DIR, 'bin')
+OUT_DIR = os.path.join(TRUNK_DIR, 'out')
+
+
+def CallSubProcess(*args, **kwargs):
+  """Wrapper around subprocess.call which treats errors as build exceptions."""
+  retcode = subprocess.call(*args, **kwargs)
+  if retcode != 0:
+    print '@@@STEP_EXCEPTION@@@'
+    sys.exit(1)
+
+
+def PrepareCmake():
+  """Build CMake 2.8.8 since the version in Precise is 2.8.7."""
+  if os.environ['BUILDBOT_CLOBBER'] == '1':
+    print '@@@BUILD_STEP Clobber CMake checkout@@@'
+    shutil.rmtree(CMAKE_DIR)
+
+  # We always build CMake 2.8.8, so no need to do anything
+  # if the directory already exists.
+  if os.path.isdir(CMAKE_DIR):
+    return
+
+  print '@@@BUILD_STEP Initialize CMake checkout@@@'
+  os.mkdir(CMAKE_DIR)
+  CallSubProcess(['git', 'config', '--global', 'user.name', 'trybot'])
+  CallSubProcess(['git', 'config', '--global',
+                  'user.email', 'chrome-bot@google.com'])
+  CallSubProcess(['git', 'config', '--global', 'color.ui', 'false'])
+
+  print '@@@BUILD_STEP Sync CMake@@@'
+  CallSubProcess(
+      ['git', 'clone',
+       '--depth', '1',
+       '--single-branch',
+       '--branch', 'v2.8.8',
+       '--',
+       'git://cmake.org/cmake.git',
+       CMAKE_DIR],
+      cwd=CMAKE_DIR)
+
+  print '@@@BUILD_STEP Build CMake@@@'
+  CallSubProcess(
+      ['/bin/bash', 'bootstrap', '--prefix=%s' % CMAKE_DIR],
+      cwd=CMAKE_DIR)
+
+  CallSubProcess( ['make', 'cmake'], cwd=CMAKE_DIR)
+
+
+_ANDROID_SETUP = 'source build/envsetup.sh && lunch full-eng'
+
+
+def PrepareAndroidTree():
+  """Prepare an Android tree to run 'android' format tests."""
+  if os.environ['BUILDBOT_CLOBBER'] == '1':
+    print '@@@BUILD_STEP Clobber Android checkout@@@'
+    shutil.rmtree(ANDROID_DIR)
+
+  # The release of Android we use is static, so there's no need to do anything
+  # if the directory already exists.
+  if os.path.isdir(ANDROID_DIR):
+    return
+
+  print '@@@BUILD_STEP Initialize Android checkout@@@'
+  os.mkdir(ANDROID_DIR)
+  CallSubProcess(['git', 'config', '--global', 'user.name', 'trybot'])
+  CallSubProcess(['git', 'config', '--global',
+                  'user.email', 'chrome-bot@google.com'])
+  CallSubProcess(['git', 'config', '--global', 'color.ui', 'false'])
+  CallSubProcess(
+      ['repo', 'init',
+       '-u', 'https://android.googlesource.com/platform/manifest',
+       '-b', 'android-4.2.1_r1',
+       '-g', 'all,-notdefault,-device,-darwin,-mips,-x86'],
+      cwd=ANDROID_DIR)
+
+  print '@@@BUILD_STEP Sync Android@@@'
+  CallSubProcess(['repo', 'sync', '-j4'], cwd=ANDROID_DIR)
+
+  print '@@@BUILD_STEP Build Android@@@'
+  CallSubProcess(
+      ['/bin/bash',
+       '-c', '%s && make -j4' % _ANDROID_SETUP],
+      cwd=ANDROID_DIR)
+
+
+def StartAndroidEmulator():
+  """Start an android emulator from the built android tree."""
+  print '@@@BUILD_STEP Start Android emulator@@@'
+  android_host_bin = '$ANDROID_HOST_OUT/bin'
+  subprocess.Popen(
+      ['/bin/bash', '-c',
+       '%s && %s/emulator -no-window' % (_ANDROID_SETUP, android_host_bin)],
+      cwd=ANDROID_DIR)
+  CallSubProcess(
+      ['/bin/bash', '-c',
+       '%s && %s/adb wait-for-device' % (_ANDROID_SETUP, android_host_bin)],
+      cwd=ANDROID_DIR)
+
+
+def StopAndroidEmulator():
+  """Stop all android emulators."""
+  print '@@@BUILD_STEP Stop Android emulator@@@'
+  # If this fails, it's because there is no emulator running.
+  subprocess.call(['pkill', 'emulator.*'])
+
+
+def GypTestFormat(title, format=None, msvs_version=None, tests=[]):
+  """Run the gyp tests for a given format, emitting annotator tags.
+
+  See annotator docs at:
+    https://sites.google.com/a/chromium.org/dev/developers/testing/chromium-build-infrastructure/buildbot-annotations
+  Args:
+    format: gyp format to test.
+  Returns:
+    0 for sucesss, 1 for failure.
+  """
+  if not format:
+    format = title
+
+  print '@@@BUILD_STEP ' + title + '@@@'
+  sys.stdout.flush()
+  env = os.environ.copy()
+  if msvs_version:
+    env['GYP_MSVS_VERSION'] = msvs_version
+  command = ' '.join(
+      [sys.executable, 'trunk/gyptest.py',
+       '--all',
+       '--passed',
+       '--format', format,
+       '--path', CMAKE_BIN_DIR,
+       '--chdir', 'trunk'] + tests)
+  if format == 'android':
+    # gyptest needs the environment setup from envsetup/lunch in order to build
+    # using the 'android' backend, so this is done in a single shell.
+    retcode = subprocess.call(
+        ['/bin/bash',
+         '-c', '%s && cd %s && %s' % (_ANDROID_SETUP, ROOT_DIR, command)],
+        cwd=ANDROID_DIR, env=env)
+  else:
+    retcode = subprocess.call(command, cwd=ROOT_DIR, env=env, shell=True)
+  if retcode:
+    # Emit failure tag, and keep going.
+    print '@@@STEP_FAILURE@@@'
+    return 1
+  return 0
+
+
+def GypBuild():
+  # Dump out/ directory.
+  print '@@@BUILD_STEP cleanup@@@'
+  print 'Removing %s...' % OUT_DIR
+  shutil.rmtree(OUT_DIR, ignore_errors=True)
+  print 'Done.'
+
+  retcode = 0
+  # The Android gyp bot runs on linux so this must be tested first.
+  if os.environ['BUILDBOT_BUILDERNAME'] == 'gyp-android':
+    PrepareAndroidTree()
+    StartAndroidEmulator()
+    try:
+      retcode += GypTestFormat('android')
+    finally:
+      StopAndroidEmulator()
+  elif sys.platform.startswith('linux'):
+    retcode += GypTestFormat('ninja')
+    retcode += GypTestFormat('make')
+    PrepareCmake()
+    retcode += GypTestFormat('cmake')
+  elif sys.platform == 'darwin':
+    retcode += GypTestFormat('ninja')
+    retcode += GypTestFormat('xcode')
+    retcode += GypTestFormat('make')
+  elif sys.platform == 'win32':
+    retcode += GypTestFormat('ninja')
+    if os.environ['BUILDBOT_BUILDERNAME'] == 'gyp-win64':
+      retcode += GypTestFormat('msvs-ninja-2012', format='msvs-ninja',
+                               msvs_version='2012',
+                               tests=[
+                                   'test\generator-output\gyptest-actions.py',
+                                   'test\generator-output\gyptest-relocate.py',
+                                   'test\generator-output\gyptest-rules.py'])
+      retcode += GypTestFormat('msvs-2010', format='msvs', msvs_version='2010')
+      retcode += GypTestFormat('msvs-2012', format='msvs', msvs_version='2012')
+  else:
+    raise Exception('Unknown platform')
+  if retcode:
+    # TODO(bradnelson): once the annotator supports a postscript (section for
+    #     after the build proper that could be used for cumulative failures),
+    #     use that instead of this. This isolates the final return value so
+    #     that it isn't misattributed to the last stage.
+    print '@@@BUILD_STEP failures@@@'
+    sys.exit(retcode)
+
+
+if __name__ == '__main__':
+  GypBuild()
diff --git a/gyp/codereview.settings b/gyp/codereview.settings
new file mode 100644 (file)
index 0000000..a04a244
--- /dev/null
@@ -0,0 +1,10 @@
+# This file is used by gcl to get repository specific information.
+CODE_REVIEW_SERVER: codereview.chromium.org
+CC_LIST: gyp-developer@googlegroups.com
+VIEW_VC: http://code.google.com/p/gyp/source/detail?r=
+TRY_ON_UPLOAD: True
+TRYSERVER_PROJECT: gyp
+TRYSERVER_PATCHLEVEL: 0
+TRYSERVER_ROOT: trunk
+TRYSERVER_SVN_URL: svn://svn.chromium.org/chrome-try/try-nacl
+
diff --git a/gyp/data/win/large-pdb-shim.cc b/gyp/data/win/large-pdb-shim.cc
new file mode 100644 (file)
index 0000000..8bca510
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is used to generate an empty .pdb -- with a 4KB pagesize -- that is
+// then used during the final link for modules that have large PDBs. Otherwise,
+// the linker will generate a pdb with a page size of 1KB, which imposes a limit
+// of 1GB on the .pdb. By generating an initial empty .pdb with the compiler
+// (rather than the linker), this limit is avoided. With this in place PDBs may
+// grow to 2GB.
+//
+// This file is referenced by the msvs_large_pdb mechanism in MSVSUtil.py.
diff --git a/gyp/gyp b/gyp/gyp
new file mode 100755 (executable)
index 0000000..b53a6dd
--- /dev/null
+++ b/gyp/gyp
@@ -0,0 +1,8 @@
+#!/bin/bash
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+base=$(dirname "$0")
+exec python "${base}/gyp_main.py" "$@"
diff --git a/gyp/gyp.bat b/gyp/gyp.bat
new file mode 100755 (executable)
index 0000000..c0b4ca2
--- /dev/null
@@ -0,0 +1,5 @@
+@rem Copyright (c) 2009 Google Inc. All rights reserved.\r
+@rem Use of this source code is governed by a BSD-style license that can be\r
+@rem found in the LICENSE file.\r
+\r
+@python "%~dp0gyp_main.py" %*\r
diff --git a/gyp/gyp_main.py b/gyp/gyp_main.py
new file mode 100755 (executable)
index 0000000..4ec872f
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+# TODO(mark): sys.path manipulation is some temporary testing stuff.
+try:
+  import gyp
+except ImportError, e:
+  import os.path
+  sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'pylib'))
+  import gyp
+
+if __name__ == '__main__':
+  sys.exit(gyp.script_main())
diff --git a/gyp/gyptest.py b/gyp/gyptest.py
new file mode 100755 (executable)
index 0000000..8f3ee0f
--- /dev/null
@@ -0,0 +1,274 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+__doc__ = """
+gyptest.py -- test runner for GYP tests.
+"""
+
+import os
+import optparse
+import subprocess
+import sys
+
+class CommandRunner:
+  """
+  Executor class for commands, including "commands" implemented by
+  Python functions.
+  """
+  verbose = True
+  active = True
+
+  def __init__(self, dictionary={}):
+    self.subst_dictionary(dictionary)
+
+  def subst_dictionary(self, dictionary):
+    self._subst_dictionary = dictionary
+
+  def subst(self, string, dictionary=None):
+    """
+    Substitutes (via the format operator) the values in the specified
+    dictionary into the specified command.
+
+    The command can be an (action, string) tuple.  In all cases, we
+    perform substitution on strings and don't worry if something isn't
+    a string.  (It's probably a Python function to be executed.)
+    """
+    if dictionary is None:
+      dictionary = self._subst_dictionary
+    if dictionary:
+      try:
+        string = string % dictionary
+      except TypeError:
+        pass
+    return string
+
+  def display(self, command, stdout=None, stderr=None):
+    if not self.verbose:
+      return
+    if type(command) == type(()):
+      func = command[0]
+      args = command[1:]
+      s = '%s(%s)' % (func.__name__, ', '.join(map(repr, args)))
+    if type(command) == type([]):
+      # TODO:  quote arguments containing spaces
+      # TODO:  handle meta characters?
+      s = ' '.join(command)
+    else:
+      s = self.subst(command)
+    if not s.endswith('\n'):
+      s += '\n'
+    sys.stdout.write(s)
+    sys.stdout.flush()
+
+  def execute(self, command, stdout=None, stderr=None):
+    """
+    Executes a single command.
+    """
+    if not self.active:
+      return 0
+    if type(command) == type(''):
+      command = self.subst(command)
+      cmdargs = shlex.split(command)
+      if cmdargs[0] == 'cd':
+         command = (os.chdir,) + tuple(cmdargs[1:])
+    if type(command) == type(()):
+      func = command[0]
+      args = command[1:]
+      return func(*args)
+    else:
+      if stdout is sys.stdout:
+        # Same as passing sys.stdout, except python2.4 doesn't fail on it.
+        subout = None
+      else:
+        # Open pipe for anything else so Popen works on python2.4.
+        subout = subprocess.PIPE
+      if stderr is sys.stderr:
+        # Same as passing sys.stderr, except python2.4 doesn't fail on it.
+        suberr = None
+      elif stderr is None:
+        # Merge with stdout if stderr isn't specified.
+        suberr = subprocess.STDOUT
+      else:
+        # Open pipe for anything else so Popen works on python2.4.
+        suberr = subprocess.PIPE
+      p = subprocess.Popen(command,
+                           shell=(sys.platform == 'win32'),
+                           stdout=subout,
+                           stderr=suberr)
+      p.wait()
+      if stdout is None:
+        self.stdout = p.stdout.read()
+      elif stdout is not sys.stdout:
+        stdout.write(p.stdout.read())
+      if stderr not in (None, sys.stderr):
+        stderr.write(p.stderr.read())
+      return p.returncode
+
+  def run(self, command, display=None, stdout=None, stderr=None):
+    """
+    Runs a single command, displaying it first.
+    """
+    if display is None:
+      display = command
+    self.display(display)
+    return self.execute(command, stdout, stderr)
+
+
+class Unbuffered:
+  def __init__(self, fp):
+    self.fp = fp
+  def write(self, arg):
+    self.fp.write(arg)
+    self.fp.flush()
+  def __getattr__(self, attr):
+    return getattr(self.fp, attr)
+
+sys.stdout = Unbuffered(sys.stdout)
+sys.stderr = Unbuffered(sys.stderr)
+
+
+def is_test_name(f):
+  return f.startswith('gyptest') and f.endswith('.py')
+
+
+def find_all_gyptest_files(directory):
+  result = []
+  for root, dirs, files in os.walk(directory):
+    if '.svn' in dirs:
+      dirs.remove('.svn')
+    result.extend([ os.path.join(root, f) for f in files if is_test_name(f) ])
+  result.sort()
+  return result
+
+
+def main(argv=None):
+  if argv is None:
+    argv = sys.argv
+
+  usage = "gyptest.py [-ahlnq] [-f formats] [test ...]"
+  parser = optparse.OptionParser(usage=usage)
+  parser.add_option("-a", "--all", action="store_true",
+            help="run all tests")
+  parser.add_option("-C", "--chdir", action="store", default=None,
+            help="chdir to the specified directory")
+  parser.add_option("-f", "--format", action="store", default='',
+            help="run tests with the specified formats")
+  parser.add_option("-G", '--gyp_option', action="append", default=[],
+            help="Add -G options to the gyp command line")
+  parser.add_option("-l", "--list", action="store_true",
+            help="list available tests and exit")
+  parser.add_option("-n", "--no-exec", action="store_true",
+            help="no execute, just print the command line")
+  parser.add_option("--passed", action="store_true",
+            help="report passed tests")
+  parser.add_option("--path", action="append", default=[],
+            help="additional $PATH directory")
+  parser.add_option("-q", "--quiet", action="store_true",
+            help="quiet, don't print test command lines")
+  opts, args = parser.parse_args(argv[1:])
+
+  if opts.chdir:
+    os.chdir(opts.chdir)
+
+  if opts.path:
+    extra_path = [os.path.abspath(p) for p in opts.path]
+    extra_path = os.pathsep.join(extra_path)
+    os.environ['PATH'] = extra_path + os.pathsep + os.environ['PATH']
+
+  if not args:
+    if not opts.all:
+      sys.stderr.write('Specify -a to get all tests.\n')
+      return 1
+    args = ['test']
+
+  tests = []
+  for arg in args:
+    if os.path.isdir(arg):
+      tests.extend(find_all_gyptest_files(os.path.normpath(arg)))
+    else:
+      if not is_test_name(os.path.basename(arg)):
+        print >>sys.stderr, arg, 'is not a valid gyp test name.'
+        sys.exit(1)
+      tests.append(arg)
+
+  if opts.list:
+    for test in tests:
+      print test
+    sys.exit(0)
+
+  CommandRunner.verbose = not opts.quiet
+  CommandRunner.active = not opts.no_exec
+  cr = CommandRunner()
+
+  os.environ['PYTHONPATH'] = os.path.abspath('test/lib')
+  if not opts.quiet:
+    sys.stdout.write('PYTHONPATH=%s\n' % os.environ['PYTHONPATH'])
+
+  passed = []
+  failed = []
+  no_result = []
+
+  if opts.format:
+    format_list = opts.format.split(',')
+  else:
+    # TODO:  not duplicate this mapping from pylib/gyp/__init__.py
+    format_list = {
+      'aix5':     ['make'],
+      'freebsd7': ['make'],
+      'freebsd8': ['make'],
+      'openbsd5': ['make'],
+      'cygwin':   ['msvs'],
+      'win32':    ['msvs', 'ninja'],
+      'linux2':   ['make', 'ninja'],
+      'linux3':   ['make', 'ninja'],
+      'darwin':   ['make', 'ninja', 'xcode'],
+    }[sys.platform]
+
+  for format in format_list:
+    os.environ['TESTGYP_FORMAT'] = format
+    if not opts.quiet:
+      sys.stdout.write('TESTGYP_FORMAT=%s\n' % format)
+
+    gyp_options = []
+    for option in opts.gyp_option:
+      gyp_options += ['-G', option]
+    if gyp_options and not opts.quiet:
+      sys.stdout.write('Extra Gyp options: %s\n' % gyp_options)
+
+    for test in tests:
+      status = cr.run([sys.executable, test] + gyp_options,
+                      stdout=sys.stdout,
+                      stderr=sys.stderr)
+      if status == 2:
+        no_result.append(test)
+      elif status:
+        failed.append(test)
+      else:
+        passed.append(test)
+
+  if not opts.quiet:
+    def report(description, tests):
+      if tests:
+        if len(tests) == 1:
+          sys.stdout.write("\n%s the following test:\n" % description)
+        else:
+          fmt = "\n%s the following %d tests:\n"
+          sys.stdout.write(fmt % (description, len(tests)))
+        sys.stdout.write("\t" + "\n\t".join(tests) + "\n")
+
+    if opts.passed:
+      report("Passed", passed)
+    report("Failed", failed)
+    report("No result from", no_result)
+
+  if failed:
+    return 1
+  else:
+    return 0
+
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/gyp/pylib/gyp/MSVSNew.py b/gyp/pylib/gyp/MSVSNew.py
new file mode 100644 (file)
index 0000000..845dcb0
--- /dev/null
@@ -0,0 +1,340 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""New implementation of Visual Studio project generation."""
+
+import os
+import random
+
+import gyp.common
+
+# hashlib is supplied as of Python 2.5 as the replacement interface for md5
+# and other secure hashes.  In 2.6, md5 is deprecated.  Import hashlib if
+# available, avoiding a deprecation warning under 2.6.  Import md5 otherwise,
+# preserving 2.4 compatibility.
+try:
+  import hashlib
+  _new_md5 = hashlib.md5
+except ImportError:
+  import md5
+  _new_md5 = md5.new
+
+
+# Initialize random number generator
+random.seed()
+
+# GUIDs for project types
+ENTRY_TYPE_GUIDS = {
+    'project': '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}',
+    'folder': '{2150E333-8FDC-42A3-9474-1A3956D46DE8}',
+}
+
+#------------------------------------------------------------------------------
+# Helper functions
+
+
+def MakeGuid(name, seed='msvs_new'):
+  """Returns a GUID for the specified target name.
+
+  Args:
+    name: Target name.
+    seed: Seed for MD5 hash.
+  Returns:
+    A GUID-line string calculated from the name and seed.
+
+  This generates something which looks like a GUID, but depends only on the
+  name and seed.  This means the same name/seed will always generate the same
+  GUID, so that projects and solutions which refer to each other can explicitly
+  determine the GUID to refer to explicitly.  It also means that the GUID will
+  not change when the project for a target is rebuilt.
+  """
+  # Calculate a MD5 signature for the seed and name.
+  d = _new_md5(str(seed) + str(name)).hexdigest().upper()
+  # Convert most of the signature to GUID form (discard the rest)
+  guid = ('{' + d[:8] + '-' + d[8:12] + '-' + d[12:16] + '-' + d[16:20]
+          + '-' + d[20:32] + '}')
+  return guid
+
+#------------------------------------------------------------------------------
+
+
+class MSVSSolutionEntry(object):
+  def __cmp__(self, other):
+    # Sort by name then guid (so things are in order on vs2008).
+    return cmp((self.name, self.get_guid()), (other.name, other.get_guid()))
+
+
+class MSVSFolder(MSVSSolutionEntry):
+  """Folder in a Visual Studio project or solution."""
+
+  def __init__(self, path, name = None, entries = None,
+               guid = None, items = None):
+    """Initializes the folder.
+
+    Args:
+      path: Full path to the folder.
+      name: Name of the folder.
+      entries: List of folder entries to nest inside this folder.  May contain
+          Folder or Project objects.  May be None, if the folder is empty.
+      guid: GUID to use for folder, if not None.
+      items: List of solution items to include in the folder project.  May be
+          None, if the folder does not directly contain items.
+    """
+    if name:
+      self.name = name
+    else:
+      # Use last layer.
+      self.name = os.path.basename(path)
+
+    self.path = path
+    self.guid = guid
+
+    # Copy passed lists (or set to empty lists)
+    self.entries = sorted(list(entries or []))
+    self.items = list(items or [])
+
+    self.entry_type_guid = ENTRY_TYPE_GUIDS['folder']
+
+  def get_guid(self):
+    if self.guid is None:
+      # Use consistent guids for folders (so things don't regenerate).
+      self.guid = MakeGuid(self.path, seed='msvs_folder')
+    return self.guid
+
+
+#------------------------------------------------------------------------------
+
+
+class MSVSProject(MSVSSolutionEntry):
+  """Visual Studio project."""
+
+  def __init__(self, path, name = None, dependencies = None, guid = None,
+               spec = None, build_file = None, config_platform_overrides = None,
+               fixpath_prefix = None):
+    """Initializes the project.
+
+    Args:
+      path: Absolute path to the project file.
+      name: Name of project.  If None, the name will be the same as the base
+          name of the project file.
+      dependencies: List of other Project objects this project is dependent
+          upon, if not None.
+      guid: GUID to use for project, if not None.
+      spec: Dictionary specifying how to build this project.
+      build_file: Filename of the .gyp file that the vcproj file comes from.
+      config_platform_overrides: optional dict of configuration platforms to
+          used in place of the default for this target.
+      fixpath_prefix: the path used to adjust the behavior of _fixpath
+    """
+    self.path = path
+    self.guid = guid
+    self.spec = spec
+    self.build_file = build_file
+    # Use project filename if name not specified
+    self.name = name or os.path.splitext(os.path.basename(path))[0]
+
+    # Copy passed lists (or set to empty lists)
+    self.dependencies = list(dependencies or [])
+
+    self.entry_type_guid = ENTRY_TYPE_GUIDS['project']
+
+    if config_platform_overrides:
+      self.config_platform_overrides = config_platform_overrides
+    else:
+      self.config_platform_overrides = {}
+    self.fixpath_prefix = fixpath_prefix
+    self.msbuild_toolset = None
+
+  def set_dependencies(self, dependencies):
+    self.dependencies = list(dependencies or [])
+
+  def get_guid(self):
+    if self.guid is None:
+      # Set GUID from path
+      # TODO(rspangler): This is fragile.
+      # 1. We can't just use the project filename sans path, since there could
+      #    be multiple projects with the same base name (for example,
+      #    foo/unittest.vcproj and bar/unittest.vcproj).
+      # 2. The path needs to be relative to $SOURCE_ROOT, so that the project
+      #    GUID is the same whether it's included from base/base.sln or
+      #    foo/bar/baz/baz.sln.
+      # 3. The GUID needs to be the same each time this builder is invoked, so
+      #    that we don't need to rebuild the solution when the project changes.
+      # 4. We should be able to handle pre-built project files by reading the
+      #    GUID from the files.
+      self.guid = MakeGuid(self.name)
+    return self.guid
+
+  def set_msbuild_toolset(self, msbuild_toolset):
+    self.msbuild_toolset = msbuild_toolset
+
+#------------------------------------------------------------------------------
+
+
+class MSVSSolution:
+  """Visual Studio solution."""
+
+  def __init__(self, path, version, entries=None, variants=None,
+               websiteProperties=True):
+    """Initializes the solution.
+
+    Args:
+      path: Path to solution file.
+      version: Format version to emit.
+      entries: List of entries in solution.  May contain Folder or Project
+          objects.  May be None, if the folder is empty.
+      variants: List of build variant strings.  If none, a default list will
+          be used.
+      websiteProperties: Flag to decide if the website properties section
+          is generated.
+    """
+    self.path = path
+    self.websiteProperties = websiteProperties
+    self.version = version
+
+    # Copy passed lists (or set to empty lists)
+    self.entries = list(entries or [])
+
+    if variants:
+      # Copy passed list
+      self.variants = variants[:]
+    else:
+      # Use default
+      self.variants = ['Debug|Win32', 'Release|Win32']
+    # TODO(rspangler): Need to be able to handle a mapping of solution config
+    # to project config.  Should we be able to handle variants being a dict,
+    # or add a separate variant_map variable?  If it's a dict, we can't
+    # guarantee the order of variants since dict keys aren't ordered.
+
+
+    # TODO(rspangler): Automatically write to disk for now; should delay until
+    # node-evaluation time.
+    self.Write()
+
+
+  def Write(self, writer=gyp.common.WriteOnDiff):
+    """Writes the solution file to disk.
+
+    Raises:
+      IndexError: An entry appears multiple times.
+    """
+    # Walk the entry tree and collect all the folders and projects.
+    all_entries = set()
+    entries_to_check = self.entries[:]
+    while entries_to_check:
+      e = entries_to_check.pop(0)
+
+      # If this entry has been visited, nothing to do.
+      if e in all_entries:
+        continue
+
+      all_entries.add(e)
+
+      # If this is a folder, check its entries too.
+      if isinstance(e, MSVSFolder):
+        entries_to_check += e.entries
+
+    all_entries = sorted(all_entries)
+
+    # Open file and print header
+    f = writer(self.path)
+    f.write('Microsoft Visual Studio Solution File, '
+            'Format Version %s\r\n' % self.version.SolutionVersion())
+    f.write('# %s\r\n' % self.version.Description())
+
+    # Project entries
+    sln_root = os.path.split(self.path)[0]
+    for e in all_entries:
+      relative_path = gyp.common.RelativePath(e.path, sln_root)
+      # msbuild does not accept an empty folder_name.
+      # use '.' in case relative_path is empty.
+      folder_name = relative_path.replace('/', '\\') or '.'
+      f.write('Project("%s") = "%s", "%s", "%s"\r\n' % (
+          e.entry_type_guid,          # Entry type GUID
+          e.name,                     # Folder name
+          folder_name,                # Folder name (again)
+          e.get_guid(),               # Entry GUID
+      ))
+
+      # TODO(rspangler): Need a way to configure this stuff
+      if self.websiteProperties:
+        f.write('\tProjectSection(WebsiteProperties) = preProject\r\n'
+                '\t\tDebug.AspNetCompiler.Debug = "True"\r\n'
+                '\t\tRelease.AspNetCompiler.Debug = "False"\r\n'
+                '\tEndProjectSection\r\n')
+
+      if isinstance(e, MSVSFolder):
+        if e.items:
+          f.write('\tProjectSection(SolutionItems) = preProject\r\n')
+          for i in e.items:
+            f.write('\t\t%s = %s\r\n' % (i, i))
+          f.write('\tEndProjectSection\r\n')
+
+      if isinstance(e, MSVSProject):
+        if e.dependencies:
+          f.write('\tProjectSection(ProjectDependencies) = postProject\r\n')
+          for d in e.dependencies:
+            f.write('\t\t%s = %s\r\n' % (d.get_guid(), d.get_guid()))
+          f.write('\tEndProjectSection\r\n')
+
+      f.write('EndProject\r\n')
+
+    # Global section
+    f.write('Global\r\n')
+
+    # Configurations (variants)
+    f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n')
+    for v in self.variants:
+      f.write('\t\t%s = %s\r\n' % (v, v))
+    f.write('\tEndGlobalSection\r\n')
+
+    # Sort config guids for easier diffing of solution changes.
+    config_guids = []
+    config_guids_overrides = {}
+    for e in all_entries:
+      if isinstance(e, MSVSProject):
+        config_guids.append(e.get_guid())
+        config_guids_overrides[e.get_guid()] = e.config_platform_overrides
+    config_guids.sort()
+
+    f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n')
+    for g in config_guids:
+      for v in self.variants:
+        nv = config_guids_overrides[g].get(v, v)
+        # Pick which project configuration to build for this solution
+        # configuration.
+        f.write('\t\t%s.%s.ActiveCfg = %s\r\n' % (
+            g,              # Project GUID
+            v,              # Solution build configuration
+            nv,             # Project build config for that solution config
+        ))
+
+        # Enable project in this solution configuration.
+        f.write('\t\t%s.%s.Build.0 = %s\r\n' % (
+            g,              # Project GUID
+            v,              # Solution build configuration
+            nv,             # Project build config for that solution config
+        ))
+    f.write('\tEndGlobalSection\r\n')
+
+    # TODO(rspangler): Should be able to configure this stuff too (though I've
+    # never seen this be any different)
+    f.write('\tGlobalSection(SolutionProperties) = preSolution\r\n')
+    f.write('\t\tHideSolutionNode = FALSE\r\n')
+    f.write('\tEndGlobalSection\r\n')
+
+    # Folder mappings
+    # Omit this section if there are no folders
+    if any([e.entries for e in all_entries if isinstance(e, MSVSFolder)]):
+      f.write('\tGlobalSection(NestedProjects) = preSolution\r\n')
+      for e in all_entries:
+        if not isinstance(e, MSVSFolder):
+          continue        # Does not apply to projects, only folders
+        for subentry in e.entries:
+          f.write('\t\t%s = %s\r\n' % (subentry.get_guid(), e.get_guid()))
+      f.write('\tEndGlobalSection\r\n')
+
+    f.write('EndGlobal\r\n')
+
+    f.close()
diff --git a/gyp/pylib/gyp/MSVSProject.py b/gyp/pylib/gyp/MSVSProject.py
new file mode 100644 (file)
index 0000000..db1ceed
--- /dev/null
@@ -0,0 +1,208 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Visual Studio project reader/writer."""
+
+import gyp.common
+import gyp.easy_xml as easy_xml
+
+#------------------------------------------------------------------------------
+
+
+class Tool(object):
+  """Visual Studio tool."""
+
+  def __init__(self, name, attrs=None):
+    """Initializes the tool.
+
+    Args:
+      name: Tool name.
+      attrs: Dict of tool attributes; may be None.
+    """
+    self._attrs = attrs or {}
+    self._attrs['Name'] = name
+
+  def _GetSpecification(self):
+    """Creates an element for the tool.
+
+    Returns:
+      A new xml.dom.Element for the tool.
+    """
+    return ['Tool', self._attrs]
+
+class Filter(object):
+  """Visual Studio filter - that is, a virtual folder."""
+
+  def __init__(self, name, contents=None):
+    """Initializes the folder.
+
+    Args:
+      name: Filter (folder) name.
+      contents: List of filenames and/or Filter objects contained.
+    """
+    self.name = name
+    self.contents = list(contents or [])
+
+
+#------------------------------------------------------------------------------
+
+
+class Writer(object):
+  """Visual Studio XML project writer."""
+
+  def __init__(self, project_path, version, name, guid=None, platforms=None):
+    """Initializes the project.
+
+    Args:
+      project_path: Path to the project file.
+      version: Format version to emit.
+      name: Name of the project.
+      guid: GUID to use for project, if not None.
+      platforms: Array of string, the supported platforms.  If null, ['Win32']
+    """
+    self.project_path = project_path
+    self.version = version
+    self.name = name
+    self.guid = guid
+
+    # Default to Win32 for platforms.
+    if not platforms:
+      platforms = ['Win32']
+
+    # Initialize the specifications of the various sections.
+    self.platform_section = ['Platforms']
+    for platform in platforms:
+      self.platform_section.append(['Platform', {'Name': platform}])
+    self.tool_files_section = ['ToolFiles']
+    self.configurations_section = ['Configurations']
+    self.files_section = ['Files']
+
+    # Keep a dict keyed on filename to speed up access.
+    self.files_dict = dict()
+
+  def AddToolFile(self, path):
+    """Adds a tool file to the project.
+
+    Args:
+      path: Relative path from project to tool file.
+    """
+    self.tool_files_section.append(['ToolFile', {'RelativePath': path}])
+
+  def _GetSpecForConfiguration(self, config_type, config_name, attrs, tools):
+    """Returns the specification for a configuration.
+
+    Args:
+      config_type: Type of configuration node.
+      config_name: Configuration name.
+      attrs: Dict of configuration attributes; may be None.
+      tools: List of tools (strings or Tool objects); may be None.
+    Returns:
+    """
+    # Handle defaults
+    if not attrs:
+      attrs = {}
+    if not tools:
+      tools = []
+
+    # Add configuration node and its attributes
+    node_attrs = attrs.copy()
+    node_attrs['Name'] = config_name
+    specification = [config_type, node_attrs]
+
+    # Add tool nodes and their attributes
+    if tools:
+      for t in tools:
+        if isinstance(t, Tool):
+          specification.append(t._GetSpecification())
+        else:
+          specification.append(Tool(t)._GetSpecification())
+    return specification
+
+
+  def AddConfig(self, name, attrs=None, tools=None):
+    """Adds a configuration to the project.
+
+    Args:
+      name: Configuration name.
+      attrs: Dict of configuration attributes; may be None.
+      tools: List of tools (strings or Tool objects); may be None.
+    """
+    spec = self._GetSpecForConfiguration('Configuration', name, attrs, tools)
+    self.configurations_section.append(spec)
+
+  def _AddFilesToNode(self, parent, files):
+    """Adds files and/or filters to the parent node.
+
+    Args:
+      parent: Destination node
+      files: A list of Filter objects and/or relative paths to files.
+
+    Will call itself recursively, if the files list contains Filter objects.
+    """
+    for f in files:
+      if isinstance(f, Filter):
+        node = ['Filter', {'Name': f.name}]
+        self._AddFilesToNode(node, f.contents)
+      else:
+        node = ['File', {'RelativePath': f}]
+        self.files_dict[f] = node
+      parent.append(node)
+
+  def AddFiles(self, files):
+    """Adds files to the project.
+
+    Args:
+      files: A list of Filter objects and/or relative paths to files.
+
+    This makes a copy of the file/filter tree at the time of this call.  If you
+    later add files to a Filter object which was passed into a previous call
+    to AddFiles(), it will not be reflected in this project.
+    """
+    self._AddFilesToNode(self.files_section, files)
+    # TODO(rspangler) This also doesn't handle adding files to an existing
+    # filter.  That is, it doesn't merge the trees.
+
+  def AddFileConfig(self, path, config, attrs=None, tools=None):
+    """Adds a configuration to a file.
+
+    Args:
+      path: Relative path to the file.
+      config: Name of configuration to add.
+      attrs: Dict of configuration attributes; may be None.
+      tools: List of tools (strings or Tool objects); may be None.
+
+    Raises:
+      ValueError: Relative path does not match any file added via AddFiles().
+    """
+    # Find the file node with the right relative path
+    parent = self.files_dict.get(path)
+    if not parent:
+      raise ValueError('AddFileConfig: file "%s" not in project.' % path)
+
+    # Add the config to the file node
+    spec = self._GetSpecForConfiguration('FileConfiguration', config, attrs,
+                                         tools)
+    parent.append(spec)
+
+  def WriteIfChanged(self):
+    """Writes the project file."""
+    # First create XML content definition
+    content = [
+        'VisualStudioProject',
+        {'ProjectType': 'Visual C++',
+         'Version': self.version.ProjectVersion(),
+         'Name': self.name,
+         'ProjectGUID': self.guid,
+         'RootNamespace': self.name,
+         'Keyword': 'Win32Proj'
+        },
+        self.platform_section,
+        self.tool_files_section,
+        self.configurations_section,
+        ['References'],  # empty section
+        self.files_section,
+        ['Globals']  # empty section
+    ]
+    easy_xml.WriteXmlIfChanged(content, self.project_path,
+                               encoding="Windows-1252")
diff --git a/gyp/pylib/gyp/MSVSSettings.py b/gyp/pylib/gyp/MSVSSettings.py
new file mode 100644 (file)
index 0000000..b4e0a78
--- /dev/null
@@ -0,0 +1,1078 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Code to validate and convert settings of the Microsoft build tools.
+
+This file contains code to validate and convert settings of the Microsoft
+build tools.  The function ConvertToMSBuildSettings(), ValidateMSVSSettings(),
+and ValidateMSBuildSettings() are the entry points.
+
+This file was created by comparing the projects created by Visual Studio 2008
+and Visual Studio 2010 for all available settings through the user interface.
+The MSBuild schemas were also considered.  They are typically found in the
+MSBuild install directory, e.g. c:\Program Files (x86)\MSBuild
+"""
+
+import sys
+import re
+
+# Dictionaries of settings validators. The key is the tool name, the value is
+# a dictionary mapping setting names to validation functions.
+_msvs_validators = {}
+_msbuild_validators = {}
+
+
+# A dictionary of settings converters. The key is the tool name, the value is
+# a dictionary mapping setting names to conversion functions.
+_msvs_to_msbuild_converters = {}
+
+
+# Tool name mapping from MSVS to MSBuild.
+_msbuild_name_of_tool = {}
+
+
+class _Tool(object):
+  """Represents a tool used by MSVS or MSBuild.
+
+  Attributes:
+      msvs_name: The name of the tool in MSVS.
+      msbuild_name: The name of the tool in MSBuild.
+  """
+
+  def __init__(self, msvs_name, msbuild_name):
+    self.msvs_name = msvs_name
+    self.msbuild_name = msbuild_name
+
+
+def _AddTool(tool):
+  """Adds a tool to the four dictionaries used to process settings.
+
+  This only defines the tool.  Each setting also needs to be added.
+
+  Args:
+    tool: The _Tool object to be added.
+  """
+  _msvs_validators[tool.msvs_name] = {}
+  _msbuild_validators[tool.msbuild_name] = {}
+  _msvs_to_msbuild_converters[tool.msvs_name] = {}
+  _msbuild_name_of_tool[tool.msvs_name] = tool.msbuild_name
+
+
+def _GetMSBuildToolSettings(msbuild_settings, tool):
+  """Returns an MSBuild tool dictionary.  Creates it if needed."""
+  return msbuild_settings.setdefault(tool.msbuild_name, {})
+
+
+class _Type(object):
+  """Type of settings (Base class)."""
+
+  def ValidateMSVS(self, value):
+    """Verifies that the value is legal for MSVS.
+
+    Args:
+      value: the value to check for this type.
+
+    Raises:
+      ValueError if value is not valid for MSVS.
+    """
+
+  def ValidateMSBuild(self, value):
+    """Verifies that the value is legal for MSBuild.
+
+    Args:
+      value: the value to check for this type.
+
+    Raises:
+      ValueError if value is not valid for MSBuild.
+    """
+
+  def ConvertToMSBuild(self, value):
+    """Returns the MSBuild equivalent of the MSVS value given.
+
+    Args:
+      value: the MSVS value to convert.
+
+    Returns:
+      the MSBuild equivalent.
+
+    Raises:
+      ValueError if value is not valid.
+    """
+    return value
+
+
+class _String(_Type):
+  """A setting that's just a string."""
+
+  def ValidateMSVS(self, value):
+    if not isinstance(value, basestring):
+      raise ValueError('expected string; got %r' % value)
+
+  def ValidateMSBuild(self, value):
+    if not isinstance(value, basestring):
+      raise ValueError('expected string; got %r' % value)
+
+  def ConvertToMSBuild(self, value):
+    # Convert the macros
+    return ConvertVCMacrosToMSBuild(value)
+
+
+class _StringList(_Type):
+  """A settings that's a list of strings."""
+
+  def ValidateMSVS(self, value):
+    if not isinstance(value, basestring) and not isinstance(value, list):
+      raise ValueError('expected string list; got %r' % value)
+
+  def ValidateMSBuild(self, value):
+    if not isinstance(value, basestring) and not isinstance(value, list):
+      raise ValueError('expected string list; got %r' % value)
+
+  def ConvertToMSBuild(self, value):
+    # Convert the macros
+    if isinstance(value, list):
+      return [ConvertVCMacrosToMSBuild(i) for i in value]
+    else:
+      return ConvertVCMacrosToMSBuild(value)
+
+
+class _Boolean(_Type):
+  """Boolean settings, can have the values 'false' or 'true'."""
+
+  def _Validate(self, value):
+    if value != 'true' and value != 'false':
+      raise ValueError('expected bool; got %r' % value)
+
+  def ValidateMSVS(self, value):
+    self._Validate(value)
+
+  def ValidateMSBuild(self, value):
+    self._Validate(value)
+
+  def ConvertToMSBuild(self, value):
+    self._Validate(value)
+    return value
+
+
+class _Integer(_Type):
+  """Integer settings."""
+
+  def __init__(self, msbuild_base=10):
+    _Type.__init__(self)
+    self._msbuild_base = msbuild_base
+
+  def ValidateMSVS(self, value):
+    # Try to convert, this will raise ValueError if invalid.
+    self.ConvertToMSBuild(value)
+
+  def ValidateMSBuild(self, value):
+    # Try to convert, this will raise ValueError if invalid.
+    int(value, self._msbuild_base)
+
+  def ConvertToMSBuild(self, value):
+    msbuild_format = (self._msbuild_base == 10) and '%d' or '0x%04x'
+    return msbuild_format % int(value)
+
+
+class _Enumeration(_Type):
+  """Type of settings that is an enumeration.
+
+  In MSVS, the values are indexes like '0', '1', and '2'.
+  MSBuild uses text labels that are more representative, like 'Win32'.
+
+  Constructor args:
+    label_list: an array of MSBuild labels that correspond to the MSVS index.
+        In the rare cases where MSVS has skipped an index value, None is
+        used in the array to indicate the unused spot.
+    new: an array of labels that are new to MSBuild.
+  """
+
+  def __init__(self, label_list, new=None):
+    _Type.__init__(self)
+    self._label_list = label_list
+    self._msbuild_values = set(value for value in label_list
+                               if value is not None)
+    if new is not None:
+      self._msbuild_values.update(new)
+
+  def ValidateMSVS(self, value):
+    # Try to convert.  It will raise an exception if not valid.
+    self.ConvertToMSBuild(value)
+
+  def ValidateMSBuild(self, value):
+    if value not in self._msbuild_values:
+      raise ValueError('unrecognized enumerated value %s' % value)
+
+  def ConvertToMSBuild(self, value):
+    index = int(value)
+    if index < 0 or index >= len(self._label_list):
+      raise ValueError('index value (%d) not in expected range [0, %d)' %
+                       (index, len(self._label_list)))
+    label = self._label_list[index]
+    if label is None:
+      raise ValueError('converted value for %s not specified.' % value)
+    return label
+
+
+# Instantiate the various generic types.
+_boolean = _Boolean()
+_integer = _Integer()
+# For now, we don't do any special validation on these types:
+_string = _String()
+_file_name = _String()
+_folder_name = _String()
+_file_list = _StringList()
+_folder_list = _StringList()
+_string_list = _StringList()
+# Some boolean settings went from numerical values to boolean.  The
+# mapping is 0: default, 1: false, 2: true.
+_newly_boolean = _Enumeration(['', 'false', 'true'])
+
+
+def _Same(tool, name, setting_type):
+  """Defines a setting that has the same name in MSVS and MSBuild.
+
+  Args:
+    tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+    name: the name of the setting.
+    setting_type: the type of this setting.
+  """
+  _Renamed(tool, name, name, setting_type)
+
+
+def _Renamed(tool, msvs_name, msbuild_name, setting_type):
+  """Defines a setting for which the name has changed.
+
+  Args:
+    tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+    msvs_name: the name of the MSVS setting.
+    msbuild_name: the name of the MSBuild setting.
+    setting_type: the type of this setting.
+  """
+
+  def _Translate(value, msbuild_settings):
+    msbuild_tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool)
+    msbuild_tool_settings[msbuild_name] = setting_type.ConvertToMSBuild(value)
+
+  _msvs_validators[tool.msvs_name][msvs_name] = setting_type.ValidateMSVS
+  _msbuild_validators[tool.msbuild_name][msbuild_name] = (
+      setting_type.ValidateMSBuild)
+  _msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate
+
+
+def _Moved(tool, settings_name, msbuild_tool_name, setting_type):
+  _MovedAndRenamed(tool, settings_name, msbuild_tool_name, settings_name,
+                   setting_type)
+
+
+def _MovedAndRenamed(tool, msvs_settings_name, msbuild_tool_name,
+                     msbuild_settings_name, setting_type):
+  """Defines a setting that may have moved to a new section.
+
+  Args:
+    tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+    msvs_settings_name: the MSVS name of the setting.
+    msbuild_tool_name: the name of the MSBuild tool to place the setting under.
+    msbuild_settings_name: the MSBuild name of the setting.
+    setting_type: the type of this setting.
+  """
+
+  def _Translate(value, msbuild_settings):
+    tool_settings = msbuild_settings.setdefault(msbuild_tool_name, {})
+    tool_settings[msbuild_settings_name] = setting_type.ConvertToMSBuild(value)
+
+  _msvs_validators[tool.msvs_name][msvs_settings_name] = (
+      setting_type.ValidateMSVS)
+  validator = setting_type.ValidateMSBuild
+  _msbuild_validators[msbuild_tool_name][msbuild_settings_name] = validator
+  _msvs_to_msbuild_converters[tool.msvs_name][msvs_settings_name] = _Translate
+
+
+def _MSVSOnly(tool, name, setting_type):
+  """Defines a setting that is only found in MSVS.
+
+  Args:
+    tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+    name: the name of the setting.
+    setting_type: the type of this setting.
+  """
+
+  def _Translate(unused_value, unused_msbuild_settings):
+    # Since this is for MSVS only settings, no translation will happen.
+    pass
+
+  _msvs_validators[tool.msvs_name][name] = setting_type.ValidateMSVS
+  _msvs_to_msbuild_converters[tool.msvs_name][name] = _Translate
+
+
+def _MSBuildOnly(tool, name, setting_type):
+  """Defines a setting that is only found in MSBuild.
+
+  Args:
+    tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+    name: the name of the setting.
+    setting_type: the type of this setting.
+  """
+  _msbuild_validators[tool.msbuild_name][name] = setting_type.ValidateMSBuild
+
+
+def _ConvertedToAdditionalOption(tool, msvs_name, flag):
+  """Defines a setting that's handled via a command line option in MSBuild.
+
+  Args:
+    tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+    msvs_name: the name of the MSVS setting that if 'true' becomes a flag
+    flag: the flag to insert at the end of the AdditionalOptions
+  """
+
+  def _Translate(value, msbuild_settings):
+    if value == 'true':
+      tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool)
+      if 'AdditionalOptions' in tool_settings:
+        new_flags = '%s %s' % (tool_settings['AdditionalOptions'], flag)
+      else:
+        new_flags = flag
+      tool_settings['AdditionalOptions'] = new_flags
+  _msvs_validators[tool.msvs_name][msvs_name] = _boolean.ValidateMSVS
+  _msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate
+
+
+def _CustomGeneratePreprocessedFile(tool, msvs_name):
+  def _Translate(value, msbuild_settings):
+    tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool)
+    if value == '0':
+      tool_settings['PreprocessToFile'] = 'false'
+      tool_settings['PreprocessSuppressLineNumbers'] = 'false'
+    elif value == '1':  # /P
+      tool_settings['PreprocessToFile'] = 'true'
+      tool_settings['PreprocessSuppressLineNumbers'] = 'false'
+    elif value == '2':  # /EP /P
+      tool_settings['PreprocessToFile'] = 'true'
+      tool_settings['PreprocessSuppressLineNumbers'] = 'true'
+    else:
+      raise ValueError('value must be one of [0, 1, 2]; got %s' % value)
+  # Create a bogus validator that looks for '0', '1', or '2'
+  msvs_validator = _Enumeration(['a', 'b', 'c']).ValidateMSVS
+  _msvs_validators[tool.msvs_name][msvs_name] = msvs_validator
+  msbuild_validator = _boolean.ValidateMSBuild
+  msbuild_tool_validators = _msbuild_validators[tool.msbuild_name]
+  msbuild_tool_validators['PreprocessToFile'] = msbuild_validator
+  msbuild_tool_validators['PreprocessSuppressLineNumbers'] = msbuild_validator
+  _msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate
+
+
+fix_vc_macro_slashes_regex_list = ('IntDir', 'OutDir')
+fix_vc_macro_slashes_regex = re.compile(
+  r'(\$\((?:%s)\))(?:[\\/]+)' % "|".join(fix_vc_macro_slashes_regex_list)
+)
+
+# Regular expression to detect keys that were generated by exclusion lists
+_EXCLUDED_SUFFIX_RE = re.compile('^(.*)_excluded$')
+
+
+def _ValidateExclusionSetting(setting, settings, error_msg, stderr=sys.stderr):
+  """Verify that 'setting' is valid if it is generated from an exclusion list.
+
+  If the setting appears to be generated from an exclusion list, the root name
+  is checked.
+
+  Args:
+      setting:   A string that is the setting name to validate
+      settings:  A dictionary where the keys are valid settings
+      error_msg: The message to emit in the event of error
+      stderr:    The stream receiving the error messages.
+  """
+  # This may be unrecognized because it's an exclusion list. If the
+  # setting name has the _excluded suffix, then check the root name.
+  unrecognized = True
+  m = re.match(_EXCLUDED_SUFFIX_RE, setting)
+  if m:
+    root_setting = m.group(1)
+    unrecognized = root_setting not in settings
+
+  if unrecognized:
+    # We don't know this setting. Give a warning.
+    print >> stderr, error_msg
+
+
+def FixVCMacroSlashes(s):
+  """Replace macros which have excessive following slashes.
+
+  These macros are known to have a built-in trailing slash. Furthermore, many
+  scripts hiccup on processing paths with extra slashes in the middle.
+
+  This list is probably not exhaustive.  Add as needed.
+  """
+  if '$' in s:
+    s = fix_vc_macro_slashes_regex.sub(r'\1', s)
+  return s
+
+
+def ConvertVCMacrosToMSBuild(s):
+  """Convert the the MSVS macros found in the string to the MSBuild equivalent.
+
+  This list is probably not exhaustive.  Add as needed.
+  """
+  if '$' in s:
+    replace_map = {
+        '$(ConfigurationName)': '$(Configuration)',
+        '$(InputDir)': '%(RelativeDir)',
+        '$(InputExt)': '%(Extension)',
+        '$(InputFileName)': '%(Filename)%(Extension)',
+        '$(InputName)': '%(Filename)',
+        '$(InputPath)': '%(Identity)',
+        '$(ParentName)': '$(ProjectFileName)',
+        '$(PlatformName)': '$(Platform)',
+        '$(SafeInputName)': '%(Filename)',
+    }
+    for old, new in replace_map.iteritems():
+      s = s.replace(old, new)
+    s = FixVCMacroSlashes(s)
+  return s
+
+
+def ConvertToMSBuildSettings(msvs_settings, stderr=sys.stderr):
+  """Converts MSVS settings (VS2008 and earlier) to MSBuild settings (VS2010+).
+
+  Args:
+      msvs_settings: A dictionary.  The key is the tool name.  The values are
+          themselves dictionaries of settings and their values.
+      stderr: The stream receiving the error messages.
+
+  Returns:
+      A dictionary of MSBuild settings.  The key is either the MSBuild tool name
+      or the empty string (for the global settings).  The values are themselves
+      dictionaries of settings and their values.
+  """
+  msbuild_settings = {}
+  for msvs_tool_name, msvs_tool_settings in msvs_settings.iteritems():
+    if msvs_tool_name in _msvs_to_msbuild_converters:
+      msvs_tool = _msvs_to_msbuild_converters[msvs_tool_name]
+      for msvs_setting, msvs_value in msvs_tool_settings.iteritems():
+        if msvs_setting in msvs_tool:
+          # Invoke the translation function.
+          try:
+            msvs_tool[msvs_setting](msvs_value, msbuild_settings)
+          except ValueError, e:
+            print >> stderr, ('Warning: while converting %s/%s to MSBuild, '
+                              '%s' % (msvs_tool_name, msvs_setting, e))
+        else:
+          _ValidateExclusionSetting(msvs_setting,
+                                    msvs_tool,
+                                    ('Warning: unrecognized setting %s/%s '
+                                     'while converting to MSBuild.' %
+                                     (msvs_tool_name, msvs_setting)),
+                                    stderr)
+    else:
+      print >> stderr, ('Warning: unrecognized tool %s while converting to '
+                        'MSBuild.' % msvs_tool_name)
+  return msbuild_settings
+
+
+def ValidateMSVSSettings(settings, stderr=sys.stderr):
+  """Validates that the names of the settings are valid for MSVS.
+
+  Args:
+      settings: A dictionary.  The key is the tool name.  The values are
+          themselves dictionaries of settings and their values.
+      stderr: The stream receiving the error messages.
+  """
+  _ValidateSettings(_msvs_validators, settings, stderr)
+
+
+def ValidateMSBuildSettings(settings, stderr=sys.stderr):
+  """Validates that the names of the settings are valid for MSBuild.
+
+  Args:
+      settings: A dictionary.  The key is the tool name.  The values are
+          themselves dictionaries of settings and their values.
+      stderr: The stream receiving the error messages.
+  """
+  _ValidateSettings(_msbuild_validators, settings, stderr)
+
+
+def _ValidateSettings(validators, settings, stderr):
+  """Validates that the settings are valid for MSBuild or MSVS.
+
+  We currently only validate the names of the settings, not their values.
+
+  Args:
+      validators: A dictionary of tools and their validators.
+      settings: A dictionary.  The key is the tool name.  The values are
+          themselves dictionaries of settings and their values.
+      stderr: The stream receiving the error messages.
+  """
+  for tool_name in settings:
+    if tool_name in validators:
+      tool_validators = validators[tool_name]
+      for setting, value in settings[tool_name].iteritems():
+        if setting in tool_validators:
+          try:
+            tool_validators[setting](value)
+          except ValueError, e:
+            print >> stderr, ('Warning: for %s/%s, %s' %
+                              (tool_name, setting, e))
+        else:
+          _ValidateExclusionSetting(setting,
+                                    tool_validators,
+                                    ('Warning: unrecognized setting %s/%s' %
+                                     (tool_name, setting)),
+                                    stderr)
+
+    else:
+      print >> stderr, ('Warning: unrecognized tool %s' % tool_name)
+
+
+# MSVS and MBuild names of the tools.
+_compile = _Tool('VCCLCompilerTool', 'ClCompile')
+_link = _Tool('VCLinkerTool', 'Link')
+_midl = _Tool('VCMIDLTool', 'Midl')
+_rc = _Tool('VCResourceCompilerTool', 'ResourceCompile')
+_lib = _Tool('VCLibrarianTool', 'Lib')
+_manifest = _Tool('VCManifestTool', 'Manifest')
+
+
+_AddTool(_compile)
+_AddTool(_link)
+_AddTool(_midl)
+_AddTool(_rc)
+_AddTool(_lib)
+_AddTool(_manifest)
+# Add sections only found in the MSBuild settings.
+_msbuild_validators[''] = {}
+_msbuild_validators['ProjectReference'] = {}
+_msbuild_validators['ManifestResourceCompile'] = {}
+
+# Descriptions of the compiler options, i.e. VCCLCompilerTool in MSVS and
+# ClCompile in MSBuild.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\cl.xml" for
+# the schema of the MSBuild ClCompile settings.
+
+# Options that have the same name in MSVS and MSBuild
+_Same(_compile, 'AdditionalIncludeDirectories', _folder_list)  # /I
+_Same(_compile, 'AdditionalOptions', _string_list)
+_Same(_compile, 'AdditionalUsingDirectories', _folder_list)  # /AI
+_Same(_compile, 'AssemblerListingLocation', _file_name)  # /Fa
+_Same(_compile, 'BrowseInformationFile', _file_name)
+_Same(_compile, 'BufferSecurityCheck', _boolean)  # /GS
+_Same(_compile, 'DisableLanguageExtensions', _boolean)  # /Za
+_Same(_compile, 'DisableSpecificWarnings', _string_list)  # /wd
+_Same(_compile, 'EnableFiberSafeOptimizations', _boolean)  # /GT
+_Same(_compile, 'EnablePREfast', _boolean)  # /analyze Visible='false'
+_Same(_compile, 'ExpandAttributedSource', _boolean)  # /Fx
+_Same(_compile, 'FloatingPointExceptions', _boolean)  # /fp:except
+_Same(_compile, 'ForceConformanceInForLoopScope', _boolean)  # /Zc:forScope
+_Same(_compile, 'ForcedIncludeFiles', _file_list)  # /FI
+_Same(_compile, 'ForcedUsingFiles', _file_list)  # /FU
+_Same(_compile, 'GenerateXMLDocumentationFiles', _boolean)  # /doc
+_Same(_compile, 'IgnoreStandardIncludePath', _boolean)  # /X
+_Same(_compile, 'MinimalRebuild', _boolean)  # /Gm
+_Same(_compile, 'OmitDefaultLibName', _boolean)  # /Zl
+_Same(_compile, 'OmitFramePointers', _boolean)  # /Oy
+_Same(_compile, 'PreprocessorDefinitions', _string_list)  # /D
+_Same(_compile, 'ProgramDataBaseFileName', _file_name)  # /Fd
+_Same(_compile, 'RuntimeTypeInfo', _boolean)  # /GR
+_Same(_compile, 'ShowIncludes', _boolean)  # /showIncludes
+_Same(_compile, 'SmallerTypeCheck', _boolean)  # /RTCc
+_Same(_compile, 'StringPooling', _boolean)  # /GF
+_Same(_compile, 'SuppressStartupBanner', _boolean)  # /nologo
+_Same(_compile, 'TreatWChar_tAsBuiltInType', _boolean)  # /Zc:wchar_t
+_Same(_compile, 'UndefineAllPreprocessorDefinitions', _boolean)  # /u
+_Same(_compile, 'UndefinePreprocessorDefinitions', _string_list)  # /U
+_Same(_compile, 'UseFullPaths', _boolean)  # /FC
+_Same(_compile, 'WholeProgramOptimization', _boolean)  # /GL
+_Same(_compile, 'XMLDocumentationFileName', _file_name)
+
+_Same(_compile, 'AssemblerOutput',
+      _Enumeration(['NoListing',
+                    'AssemblyCode',  # /FA
+                    'All',  # /FAcs
+                    'AssemblyAndMachineCode',  # /FAc
+                    'AssemblyAndSourceCode']))  # /FAs
+_Same(_compile, 'BasicRuntimeChecks',
+      _Enumeration(['Default',
+                    'StackFrameRuntimeCheck',  # /RTCs
+                    'UninitializedLocalUsageCheck',  # /RTCu
+                    'EnableFastChecks']))  # /RTC1
+_Same(_compile, 'BrowseInformation',
+      _Enumeration(['false',
+                    'true',  # /FR
+                    'true']))  # /Fr
+_Same(_compile, 'CallingConvention',
+      _Enumeration(['Cdecl',  # /Gd
+                    'FastCall',  # /Gr
+                    'StdCall']))  # /Gz
+_Same(_compile, 'CompileAs',
+      _Enumeration(['Default',
+                    'CompileAsC',  # /TC
+                    'CompileAsCpp']))  # /TP
+_Same(_compile, 'DebugInformationFormat',
+      _Enumeration(['',  # Disabled
+                    'OldStyle',  # /Z7
+                    None,
+                    'ProgramDatabase',  # /Zi
+                    'EditAndContinue']))  # /ZI
+_Same(_compile, 'EnableEnhancedInstructionSet',
+      _Enumeration(['NotSet',
+                    'StreamingSIMDExtensions',  # /arch:SSE
+                    'StreamingSIMDExtensions2',  # /arch:SSE2
+                    'AdvancedVectorExtensions',  # /arch:AVX (vs2012+)
+                    'NoExtensions',]))  # /arch:IA32 (vs2012+)
+_Same(_compile, 'ErrorReporting',
+      _Enumeration(['None',  # /errorReport:none
+                    'Prompt',  # /errorReport:prompt
+                    'Queue'],  # /errorReport:queue
+                   new=['Send']))  # /errorReport:send"
+_Same(_compile, 'ExceptionHandling',
+      _Enumeration(['false',
+                    'Sync',  # /EHsc
+                    'Async'],  # /EHa
+                   new=['SyncCThrow']))  # /EHs
+_Same(_compile, 'FavorSizeOrSpeed',
+      _Enumeration(['Neither',
+                    'Speed',  # /Ot
+                    'Size']))  # /Os
+_Same(_compile, 'FloatingPointModel',
+      _Enumeration(['Precise',  # /fp:precise
+                    'Strict',  # /fp:strict
+                    'Fast']))  # /fp:fast
+_Same(_compile, 'InlineFunctionExpansion',
+      _Enumeration(['Default',
+                    'OnlyExplicitInline',  # /Ob1
+                    'AnySuitable'],  # /Ob2
+                   new=['Disabled']))  # /Ob0
+_Same(_compile, 'Optimization',
+      _Enumeration(['Disabled',  # /Od
+                    'MinSpace',  # /O1
+                    'MaxSpeed',  # /O2
+                    'Full']))  # /Ox
+_Same(_compile, 'RuntimeLibrary',
+      _Enumeration(['MultiThreaded',  # /MT
+                    'MultiThreadedDebug',  # /MTd
+                    'MultiThreadedDLL',  # /MD
+                    'MultiThreadedDebugDLL']))  # /MDd
+_Same(_compile, 'StructMemberAlignment',
+      _Enumeration(['Default',
+                    '1Byte',  # /Zp1
+                    '2Bytes',  # /Zp2
+                    '4Bytes',  # /Zp4
+                    '8Bytes',  # /Zp8
+                    '16Bytes']))  # /Zp16
+_Same(_compile, 'WarningLevel',
+      _Enumeration(['TurnOffAllWarnings',  # /W0
+                    'Level1',  # /W1
+                    'Level2',  # /W2
+                    'Level3',  # /W3
+                    'Level4'],  # /W4
+                   new=['EnableAllWarnings']))  # /Wall
+
+# Options found in MSVS that have been renamed in MSBuild.
+_Renamed(_compile, 'EnableFunctionLevelLinking', 'FunctionLevelLinking',
+         _boolean)  # /Gy
+_Renamed(_compile, 'EnableIntrinsicFunctions', 'IntrinsicFunctions',
+         _boolean)  # /Oi
+_Renamed(_compile, 'KeepComments', 'PreprocessKeepComments', _boolean)  # /C
+_Renamed(_compile, 'ObjectFile', 'ObjectFileName', _file_name)  # /Fo
+_Renamed(_compile, 'OpenMP', 'OpenMPSupport', _boolean)  # /openmp
+_Renamed(_compile, 'PrecompiledHeaderThrough', 'PrecompiledHeaderFile',
+         _file_name)  # Used with /Yc and /Yu
+_Renamed(_compile, 'PrecompiledHeaderFile', 'PrecompiledHeaderOutputFile',
+         _file_name)  # /Fp
+_Renamed(_compile, 'UsePrecompiledHeader', 'PrecompiledHeader',
+         _Enumeration(['NotUsing',  # VS recognized '' for this value too.
+                       'Create',   # /Yc
+                       'Use']))  # /Yu
+_Renamed(_compile, 'WarnAsError', 'TreatWarningAsError', _boolean)  # /WX
+
+_ConvertedToAdditionalOption(_compile, 'DefaultCharIsUnsigned', '/J')
+
+# MSVS options not found in MSBuild.
+_MSVSOnly(_compile, 'Detect64BitPortabilityProblems', _boolean)
+_MSVSOnly(_compile, 'UseUnicodeResponseFiles', _boolean)
+
+# MSBuild options not found in MSVS.
+_MSBuildOnly(_compile, 'BuildingInIDE', _boolean)
+_MSBuildOnly(_compile, 'CompileAsManaged',
+             _Enumeration([], new=['false',
+                                   'true',  # /clr
+                                   'Pure',  # /clr:pure
+                                   'Safe',  # /clr:safe
+                                   'OldSyntax']))  # /clr:oldSyntax
+_MSBuildOnly(_compile, 'CreateHotpatchableImage', _boolean)  # /hotpatch
+_MSBuildOnly(_compile, 'MultiProcessorCompilation', _boolean)  # /MP
+_MSBuildOnly(_compile, 'PreprocessOutputPath', _string)  # /Fi
+_MSBuildOnly(_compile, 'ProcessorNumber', _integer)  # the number of processors
+_MSBuildOnly(_compile, 'TrackerLogDirectory', _folder_name)
+_MSBuildOnly(_compile, 'TreatSpecificWarningsAsErrors', _string_list)  # /we
+_MSBuildOnly(_compile, 'UseUnicodeForAssemblerListing', _boolean)  # /FAu
+
+# Defines a setting that needs very customized processing
+_CustomGeneratePreprocessedFile(_compile, 'GeneratePreprocessedFile')
+
+
+# Directives for converting MSVS VCLinkerTool to MSBuild Link.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\link.xml" for
+# the schema of the MSBuild Link settings.
+
+# Options that have the same name in MSVS and MSBuild
+_Same(_link, 'AdditionalDependencies', _file_list)
+_Same(_link, 'AdditionalLibraryDirectories', _folder_list)  # /LIBPATH
+#  /MANIFESTDEPENDENCY:
+_Same(_link, 'AdditionalManifestDependencies', _file_list)
+_Same(_link, 'AdditionalOptions', _string_list)
+_Same(_link, 'AddModuleNamesToAssembly', _file_list)  # /ASSEMBLYMODULE
+_Same(_link, 'AllowIsolation', _boolean)  # /ALLOWISOLATION
+_Same(_link, 'AssemblyLinkResource', _file_list)  # /ASSEMBLYLINKRESOURCE
+_Same(_link, 'BaseAddress', _string)  # /BASE
+_Same(_link, 'CLRUnmanagedCodeCheck', _boolean)  # /CLRUNMANAGEDCODECHECK
+_Same(_link, 'DelayLoadDLLs', _file_list)  # /DELAYLOAD
+_Same(_link, 'DelaySign', _boolean)  # /DELAYSIGN
+_Same(_link, 'EmbedManagedResourceFile', _file_list)  # /ASSEMBLYRESOURCE
+_Same(_link, 'EnableUAC', _boolean)  # /MANIFESTUAC
+_Same(_link, 'EntryPointSymbol', _string)  # /ENTRY
+_Same(_link, 'ForceSymbolReferences', _file_list)  # /INCLUDE
+_Same(_link, 'FunctionOrder', _file_name)  # /ORDER
+_Same(_link, 'GenerateDebugInformation', _boolean)  # /DEBUG
+_Same(_link, 'GenerateMapFile', _boolean)  # /MAP
+_Same(_link, 'HeapCommitSize', _string)
+_Same(_link, 'HeapReserveSize', _string)  # /HEAP
+_Same(_link, 'IgnoreAllDefaultLibraries', _boolean)  # /NODEFAULTLIB
+_Same(_link, 'IgnoreEmbeddedIDL', _boolean)  # /IGNOREIDL
+_Same(_link, 'ImportLibrary', _file_name)  # /IMPLIB
+_Same(_link, 'KeyContainer', _file_name)  # /KEYCONTAINER
+_Same(_link, 'KeyFile', _file_name)  # /KEYFILE
+_Same(_link, 'ManifestFile', _file_name)  # /ManifestFile
+_Same(_link, 'MapExports', _boolean)  # /MAPINFO:EXPORTS
+_Same(_link, 'MapFileName', _file_name)
+_Same(_link, 'MergedIDLBaseFileName', _file_name)  # /IDLOUT
+_Same(_link, 'MergeSections', _string)  # /MERGE
+_Same(_link, 'MidlCommandFile', _file_name)  # /MIDL
+_Same(_link, 'ModuleDefinitionFile', _file_name)  # /DEF
+_Same(_link, 'OutputFile', _file_name)  # /OUT
+_Same(_link, 'PerUserRedirection', _boolean)
+_Same(_link, 'Profile', _boolean)  # /PROFILE
+_Same(_link, 'ProfileGuidedDatabase', _file_name)  # /PGD
+_Same(_link, 'ProgramDatabaseFile', _file_name)  # /PDB
+_Same(_link, 'RegisterOutput', _boolean)
+_Same(_link, 'SetChecksum', _boolean)  # /RELEASE
+_Same(_link, 'StackCommitSize', _string)
+_Same(_link, 'StackReserveSize', _string)  # /STACK
+_Same(_link, 'StripPrivateSymbols', _file_name)  # /PDBSTRIPPED
+_Same(_link, 'SupportUnloadOfDelayLoadedDLL', _boolean)  # /DELAY:UNLOAD
+_Same(_link, 'SuppressStartupBanner', _boolean)  # /NOLOGO
+_Same(_link, 'SwapRunFromCD', _boolean)  # /SWAPRUN:CD
+_Same(_link, 'TurnOffAssemblyGeneration', _boolean)  # /NOASSEMBLY
+_Same(_link, 'TypeLibraryFile', _file_name)  # /TLBOUT
+_Same(_link, 'TypeLibraryResourceID', _integer)  # /TLBID
+_Same(_link, 'UACUIAccess', _boolean)  # /uiAccess='true'
+_Same(_link, 'Version', _string)  # /VERSION
+
+_Same(_link, 'EnableCOMDATFolding', _newly_boolean)  # /OPT:ICF
+_Same(_link, 'FixedBaseAddress', _newly_boolean)  # /FIXED
+_Same(_link, 'LargeAddressAware', _newly_boolean)  # /LARGEADDRESSAWARE
+_Same(_link, 'OptimizeReferences', _newly_boolean)  # /OPT:REF
+_Same(_link, 'RandomizedBaseAddress', _newly_boolean)  # /DYNAMICBASE
+_Same(_link, 'TerminalServerAware', _newly_boolean)  # /TSAWARE
+
+_subsystem_enumeration = _Enumeration(
+    ['NotSet',
+     'Console',  # /SUBSYSTEM:CONSOLE
+     'Windows',  # /SUBSYSTEM:WINDOWS
+     'Native',  # /SUBSYSTEM:NATIVE
+     'EFI Application',  # /SUBSYSTEM:EFI_APPLICATION
+     'EFI Boot Service Driver',  # /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER
+     'EFI ROM',  # /SUBSYSTEM:EFI_ROM
+     'EFI Runtime',  # /SUBSYSTEM:EFI_RUNTIME_DRIVER
+     'WindowsCE'],  # /SUBSYSTEM:WINDOWSCE
+    new=['POSIX'])  # /SUBSYSTEM:POSIX
+
+_target_machine_enumeration = _Enumeration(
+    ['NotSet',
+     'MachineX86',  # /MACHINE:X86
+     None,
+     'MachineARM',  # /MACHINE:ARM
+     'MachineEBC',  # /MACHINE:EBC
+     'MachineIA64',  # /MACHINE:IA64
+     None,
+     'MachineMIPS',  # /MACHINE:MIPS
+     'MachineMIPS16',  # /MACHINE:MIPS16
+     'MachineMIPSFPU',  # /MACHINE:MIPSFPU
+     'MachineMIPSFPU16',  # /MACHINE:MIPSFPU16
+     None,
+     None,
+     None,
+     'MachineSH4',  # /MACHINE:SH4
+     None,
+     'MachineTHUMB',  # /MACHINE:THUMB
+     'MachineX64'])  # /MACHINE:X64
+
+_Same(_link, 'AssemblyDebug',
+      _Enumeration(['',
+                    'true',  # /ASSEMBLYDEBUG
+                    'false']))  # /ASSEMBLYDEBUG:DISABLE
+_Same(_link, 'CLRImageType',
+      _Enumeration(['Default',
+                    'ForceIJWImage',  # /CLRIMAGETYPE:IJW
+                    'ForcePureILImage',  # /Switch="CLRIMAGETYPE:PURE
+                    'ForceSafeILImage']))  # /Switch="CLRIMAGETYPE:SAFE
+_Same(_link, 'CLRThreadAttribute',
+      _Enumeration(['DefaultThreadingAttribute',  # /CLRTHREADATTRIBUTE:NONE
+                    'MTAThreadingAttribute',  # /CLRTHREADATTRIBUTE:MTA
+                    'STAThreadingAttribute']))  # /CLRTHREADATTRIBUTE:STA
+_Same(_link, 'DataExecutionPrevention',
+      _Enumeration(['',
+                    'false',  # /NXCOMPAT:NO
+                    'true']))  # /NXCOMPAT
+_Same(_link, 'Driver',
+      _Enumeration(['NotSet',
+                    'Driver',  # /Driver
+                    'UpOnly',  # /DRIVER:UPONLY
+                    'WDM']))  # /DRIVER:WDM
+_Same(_link, 'LinkTimeCodeGeneration',
+      _Enumeration(['Default',
+                    'UseLinkTimeCodeGeneration',  # /LTCG
+                    'PGInstrument',  # /LTCG:PGInstrument
+                    'PGOptimization',  # /LTCG:PGOptimize
+                    'PGUpdate']))  # /LTCG:PGUpdate
+_Same(_link, 'ShowProgress',
+      _Enumeration(['NotSet',
+                    'LinkVerbose',  # /VERBOSE
+                    'LinkVerboseLib'],  # /VERBOSE:Lib
+                   new=['LinkVerboseICF',  # /VERBOSE:ICF
+                        'LinkVerboseREF',  # /VERBOSE:REF
+                        'LinkVerboseSAFESEH',  # /VERBOSE:SAFESEH
+                        'LinkVerboseCLR']))  # /VERBOSE:CLR
+_Same(_link, 'SubSystem', _subsystem_enumeration)
+_Same(_link, 'TargetMachine', _target_machine_enumeration)
+_Same(_link, 'UACExecutionLevel',
+      _Enumeration(['AsInvoker',  # /level='asInvoker'
+                    'HighestAvailable',  # /level='highestAvailable'
+                    'RequireAdministrator']))  # /level='requireAdministrator'
+_Same(_link, 'MinimumRequiredVersion', _string)
+_Same(_link, 'TreatLinkerWarningAsErrors', _boolean)  # /WX
+
+
+# Options found in MSVS that have been renamed in MSBuild.
+_Renamed(_link, 'ErrorReporting', 'LinkErrorReporting',
+         _Enumeration(['NoErrorReport',  # /ERRORREPORT:NONE
+                       'PromptImmediately',  # /ERRORREPORT:PROMPT
+                       'QueueForNextLogin'],  # /ERRORREPORT:QUEUE
+                      new=['SendErrorReport']))  # /ERRORREPORT:SEND
+_Renamed(_link, 'IgnoreDefaultLibraryNames', 'IgnoreSpecificDefaultLibraries',
+         _file_list)  # /NODEFAULTLIB
+_Renamed(_link, 'ResourceOnlyDLL', 'NoEntryPoint', _boolean)  # /NOENTRY
+_Renamed(_link, 'SwapRunFromNet', 'SwapRunFromNET', _boolean)  # /SWAPRUN:NET
+
+_Moved(_link, 'GenerateManifest', '', _boolean)
+_Moved(_link, 'IgnoreImportLibrary', '', _boolean)
+_Moved(_link, 'LinkIncremental', '', _newly_boolean)
+_Moved(_link, 'LinkLibraryDependencies', 'ProjectReference', _boolean)
+_Moved(_link, 'UseLibraryDependencyInputs', 'ProjectReference', _boolean)
+
+# MSVS options not found in MSBuild.
+_MSVSOnly(_link, 'OptimizeForWindows98', _newly_boolean)
+_MSVSOnly(_link, 'UseUnicodeResponseFiles', _boolean)
+
+# MSBuild options not found in MSVS.
+_MSBuildOnly(_link, 'BuildingInIDE', _boolean)
+_MSBuildOnly(_link, 'ImageHasSafeExceptionHandlers', _boolean)  # /SAFESEH
+_MSBuildOnly(_link, 'LinkDLL', _boolean)  # /DLL Visible='false'
+_MSBuildOnly(_link, 'LinkStatus', _boolean)  # /LTCG:STATUS
+_MSBuildOnly(_link, 'PreventDllBinding', _boolean)  # /ALLOWBIND
+_MSBuildOnly(_link, 'SupportNobindOfDelayLoadedDLL', _boolean)  # /DELAY:NOBIND
+_MSBuildOnly(_link, 'TrackerLogDirectory', _folder_name)
+_MSBuildOnly(_link, 'MSDOSStubFileName', _file_name)  # /STUB Visible='false'
+_MSBuildOnly(_link, 'SectionAlignment', _integer)  # /ALIGN
+_MSBuildOnly(_link, 'SpecifySectionAttributes', _string)  # /SECTION
+_MSBuildOnly(_link, 'ForceFileOutput',
+             _Enumeration([], new=['Enabled',  # /FORCE
+                                   # /FORCE:MULTIPLE
+                                   'MultiplyDefinedSymbolOnly',
+                                   'UndefinedSymbolOnly']))  # /FORCE:UNRESOLVED
+_MSBuildOnly(_link, 'CreateHotPatchableImage',
+             _Enumeration([], new=['Enabled',  # /FUNCTIONPADMIN
+                                   'X86Image',  # /FUNCTIONPADMIN:5
+                                   'X64Image',  # /FUNCTIONPADMIN:6
+                                   'ItaniumImage']))  # /FUNCTIONPADMIN:16
+_MSBuildOnly(_link, 'CLRSupportLastError',
+             _Enumeration([], new=['Enabled',  # /CLRSupportLastError
+                                   'Disabled',  # /CLRSupportLastError:NO
+                                   # /CLRSupportLastError:SYSTEMDLL
+                                   'SystemDlls']))
+
+
+# Directives for converting VCResourceCompilerTool to ResourceCompile.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\rc.xml" for
+# the schema of the MSBuild ResourceCompile settings.
+
+_Same(_rc, 'AdditionalOptions', _string_list)
+_Same(_rc, 'AdditionalIncludeDirectories', _folder_list)  # /I
+_Same(_rc, 'Culture', _Integer(msbuild_base=16))
+_Same(_rc, 'IgnoreStandardIncludePath', _boolean)  # /X
+_Same(_rc, 'PreprocessorDefinitions', _string_list)  # /D
+_Same(_rc, 'ResourceOutputFileName', _string)  # /fo
+_Same(_rc, 'ShowProgress', _boolean)  # /v
+# There is no UI in VisualStudio 2008 to set the following properties.
+# However they are found in CL and other tools.  Include them here for
+# completeness, as they are very likely to have the same usage pattern.
+_Same(_rc, 'SuppressStartupBanner', _boolean)  # /nologo
+_Same(_rc, 'UndefinePreprocessorDefinitions', _string_list)  # /u
+
+# MSBuild options not found in MSVS.
+_MSBuildOnly(_rc, 'NullTerminateStrings', _boolean)  # /n
+_MSBuildOnly(_rc, 'TrackerLogDirectory', _folder_name)
+
+
+# Directives for converting VCMIDLTool to Midl.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\midl.xml" for
+# the schema of the MSBuild Midl settings.
+
+_Same(_midl, 'AdditionalIncludeDirectories', _folder_list)  # /I
+_Same(_midl, 'AdditionalOptions', _string_list)
+_Same(_midl, 'CPreprocessOptions', _string)  # /cpp_opt
+_Same(_midl, 'ErrorCheckAllocations', _boolean)  # /error allocation
+_Same(_midl, 'ErrorCheckBounds', _boolean)  # /error bounds_check
+_Same(_midl, 'ErrorCheckEnumRange', _boolean)  # /error enum
+_Same(_midl, 'ErrorCheckRefPointers', _boolean)  # /error ref
+_Same(_midl, 'ErrorCheckStubData', _boolean)  # /error stub_data
+_Same(_midl, 'GenerateStublessProxies', _boolean)  # /Oicf
+_Same(_midl, 'GenerateTypeLibrary', _boolean)
+_Same(_midl, 'HeaderFileName', _file_name)  # /h
+_Same(_midl, 'IgnoreStandardIncludePath', _boolean)  # /no_def_idir
+_Same(_midl, 'InterfaceIdentifierFileName', _file_name)  # /iid
+_Same(_midl, 'MkTypLibCompatible', _boolean)  # /mktyplib203
+_Same(_midl, 'OutputDirectory', _string)  # /out
+_Same(_midl, 'PreprocessorDefinitions', _string_list)  # /D
+_Same(_midl, 'ProxyFileName', _file_name)  # /proxy
+_Same(_midl, 'RedirectOutputAndErrors', _file_name)  # /o
+_Same(_midl, 'SuppressStartupBanner', _boolean)  # /nologo
+_Same(_midl, 'TypeLibraryName', _file_name)  # /tlb
+_Same(_midl, 'UndefinePreprocessorDefinitions', _string_list)  # /U
+_Same(_midl, 'WarnAsError', _boolean)  # /WX
+
+_Same(_midl, 'DefaultCharType',
+      _Enumeration(['Unsigned',  # /char unsigned
+                    'Signed',  # /char signed
+                    'Ascii']))  # /char ascii7
+_Same(_midl, 'TargetEnvironment',
+      _Enumeration(['NotSet',
+                    'Win32',  # /env win32
+                    'Itanium',  # /env ia64
+                    'X64']))  # /env x64
+_Same(_midl, 'EnableErrorChecks',
+      _Enumeration(['EnableCustom',
+                    'None',  # /error none
+                    'All']))  # /error all
+_Same(_midl, 'StructMemberAlignment',
+      _Enumeration(['NotSet',
+                    '1',  # Zp1
+                    '2',  # Zp2
+                    '4',  # Zp4
+                    '8']))  # Zp8
+_Same(_midl, 'WarningLevel',
+      _Enumeration(['0',  # /W0
+                    '1',  # /W1
+                    '2',  # /W2
+                    '3',  # /W3
+                    '4']))  # /W4
+
+_Renamed(_midl, 'DLLDataFileName', 'DllDataFileName', _file_name)  # /dlldata
+_Renamed(_midl, 'ValidateParameters', 'ValidateAllParameters',
+         _boolean)  # /robust
+
+# MSBuild options not found in MSVS.
+_MSBuildOnly(_midl, 'ApplicationConfigurationMode', _boolean)  # /app_config
+_MSBuildOnly(_midl, 'ClientStubFile', _file_name)  # /cstub
+_MSBuildOnly(_midl, 'GenerateClientFiles',
+             _Enumeration([], new=['Stub',  # /client stub
+                                   'None']))  # /client none
+_MSBuildOnly(_midl, 'GenerateServerFiles',
+             _Enumeration([], new=['Stub',  # /client stub
+                                   'None']))  # /client none
+_MSBuildOnly(_midl, 'LocaleID', _integer)  # /lcid DECIMAL
+_MSBuildOnly(_midl, 'ServerStubFile', _file_name)  # /sstub
+_MSBuildOnly(_midl, 'SuppressCompilerWarnings', _boolean)  # /no_warn
+_MSBuildOnly(_midl, 'TrackerLogDirectory', _folder_name)
+_MSBuildOnly(_midl, 'TypeLibFormat',
+             _Enumeration([], new=['NewFormat',  # /newtlb
+                                   'OldFormat']))  # /oldtlb
+
+
+# Directives for converting VCLibrarianTool to Lib.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\lib.xml" for
+# the schema of the MSBuild Lib settings.
+
+_Same(_lib, 'AdditionalDependencies', _file_list)
+_Same(_lib, 'AdditionalLibraryDirectories', _folder_list)  # /LIBPATH
+_Same(_lib, 'AdditionalOptions', _string_list)
+_Same(_lib, 'ExportNamedFunctions', _string_list)  # /EXPORT
+_Same(_lib, 'ForceSymbolReferences', _string)  # /INCLUDE
+_Same(_lib, 'IgnoreAllDefaultLibraries', _boolean)  # /NODEFAULTLIB
+_Same(_lib, 'IgnoreSpecificDefaultLibraries', _file_list)  # /NODEFAULTLIB
+_Same(_lib, 'ModuleDefinitionFile', _file_name)  # /DEF
+_Same(_lib, 'OutputFile', _file_name)  # /OUT
+_Same(_lib, 'SuppressStartupBanner', _boolean)  # /NOLOGO
+_Same(_lib, 'UseUnicodeResponseFiles', _boolean)
+_Same(_lib, 'LinkTimeCodeGeneration', _boolean)  # /LTCG
+_Same(_lib, 'TargetMachine', _target_machine_enumeration)
+
+# TODO(jeanluc) _link defines the same value that gets moved to
+# ProjectReference.  We may want to validate that they are consistent.
+_Moved(_lib, 'LinkLibraryDependencies', 'ProjectReference', _boolean)
+
+_MSBuildOnly(_lib, 'DisplayLibrary', _string)  # /LIST Visible='false'
+_MSBuildOnly(_lib, 'ErrorReporting',
+             _Enumeration([], new=['PromptImmediately',  # /ERRORREPORT:PROMPT
+                                   'QueueForNextLogin',  # /ERRORREPORT:QUEUE
+                                   'SendErrorReport',  # /ERRORREPORT:SEND
+                                   'NoErrorReport']))  # /ERRORREPORT:NONE
+_MSBuildOnly(_lib, 'MinimumRequiredVersion', _string)
+_MSBuildOnly(_lib, 'Name', _file_name)  # /NAME
+_MSBuildOnly(_lib, 'RemoveObjects', _file_list)  # /REMOVE
+_MSBuildOnly(_lib, 'SubSystem', _subsystem_enumeration)
+_MSBuildOnly(_lib, 'TrackerLogDirectory', _folder_name)
+_MSBuildOnly(_lib, 'TreatLibWarningAsErrors', _boolean)  # /WX
+_MSBuildOnly(_lib, 'Verbose', _boolean)
+
+
+# Directives for converting VCManifestTool to Mt.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\mt.xml" for
+# the schema of the MSBuild Lib settings.
+
+# Options that have the same name in MSVS and MSBuild
+_Same(_manifest, 'AdditionalManifestFiles', _file_list)  # /manifest
+_Same(_manifest, 'AdditionalOptions', _string_list)
+_Same(_manifest, 'AssemblyIdentity', _string)  # /identity:
+_Same(_manifest, 'ComponentFileName', _file_name)  # /dll
+_Same(_manifest, 'GenerateCatalogFiles', _boolean)  # /makecdfs
+_Same(_manifest, 'InputResourceManifests', _string)  # /inputresource
+_Same(_manifest, 'OutputManifestFile', _file_name)  # /out
+_Same(_manifest, 'RegistrarScriptFile', _file_name)  # /rgs
+_Same(_manifest, 'ReplacementsFile', _file_name)  # /replacements
+_Same(_manifest, 'SuppressStartupBanner', _boolean)  # /nologo
+_Same(_manifest, 'TypeLibraryFile', _file_name)  # /tlb:
+_Same(_manifest, 'UpdateFileHashes', _boolean)  # /hashupdate
+_Same(_manifest, 'UpdateFileHashesSearchPath', _file_name)
+_Same(_manifest, 'VerboseOutput', _boolean)  # /verbose
+
+# Options that have moved location.
+_MovedAndRenamed(_manifest, 'ManifestResourceFile',
+                 'ManifestResourceCompile',
+                 'ResourceOutputFileName',
+                 _file_name)
+_Moved(_manifest, 'EmbedManifest', '', _boolean)
+
+# MSVS options not found in MSBuild.
+_MSVSOnly(_manifest, 'DependencyInformationFile', _file_name)
+_MSVSOnly(_manifest, 'UseFAT32Workaround', _boolean)
+_MSVSOnly(_manifest, 'UseUnicodeResponseFiles', _boolean)
+
+# MSBuild options not found in MSVS.
+_MSBuildOnly(_manifest, 'EnableDPIAwareness', _boolean)
+_MSBuildOnly(_manifest, 'GenerateCategoryTags', _boolean)  # /category
+_MSBuildOnly(_manifest, 'ManifestFromManagedAssembly',
+             _file_name)  # /managedassemblyname
+_MSBuildOnly(_manifest, 'OutputResourceManifests', _string)  # /outputresource
+_MSBuildOnly(_manifest, 'SuppressDependencyElement', _boolean)  # /nodependency
+_MSBuildOnly(_manifest, 'TrackerLogDirectory', _folder_name)
diff --git a/gyp/pylib/gyp/MSVSSettings_test.py b/gyp/pylib/gyp/MSVSSettings_test.py
new file mode 100755 (executable)
index 0000000..9bd37ec
--- /dev/null
@@ -0,0 +1,1483 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unit tests for the MSVSSettings.py file."""
+
+import StringIO
+import unittest
+import gyp.MSVSSettings as MSVSSettings
+
+
+class TestSequenceFunctions(unittest.TestCase):
+
+  def setUp(self):
+    self.stderr = StringIO.StringIO()
+
+  def _ExpectedWarnings(self, expected):
+    """Compares recorded lines to expected warnings."""
+    self.stderr.seek(0)
+    actual = self.stderr.read().split('\n')
+    actual = [line for line in actual if line]
+    self.assertEqual(sorted(expected), sorted(actual))
+
+  def testValidateMSVSSettings_tool_names(self):
+    """Tests that only MSVS tool names are allowed."""
+    MSVSSettings.ValidateMSVSSettings(
+        {'VCCLCompilerTool': {},
+         'VCLinkerTool': {},
+         'VCMIDLTool': {},
+         'foo': {},
+         'VCResourceCompilerTool': {},
+         'VCLibrarianTool': {},
+         'VCManifestTool': {},
+         'ClCompile': {}},
+        self.stderr)
+    self._ExpectedWarnings([
+        'Warning: unrecognized tool foo',
+        'Warning: unrecognized tool ClCompile'])
+
+  def testValidateMSVSSettings_settings(self):
+    """Tests that for invalid MSVS settings."""
+    MSVSSettings.ValidateMSVSSettings(
+        {'VCCLCompilerTool': {
+            'AdditionalIncludeDirectories': 'folder1;folder2',
+            'AdditionalOptions': ['string1', 'string2'],
+            'AdditionalUsingDirectories': 'folder1;folder2',
+            'AssemblerListingLocation': 'a_file_name',
+            'AssemblerOutput': '0',
+            'BasicRuntimeChecks': '5',
+            'BrowseInformation': 'fdkslj',
+            'BrowseInformationFile': 'a_file_name',
+            'BufferSecurityCheck': 'true',
+            'CallingConvention': '-1',
+            'CompileAs': '1',
+            'DebugInformationFormat': '2',
+            'DefaultCharIsUnsigned': 'true',
+            'Detect64BitPortabilityProblems': 'true',
+            'DisableLanguageExtensions': 'true',
+            'DisableSpecificWarnings': 'string1;string2',
+            'EnableEnhancedInstructionSet': '1',
+            'EnableFiberSafeOptimizations': 'true',
+            'EnableFunctionLevelLinking': 'true',
+            'EnableIntrinsicFunctions': 'true',
+            'EnablePREfast': 'true',
+            'Enableprefast': 'bogus',
+            'ErrorReporting': '1',
+            'ExceptionHandling': '1',
+            'ExpandAttributedSource': 'true',
+            'FavorSizeOrSpeed': '1',
+            'FloatingPointExceptions': 'true',
+            'FloatingPointModel': '1',
+            'ForceConformanceInForLoopScope': 'true',
+            'ForcedIncludeFiles': 'file1;file2',
+            'ForcedUsingFiles': 'file1;file2',
+            'GeneratePreprocessedFile': '1',
+            'GenerateXMLDocumentationFiles': 'true',
+            'IgnoreStandardIncludePath': 'true',
+            'InlineFunctionExpansion': '1',
+            'KeepComments': 'true',
+            'MinimalRebuild': 'true',
+            'ObjectFile': 'a_file_name',
+            'OmitDefaultLibName': 'true',
+            'OmitFramePointers': 'true',
+            'OpenMP': 'true',
+            'Optimization': '1',
+            'PrecompiledHeaderFile': 'a_file_name',
+            'PrecompiledHeaderThrough': 'a_file_name',
+            'PreprocessorDefinitions': 'string1;string2',
+            'ProgramDataBaseFileName': 'a_file_name',
+            'RuntimeLibrary': '1',
+            'RuntimeTypeInfo': 'true',
+            'ShowIncludes': 'true',
+            'SmallerTypeCheck': 'true',
+            'StringPooling': 'true',
+            'StructMemberAlignment': '1',
+            'SuppressStartupBanner': 'true',
+            'TreatWChar_tAsBuiltInType': 'true',
+            'UndefineAllPreprocessorDefinitions': 'true',
+            'UndefinePreprocessorDefinitions': 'string1;string2',
+            'UseFullPaths': 'true',
+            'UsePrecompiledHeader': '1',
+            'UseUnicodeResponseFiles': 'true',
+            'WarnAsError': 'true',
+            'WarningLevel': '1',
+            'WholeProgramOptimization': 'true',
+            'XMLDocumentationFileName': 'a_file_name',
+            'ZZXYZ': 'bogus'},
+         'VCLinkerTool': {
+             'AdditionalDependencies': 'file1;file2',
+             'AdditionalDependencies_excluded': 'file3',
+             'AdditionalLibraryDirectories': 'folder1;folder2',
+             'AdditionalManifestDependencies': 'file1;file2',
+             'AdditionalOptions': 'a string1',
+             'AddModuleNamesToAssembly': 'file1;file2',
+             'AllowIsolation': 'true',
+             'AssemblyDebug': '2',
+             'AssemblyLinkResource': 'file1;file2',
+             'BaseAddress': 'a string1',
+             'CLRImageType': '2',
+             'CLRThreadAttribute': '2',
+             'CLRUnmanagedCodeCheck': 'true',
+             'DataExecutionPrevention': '2',
+             'DelayLoadDLLs': 'file1;file2',
+             'DelaySign': 'true',
+             'Driver': '2',
+             'EmbedManagedResourceFile': 'file1;file2',
+             'EnableCOMDATFolding': '2',
+             'EnableUAC': 'true',
+             'EntryPointSymbol': 'a string1',
+             'ErrorReporting': '2',
+             'FixedBaseAddress': '2',
+             'ForceSymbolReferences': 'file1;file2',
+             'FunctionOrder': 'a_file_name',
+             'GenerateDebugInformation': 'true',
+             'GenerateManifest': 'true',
+             'GenerateMapFile': 'true',
+             'HeapCommitSize': 'a string1',
+             'HeapReserveSize': 'a string1',
+             'IgnoreAllDefaultLibraries': 'true',
+             'IgnoreDefaultLibraryNames': 'file1;file2',
+             'IgnoreEmbeddedIDL': 'true',
+             'IgnoreImportLibrary': 'true',
+             'ImportLibrary': 'a_file_name',
+             'KeyContainer': 'a_file_name',
+             'KeyFile': 'a_file_name',
+             'LargeAddressAware': '2',
+             'LinkIncremental': '2',
+             'LinkLibraryDependencies': 'true',
+             'LinkTimeCodeGeneration': '2',
+             'ManifestFile': 'a_file_name',
+             'MapExports': 'true',
+             'MapFileName': 'a_file_name',
+             'MergedIDLBaseFileName': 'a_file_name',
+             'MergeSections': 'a string1',
+             'MidlCommandFile': 'a_file_name',
+             'ModuleDefinitionFile': 'a_file_name',
+             'OptimizeForWindows98': '1',
+             'OptimizeReferences': '2',
+             'OutputFile': 'a_file_name',
+             'PerUserRedirection': 'true',
+             'Profile': 'true',
+             'ProfileGuidedDatabase': 'a_file_name',
+             'ProgramDatabaseFile': 'a_file_name',
+             'RandomizedBaseAddress': '2',
+             'RegisterOutput': 'true',
+             'ResourceOnlyDLL': 'true',
+             'SetChecksum': 'true',
+             'ShowProgress': '2',
+             'StackCommitSize': 'a string1',
+             'StackReserveSize': 'a string1',
+             'StripPrivateSymbols': 'a_file_name',
+             'SubSystem': '2',
+             'SupportUnloadOfDelayLoadedDLL': 'true',
+             'SuppressStartupBanner': 'true',
+             'SwapRunFromCD': 'true',
+             'SwapRunFromNet': 'true',
+             'TargetMachine': '2',
+             'TerminalServerAware': '2',
+             'TurnOffAssemblyGeneration': 'true',
+             'TypeLibraryFile': 'a_file_name',
+             'TypeLibraryResourceID': '33',
+             'UACExecutionLevel': '2',
+             'UACUIAccess': 'true',
+             'UseLibraryDependencyInputs': 'true',
+             'UseUnicodeResponseFiles': 'true',
+             'Version': 'a string1'},
+         'VCMIDLTool': {
+             'AdditionalIncludeDirectories': 'folder1;folder2',
+             'AdditionalOptions': 'a string1',
+             'CPreprocessOptions': 'a string1',
+             'DefaultCharType': '1',
+             'DLLDataFileName': 'a_file_name',
+             'EnableErrorChecks': '1',
+             'ErrorCheckAllocations': 'true',
+             'ErrorCheckBounds': 'true',
+             'ErrorCheckEnumRange': 'true',
+             'ErrorCheckRefPointers': 'true',
+             'ErrorCheckStubData': 'true',
+             'GenerateStublessProxies': 'true',
+             'GenerateTypeLibrary': 'true',
+             'HeaderFileName': 'a_file_name',
+             'IgnoreStandardIncludePath': 'true',
+             'InterfaceIdentifierFileName': 'a_file_name',
+             'MkTypLibCompatible': 'true',
+             'notgood': 'bogus',
+             'OutputDirectory': 'a string1',
+             'PreprocessorDefinitions': 'string1;string2',
+             'ProxyFileName': 'a_file_name',
+             'RedirectOutputAndErrors': 'a_file_name',
+             'StructMemberAlignment': '1',
+             'SuppressStartupBanner': 'true',
+             'TargetEnvironment': '1',
+             'TypeLibraryName': 'a_file_name',
+             'UndefinePreprocessorDefinitions': 'string1;string2',
+             'ValidateParameters': 'true',
+             'WarnAsError': 'true',
+             'WarningLevel': '1'},
+         'VCResourceCompilerTool': {
+             'AdditionalOptions': 'a string1',
+             'AdditionalIncludeDirectories': 'folder1;folder2',
+             'Culture': '1003',
+             'IgnoreStandardIncludePath': 'true',
+             'notgood2': 'bogus',
+             'PreprocessorDefinitions': 'string1;string2',
+             'ResourceOutputFileName': 'a string1',
+             'ShowProgress': 'true',
+             'SuppressStartupBanner': 'true',
+             'UndefinePreprocessorDefinitions': 'string1;string2'},
+         'VCLibrarianTool': {
+             'AdditionalDependencies': 'file1;file2',
+             'AdditionalLibraryDirectories': 'folder1;folder2',
+             'AdditionalOptions': 'a string1',
+             'ExportNamedFunctions': 'string1;string2',
+             'ForceSymbolReferences': 'a string1',
+             'IgnoreAllDefaultLibraries': 'true',
+             'IgnoreSpecificDefaultLibraries': 'file1;file2',
+             'LinkLibraryDependencies': 'true',
+             'ModuleDefinitionFile': 'a_file_name',
+             'OutputFile': 'a_file_name',
+             'SuppressStartupBanner': 'true',
+             'UseUnicodeResponseFiles': 'true'},
+         'VCManifestTool': {
+             'AdditionalManifestFiles': 'file1;file2',
+             'AdditionalOptions': 'a string1',
+             'AssemblyIdentity': 'a string1',
+             'ComponentFileName': 'a_file_name',
+             'DependencyInformationFile': 'a_file_name',
+             'GenerateCatalogFiles': 'true',
+             'InputResourceManifests': 'a string1',
+             'ManifestResourceFile': 'a_file_name',
+             'OutputManifestFile': 'a_file_name',
+             'RegistrarScriptFile': 'a_file_name',
+             'ReplacementsFile': 'a_file_name',
+             'SuppressStartupBanner': 'true',
+             'TypeLibraryFile': 'a_file_name',
+             'UpdateFileHashes': 'truel',
+             'UpdateFileHashesSearchPath': 'a_file_name',
+             'UseFAT32Workaround': 'true',
+             'UseUnicodeResponseFiles': 'true',
+             'VerboseOutput': 'true'}},
+        self.stderr)
+    self._ExpectedWarnings([
+        'Warning: for VCCLCompilerTool/BasicRuntimeChecks, '
+        'index value (5) not in expected range [0, 4)',
+        'Warning: for VCCLCompilerTool/BrowseInformation, '
+        "invalid literal for int() with base 10: 'fdkslj'",
+        'Warning: for VCCLCompilerTool/CallingConvention, '
+        'index value (-1) not in expected range [0, 3)',
+        'Warning: for VCCLCompilerTool/DebugInformationFormat, '
+        'converted value for 2 not specified.',
+        'Warning: unrecognized setting VCCLCompilerTool/Enableprefast',
+        'Warning: unrecognized setting VCCLCompilerTool/ZZXYZ',
+        'Warning: for VCLinkerTool/TargetMachine, '
+        'converted value for 2 not specified.',
+        'Warning: unrecognized setting VCMIDLTool/notgood',
+        'Warning: unrecognized setting VCResourceCompilerTool/notgood2',
+        'Warning: for VCManifestTool/UpdateFileHashes, '
+        "expected bool; got 'truel'"
+        ''])
+
+  def testValidateMSBuildSettings_settings(self):
+    """Tests that for invalid MSBuild settings."""
+    MSVSSettings.ValidateMSBuildSettings(
+        {'ClCompile': {
+            'AdditionalIncludeDirectories': 'folder1;folder2',
+            'AdditionalOptions': ['string1', 'string2'],
+            'AdditionalUsingDirectories': 'folder1;folder2',
+            'AssemblerListingLocation': 'a_file_name',
+            'AssemblerOutput': 'NoListing',
+            'BasicRuntimeChecks': 'StackFrameRuntimeCheck',
+            'BrowseInformation': 'false',
+            'BrowseInformationFile': 'a_file_name',
+            'BufferSecurityCheck': 'true',
+            'BuildingInIDE': 'true',
+            'CallingConvention': 'Cdecl',
+            'CompileAs': 'CompileAsC',
+            'CompileAsManaged': 'Pure',
+            'CreateHotpatchableImage': 'true',
+            'DebugInformationFormat': 'ProgramDatabase',
+            'DisableLanguageExtensions': 'true',
+            'DisableSpecificWarnings': 'string1;string2',
+            'EnableEnhancedInstructionSet': 'StreamingSIMDExtensions',
+            'EnableFiberSafeOptimizations': 'true',
+            'EnablePREfast': 'true',
+            'Enableprefast': 'bogus',
+            'ErrorReporting': 'Prompt',
+            'ExceptionHandling': 'SyncCThrow',
+            'ExpandAttributedSource': 'true',
+            'FavorSizeOrSpeed': 'Neither',
+            'FloatingPointExceptions': 'true',
+            'FloatingPointModel': 'Precise',
+            'ForceConformanceInForLoopScope': 'true',
+            'ForcedIncludeFiles': 'file1;file2',
+            'ForcedUsingFiles': 'file1;file2',
+            'FunctionLevelLinking': 'false',
+            'GenerateXMLDocumentationFiles': 'true',
+            'IgnoreStandardIncludePath': 'true',
+            'InlineFunctionExpansion': 'OnlyExplicitInline',
+            'IntrinsicFunctions': 'false',
+            'MinimalRebuild': 'true',
+            'MultiProcessorCompilation': 'true',
+            'ObjectFileName': 'a_file_name',
+            'OmitDefaultLibName': 'true',
+            'OmitFramePointers': 'true',
+            'OpenMPSupport': 'true',
+            'Optimization': 'Disabled',
+            'PrecompiledHeader': 'NotUsing',
+            'PrecompiledHeaderFile': 'a_file_name',
+            'PrecompiledHeaderOutputFile': 'a_file_name',
+            'PreprocessKeepComments': 'true',
+            'PreprocessorDefinitions': 'string1;string2',
+            'PreprocessOutputPath': 'a string1',
+            'PreprocessSuppressLineNumbers': 'false',
+            'PreprocessToFile': 'false',
+            'ProcessorNumber': '33',
+            'ProgramDataBaseFileName': 'a_file_name',
+            'RuntimeLibrary': 'MultiThreaded',
+            'RuntimeTypeInfo': 'true',
+            'ShowIncludes': 'true',
+            'SmallerTypeCheck': 'true',
+            'StringPooling': 'true',
+            'StructMemberAlignment': '1Byte',
+            'SuppressStartupBanner': 'true',
+            'TrackerLogDirectory': 'a_folder',
+            'TreatSpecificWarningsAsErrors': 'string1;string2',
+            'TreatWarningAsError': 'true',
+            'TreatWChar_tAsBuiltInType': 'true',
+            'UndefineAllPreprocessorDefinitions': 'true',
+            'UndefinePreprocessorDefinitions': 'string1;string2',
+            'UseFullPaths': 'true',
+            'UseUnicodeForAssemblerListing': 'true',
+            'WarningLevel': 'TurnOffAllWarnings',
+            'WholeProgramOptimization': 'true',
+            'XMLDocumentationFileName': 'a_file_name',
+            'ZZXYZ': 'bogus'},
+         'Link': {
+             'AdditionalDependencies': 'file1;file2',
+             'AdditionalLibraryDirectories': 'folder1;folder2',
+             'AdditionalManifestDependencies': 'file1;file2',
+             'AdditionalOptions': 'a string1',
+             'AddModuleNamesToAssembly': 'file1;file2',
+             'AllowIsolation': 'true',
+             'AssemblyDebug': '',
+             'AssemblyLinkResource': 'file1;file2',
+             'BaseAddress': 'a string1',
+             'BuildingInIDE': 'true',
+             'CLRImageType': 'ForceIJWImage',
+             'CLRSupportLastError': 'Enabled',
+             'CLRThreadAttribute': 'MTAThreadingAttribute',
+             'CLRUnmanagedCodeCheck': 'true',
+             'CreateHotPatchableImage': 'X86Image',
+             'DataExecutionPrevention': 'false',
+             'DelayLoadDLLs': 'file1;file2',
+             'DelaySign': 'true',
+             'Driver': 'NotSet',
+             'EmbedManagedResourceFile': 'file1;file2',
+             'EnableCOMDATFolding': 'false',
+             'EnableUAC': 'true',
+             'EntryPointSymbol': 'a string1',
+             'FixedBaseAddress': 'false',
+             'ForceFileOutput': 'Enabled',
+             'ForceSymbolReferences': 'file1;file2',
+             'FunctionOrder': 'a_file_name',
+             'GenerateDebugInformation': 'true',
+             'GenerateMapFile': 'true',
+             'HeapCommitSize': 'a string1',
+             'HeapReserveSize': 'a string1',
+             'IgnoreAllDefaultLibraries': 'true',
+             'IgnoreEmbeddedIDL': 'true',
+             'IgnoreSpecificDefaultLibraries': 'a_file_list',
+             'ImageHasSafeExceptionHandlers': 'true',
+             'ImportLibrary': 'a_file_name',
+             'KeyContainer': 'a_file_name',
+             'KeyFile': 'a_file_name',
+             'LargeAddressAware': 'false',
+             'LinkDLL': 'true',
+             'LinkErrorReporting': 'SendErrorReport',
+             'LinkStatus': 'true',
+             'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration',
+             'ManifestFile': 'a_file_name',
+             'MapExports': 'true',
+             'MapFileName': 'a_file_name',
+             'MergedIDLBaseFileName': 'a_file_name',
+             'MergeSections': 'a string1',
+             'MidlCommandFile': 'a_file_name',
+             'MinimumRequiredVersion': 'a string1',
+             'ModuleDefinitionFile': 'a_file_name',
+             'MSDOSStubFileName': 'a_file_name',
+             'NoEntryPoint': 'true',
+             'OptimizeReferences': 'false',
+             'OutputFile': 'a_file_name',
+             'PerUserRedirection': 'true',
+             'PreventDllBinding': 'true',
+             'Profile': 'true',
+             'ProfileGuidedDatabase': 'a_file_name',
+             'ProgramDatabaseFile': 'a_file_name',
+             'RandomizedBaseAddress': 'false',
+             'RegisterOutput': 'true',
+             'SectionAlignment': '33',
+             'SetChecksum': 'true',
+             'ShowProgress': 'LinkVerboseREF',
+             'SpecifySectionAttributes': 'a string1',
+             'StackCommitSize': 'a string1',
+             'StackReserveSize': 'a string1',
+             'StripPrivateSymbols': 'a_file_name',
+             'SubSystem': 'Console',
+             'SupportNobindOfDelayLoadedDLL': 'true',
+             'SupportUnloadOfDelayLoadedDLL': 'true',
+             'SuppressStartupBanner': 'true',
+             'SwapRunFromCD': 'true',
+             'SwapRunFromNET': 'true',
+             'TargetMachine': 'MachineX86',
+             'TerminalServerAware': 'false',
+             'TrackerLogDirectory': 'a_folder',
+             'TreatLinkerWarningAsErrors': 'true',
+             'TurnOffAssemblyGeneration': 'true',
+             'TypeLibraryFile': 'a_file_name',
+             'TypeLibraryResourceID': '33',
+             'UACExecutionLevel': 'AsInvoker',
+             'UACUIAccess': 'true',
+             'Version': 'a string1'},
+         'ResourceCompile': {
+             'AdditionalIncludeDirectories': 'folder1;folder2',
+             'AdditionalOptions': 'a string1',
+             'Culture': '0x236',
+             'IgnoreStandardIncludePath': 'true',
+             'NullTerminateStrings': 'true',
+             'PreprocessorDefinitions': 'string1;string2',
+             'ResourceOutputFileName': 'a string1',
+             'ShowProgress': 'true',
+             'SuppressStartupBanner': 'true',
+             'TrackerLogDirectory': 'a_folder',
+             'UndefinePreprocessorDefinitions': 'string1;string2'},
+         'Midl': {
+             'AdditionalIncludeDirectories': 'folder1;folder2',
+             'AdditionalOptions': 'a string1',
+             'ApplicationConfigurationMode': 'true',
+             'ClientStubFile': 'a_file_name',
+             'CPreprocessOptions': 'a string1',
+             'DefaultCharType': 'Signed',
+             'DllDataFileName': 'a_file_name',
+             'EnableErrorChecks': 'EnableCustom',
+             'ErrorCheckAllocations': 'true',
+             'ErrorCheckBounds': 'true',
+             'ErrorCheckEnumRange': 'true',
+             'ErrorCheckRefPointers': 'true',
+             'ErrorCheckStubData': 'true',
+             'GenerateClientFiles': 'Stub',
+             'GenerateServerFiles': 'None',
+             'GenerateStublessProxies': 'true',
+             'GenerateTypeLibrary': 'true',
+             'HeaderFileName': 'a_file_name',
+             'IgnoreStandardIncludePath': 'true',
+             'InterfaceIdentifierFileName': 'a_file_name',
+             'LocaleID': '33',
+             'MkTypLibCompatible': 'true',
+             'OutputDirectory': 'a string1',
+             'PreprocessorDefinitions': 'string1;string2',
+             'ProxyFileName': 'a_file_name',
+             'RedirectOutputAndErrors': 'a_file_name',
+             'ServerStubFile': 'a_file_name',
+             'StructMemberAlignment': 'NotSet',
+             'SuppressCompilerWarnings': 'true',
+             'SuppressStartupBanner': 'true',
+             'TargetEnvironment': 'Itanium',
+             'TrackerLogDirectory': 'a_folder',
+             'TypeLibFormat': 'NewFormat',
+             'TypeLibraryName': 'a_file_name',
+             'UndefinePreprocessorDefinitions': 'string1;string2',
+             'ValidateAllParameters': 'true',
+             'WarnAsError': 'true',
+             'WarningLevel': '1'},
+         'Lib': {
+             'AdditionalDependencies': 'file1;file2',
+             'AdditionalLibraryDirectories': 'folder1;folder2',
+             'AdditionalOptions': 'a string1',
+             'DisplayLibrary': 'a string1',
+             'ErrorReporting': 'PromptImmediately',
+             'ExportNamedFunctions': 'string1;string2',
+             'ForceSymbolReferences': 'a string1',
+             'IgnoreAllDefaultLibraries': 'true',
+             'IgnoreSpecificDefaultLibraries': 'file1;file2',
+             'LinkTimeCodeGeneration': 'true',
+             'MinimumRequiredVersion': 'a string1',
+             'ModuleDefinitionFile': 'a_file_name',
+             'Name': 'a_file_name',
+             'OutputFile': 'a_file_name',
+             'RemoveObjects': 'file1;file2',
+             'SubSystem': 'Console',
+             'SuppressStartupBanner': 'true',
+             'TargetMachine': 'MachineX86i',
+             'TrackerLogDirectory': 'a_folder',
+             'TreatLibWarningAsErrors': 'true',
+             'UseUnicodeResponseFiles': 'true',
+             'Verbose': 'true'},
+         'Manifest': {
+             'AdditionalManifestFiles': 'file1;file2',
+             'AdditionalOptions': 'a string1',
+             'AssemblyIdentity': 'a string1',
+             'ComponentFileName': 'a_file_name',
+             'EnableDPIAwareness': 'fal',
+             'GenerateCatalogFiles': 'truel',
+             'GenerateCategoryTags': 'true',
+             'InputResourceManifests': 'a string1',
+             'ManifestFromManagedAssembly': 'a_file_name',
+             'notgood3': 'bogus',
+             'OutputManifestFile': 'a_file_name',
+             'OutputResourceManifests': 'a string1',
+             'RegistrarScriptFile': 'a_file_name',
+             'ReplacementsFile': 'a_file_name',
+             'SuppressDependencyElement': 'true',
+             'SuppressStartupBanner': 'true',
+             'TrackerLogDirectory': 'a_folder',
+             'TypeLibraryFile': 'a_file_name',
+             'UpdateFileHashes': 'true',
+             'UpdateFileHashesSearchPath': 'a_file_name',
+             'VerboseOutput': 'true'},
+         'ProjectReference': {
+             'LinkLibraryDependencies': 'true',
+             'UseLibraryDependencyInputs': 'true'},
+         'ManifestResourceCompile': {
+             'ResourceOutputFileName': 'a_file_name'},
+         '': {
+             'EmbedManifest': 'true',
+             'GenerateManifest': 'true',
+             'IgnoreImportLibrary': 'true',
+             'LinkIncremental': 'false'}},
+        self.stderr)
+    self._ExpectedWarnings([
+        'Warning: unrecognized setting ClCompile/Enableprefast',
+        'Warning: unrecognized setting ClCompile/ZZXYZ',
+        'Warning: unrecognized setting Manifest/notgood3',
+        'Warning: for Manifest/GenerateCatalogFiles, '
+        "expected bool; got 'truel'",
+        'Warning: for Lib/TargetMachine, unrecognized enumerated value '
+        'MachineX86i',
+        "Warning: for Manifest/EnableDPIAwareness, expected bool; got 'fal'"])
+
+  def testConvertToMSBuildSettings_empty(self):
+    """Tests an empty conversion."""
+    msvs_settings = {}
+    expected_msbuild_settings = {}
+    actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings(
+        msvs_settings,
+        self.stderr)
+    self.assertEqual(expected_msbuild_settings, actual_msbuild_settings)
+    self._ExpectedWarnings([])
+
+  def testConvertToMSBuildSettings_minimal(self):
+    """Tests a minimal conversion."""
+    msvs_settings = {
+        'VCCLCompilerTool': {
+            'AdditionalIncludeDirectories': 'dir1',
+            'AdditionalOptions': '/foo',
+            'BasicRuntimeChecks': '0',
+            },
+        'VCLinkerTool': {
+            'LinkTimeCodeGeneration': '1',
+            'ErrorReporting': '1',
+            'DataExecutionPrevention': '2',
+            },
+        }
+    expected_msbuild_settings = {
+        'ClCompile': {
+            'AdditionalIncludeDirectories': 'dir1',
+            'AdditionalOptions': '/foo',
+            'BasicRuntimeChecks': 'Default',
+            },
+        'Link': {
+            'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration',
+            'LinkErrorReporting': 'PromptImmediately',
+            'DataExecutionPrevention': 'true',
+            },
+        }
+    actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings(
+        msvs_settings,
+        self.stderr)
+    self.assertEqual(expected_msbuild_settings, actual_msbuild_settings)
+    self._ExpectedWarnings([])
+
+  def testConvertToMSBuildSettings_warnings(self):
+    """Tests conversion that generates warnings."""
+    msvs_settings = {
+        'VCCLCompilerTool': {
+            'AdditionalIncludeDirectories': '1',
+            'AdditionalOptions': '2',
+            # These are incorrect values:
+            'BasicRuntimeChecks': '12',
+            'BrowseInformation': '21',
+            'UsePrecompiledHeader': '13',
+            'GeneratePreprocessedFile': '14'},
+        'VCLinkerTool': {
+            # These are incorrect values:
+            'Driver': '10',
+            'LinkTimeCodeGeneration': '31',
+            'ErrorReporting': '21',
+            'FixedBaseAddress': '6'},
+        'VCResourceCompilerTool': {
+            # Custom
+            'Culture': '1003'}}
+    expected_msbuild_settings = {
+        'ClCompile': {
+            'AdditionalIncludeDirectories': '1',
+            'AdditionalOptions': '2'},
+        'Link': {},
+        'ResourceCompile': {
+            # Custom
+            'Culture': '0x03eb'}}
+    actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings(
+        msvs_settings,
+        self.stderr)
+    self.assertEqual(expected_msbuild_settings, actual_msbuild_settings)
+    self._ExpectedWarnings([
+        'Warning: while converting VCCLCompilerTool/BasicRuntimeChecks to '
+        'MSBuild, index value (12) not in expected range [0, 4)',
+        'Warning: while converting VCCLCompilerTool/BrowseInformation to '
+        'MSBuild, index value (21) not in expected range [0, 3)',
+        'Warning: while converting VCCLCompilerTool/UsePrecompiledHeader to '
+        'MSBuild, index value (13) not in expected range [0, 3)',
+        'Warning: while converting VCCLCompilerTool/GeneratePreprocessedFile to '
+        'MSBuild, value must be one of [0, 1, 2]; got 14',
+
+        'Warning: while converting VCLinkerTool/Driver to '
+        'MSBuild, index value (10) not in expected range [0, 4)',
+        'Warning: while converting VCLinkerTool/LinkTimeCodeGeneration to '
+        'MSBuild, index value (31) not in expected range [0, 5)',
+        'Warning: while converting VCLinkerTool/ErrorReporting to '
+        'MSBuild, index value (21) not in expected range [0, 3)',
+        'Warning: while converting VCLinkerTool/FixedBaseAddress to '
+        'MSBuild, index value (6) not in expected range [0, 3)',
+        ])
+
+  def testConvertToMSBuildSettings_full_synthetic(self):
+    """Tests conversion of all the MSBuild settings."""
+    msvs_settings = {
+        'VCCLCompilerTool': {
+            'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+            'AdditionalOptions': 'a_string',
+            'AdditionalUsingDirectories': 'folder1;folder2;folder3',
+            'AssemblerListingLocation': 'a_file_name',
+            'AssemblerOutput': '0',
+            'BasicRuntimeChecks': '1',
+            'BrowseInformation': '2',
+            'BrowseInformationFile': 'a_file_name',
+            'BufferSecurityCheck': 'true',
+            'CallingConvention': '0',
+            'CompileAs': '1',
+            'DebugInformationFormat': '4',
+            'DefaultCharIsUnsigned': 'true',
+            'Detect64BitPortabilityProblems': 'true',
+            'DisableLanguageExtensions': 'true',
+            'DisableSpecificWarnings': 'd1;d2;d3',
+            'EnableEnhancedInstructionSet': '0',
+            'EnableFiberSafeOptimizations': 'true',
+            'EnableFunctionLevelLinking': 'true',
+            'EnableIntrinsicFunctions': 'true',
+            'EnablePREfast': 'true',
+            'ErrorReporting': '1',
+            'ExceptionHandling': '2',
+            'ExpandAttributedSource': 'true',
+            'FavorSizeOrSpeed': '0',
+            'FloatingPointExceptions': 'true',
+            'FloatingPointModel': '1',
+            'ForceConformanceInForLoopScope': 'true',
+            'ForcedIncludeFiles': 'file1;file2;file3',
+            'ForcedUsingFiles': 'file1;file2;file3',
+            'GeneratePreprocessedFile': '1',
+            'GenerateXMLDocumentationFiles': 'true',
+            'IgnoreStandardIncludePath': 'true',
+            'InlineFunctionExpansion': '2',
+            'KeepComments': 'true',
+            'MinimalRebuild': 'true',
+            'ObjectFile': 'a_file_name',
+            'OmitDefaultLibName': 'true',
+            'OmitFramePointers': 'true',
+            'OpenMP': 'true',
+            'Optimization': '3',
+            'PrecompiledHeaderFile': 'a_file_name',
+            'PrecompiledHeaderThrough': 'a_file_name',
+            'PreprocessorDefinitions': 'd1;d2;d3',
+            'ProgramDataBaseFileName': 'a_file_name',
+            'RuntimeLibrary': '0',
+            'RuntimeTypeInfo': 'true',
+            'ShowIncludes': 'true',
+            'SmallerTypeCheck': 'true',
+            'StringPooling': 'true',
+            'StructMemberAlignment': '1',
+            'SuppressStartupBanner': 'true',
+            'TreatWChar_tAsBuiltInType': 'true',
+            'UndefineAllPreprocessorDefinitions': 'true',
+            'UndefinePreprocessorDefinitions': 'd1;d2;d3',
+            'UseFullPaths': 'true',
+            'UsePrecompiledHeader': '1',
+            'UseUnicodeResponseFiles': 'true',
+            'WarnAsError': 'true',
+            'WarningLevel': '2',
+            'WholeProgramOptimization': 'true',
+            'XMLDocumentationFileName': 'a_file_name'},
+        'VCLinkerTool': {
+            'AdditionalDependencies': 'file1;file2;file3',
+            'AdditionalLibraryDirectories': 'folder1;folder2;folder3',
+            'AdditionalLibraryDirectories_excluded': 'folder1;folder2;folder3',
+            'AdditionalManifestDependencies': 'file1;file2;file3',
+            'AdditionalOptions': 'a_string',
+            'AddModuleNamesToAssembly': 'file1;file2;file3',
+            'AllowIsolation': 'true',
+            'AssemblyDebug': '0',
+            'AssemblyLinkResource': 'file1;file2;file3',
+            'BaseAddress': 'a_string',
+            'CLRImageType': '1',
+            'CLRThreadAttribute': '2',
+            'CLRUnmanagedCodeCheck': 'true',
+            'DataExecutionPrevention': '0',
+            'DelayLoadDLLs': 'file1;file2;file3',
+            'DelaySign': 'true',
+            'Driver': '1',
+            'EmbedManagedResourceFile': 'file1;file2;file3',
+            'EnableCOMDATFolding': '0',
+            'EnableUAC': 'true',
+            'EntryPointSymbol': 'a_string',
+            'ErrorReporting': '0',
+            'FixedBaseAddress': '1',
+            'ForceSymbolReferences': 'file1;file2;file3',
+            'FunctionOrder': 'a_file_name',
+            'GenerateDebugInformation': 'true',
+            'GenerateManifest': 'true',
+            'GenerateMapFile': 'true',
+            'HeapCommitSize': 'a_string',
+            'HeapReserveSize': 'a_string',
+            'IgnoreAllDefaultLibraries': 'true',
+            'IgnoreDefaultLibraryNames': 'file1;file2;file3',
+            'IgnoreEmbeddedIDL': 'true',
+            'IgnoreImportLibrary': 'true',
+            'ImportLibrary': 'a_file_name',
+            'KeyContainer': 'a_file_name',
+            'KeyFile': 'a_file_name',
+            'LargeAddressAware': '2',
+            'LinkIncremental': '1',
+            'LinkLibraryDependencies': 'true',
+            'LinkTimeCodeGeneration': '2',
+            'ManifestFile': 'a_file_name',
+            'MapExports': 'true',
+            'MapFileName': 'a_file_name',
+            'MergedIDLBaseFileName': 'a_file_name',
+            'MergeSections': 'a_string',
+            'MidlCommandFile': 'a_file_name',
+            'ModuleDefinitionFile': 'a_file_name',
+            'OptimizeForWindows98': '1',
+            'OptimizeReferences': '0',
+            'OutputFile': 'a_file_name',
+            'PerUserRedirection': 'true',
+            'Profile': 'true',
+            'ProfileGuidedDatabase': 'a_file_name',
+            'ProgramDatabaseFile': 'a_file_name',
+            'RandomizedBaseAddress': '1',
+            'RegisterOutput': 'true',
+            'ResourceOnlyDLL': 'true',
+            'SetChecksum': 'true',
+            'ShowProgress': '0',
+            'StackCommitSize': 'a_string',
+            'StackReserveSize': 'a_string',
+            'StripPrivateSymbols': 'a_file_name',
+            'SubSystem': '2',
+            'SupportUnloadOfDelayLoadedDLL': 'true',
+            'SuppressStartupBanner': 'true',
+            'SwapRunFromCD': 'true',
+            'SwapRunFromNet': 'true',
+            'TargetMachine': '3',
+            'TerminalServerAware': '2',
+            'TurnOffAssemblyGeneration': 'true',
+            'TypeLibraryFile': 'a_file_name',
+            'TypeLibraryResourceID': '33',
+            'UACExecutionLevel': '1',
+            'UACUIAccess': 'true',
+            'UseLibraryDependencyInputs': 'false',
+            'UseUnicodeResponseFiles': 'true',
+            'Version': 'a_string'},
+        'VCResourceCompilerTool': {
+            'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+            'AdditionalOptions': 'a_string',
+            'Culture': '1003',
+            'IgnoreStandardIncludePath': 'true',
+            'PreprocessorDefinitions': 'd1;d2;d3',
+            'ResourceOutputFileName': 'a_string',
+            'ShowProgress': 'true',
+            'SuppressStartupBanner': 'true',
+            'UndefinePreprocessorDefinitions': 'd1;d2;d3'},
+        'VCMIDLTool': {
+            'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+            'AdditionalOptions': 'a_string',
+            'CPreprocessOptions': 'a_string',
+            'DefaultCharType': '0',
+            'DLLDataFileName': 'a_file_name',
+            'EnableErrorChecks': '2',
+            'ErrorCheckAllocations': 'true',
+            'ErrorCheckBounds': 'true',
+            'ErrorCheckEnumRange': 'true',
+            'ErrorCheckRefPointers': 'true',
+            'ErrorCheckStubData': 'true',
+            'GenerateStublessProxies': 'true',
+            'GenerateTypeLibrary': 'true',
+            'HeaderFileName': 'a_file_name',
+            'IgnoreStandardIncludePath': 'true',
+            'InterfaceIdentifierFileName': 'a_file_name',
+            'MkTypLibCompatible': 'true',
+            'OutputDirectory': 'a_string',
+            'PreprocessorDefinitions': 'd1;d2;d3',
+            'ProxyFileName': 'a_file_name',
+            'RedirectOutputAndErrors': 'a_file_name',
+            'StructMemberAlignment': '3',
+            'SuppressStartupBanner': 'true',
+            'TargetEnvironment': '1',
+            'TypeLibraryName': 'a_file_name',
+            'UndefinePreprocessorDefinitions': 'd1;d2;d3',
+            'ValidateParameters': 'true',
+            'WarnAsError': 'true',
+            'WarningLevel': '4'},
+        'VCLibrarianTool': {
+            'AdditionalDependencies': 'file1;file2;file3',
+            'AdditionalLibraryDirectories': 'folder1;folder2;folder3',
+            'AdditionalLibraryDirectories_excluded': 'folder1;folder2;folder3',
+            'AdditionalOptions': 'a_string',
+            'ExportNamedFunctions': 'd1;d2;d3',
+            'ForceSymbolReferences': 'a_string',
+            'IgnoreAllDefaultLibraries': 'true',
+            'IgnoreSpecificDefaultLibraries': 'file1;file2;file3',
+            'LinkLibraryDependencies': 'true',
+            'ModuleDefinitionFile': 'a_file_name',
+            'OutputFile': 'a_file_name',
+            'SuppressStartupBanner': 'true',
+            'UseUnicodeResponseFiles': 'true'},
+        'VCManifestTool': {
+            'AdditionalManifestFiles': 'file1;file2;file3',
+            'AdditionalOptions': 'a_string',
+            'AssemblyIdentity': 'a_string',
+            'ComponentFileName': 'a_file_name',
+            'DependencyInformationFile': 'a_file_name',
+            'EmbedManifest': 'true',
+            'GenerateCatalogFiles': 'true',
+            'InputResourceManifests': 'a_string',
+            'ManifestResourceFile': 'my_name',
+            'OutputManifestFile': 'a_file_name',
+            'RegistrarScriptFile': 'a_file_name',
+            'ReplacementsFile': 'a_file_name',
+            'SuppressStartupBanner': 'true',
+            'TypeLibraryFile': 'a_file_name',
+            'UpdateFileHashes': 'true',
+            'UpdateFileHashesSearchPath': 'a_file_name',
+            'UseFAT32Workaround': 'true',
+            'UseUnicodeResponseFiles': 'true',
+            'VerboseOutput': 'true'}}
+    expected_msbuild_settings = {
+        'ClCompile': {
+            'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+            'AdditionalOptions': 'a_string /J',
+            'AdditionalUsingDirectories': 'folder1;folder2;folder3',
+            'AssemblerListingLocation': 'a_file_name',
+            'AssemblerOutput': 'NoListing',
+            'BasicRuntimeChecks': 'StackFrameRuntimeCheck',
+            'BrowseInformation': 'true',
+            'BrowseInformationFile': 'a_file_name',
+            'BufferSecurityCheck': 'true',
+            'CallingConvention': 'Cdecl',
+            'CompileAs': 'CompileAsC',
+            'DebugInformationFormat': 'EditAndContinue',
+            'DisableLanguageExtensions': 'true',
+            'DisableSpecificWarnings': 'd1;d2;d3',
+            'EnableEnhancedInstructionSet': 'NotSet',
+            'EnableFiberSafeOptimizations': 'true',
+            'EnablePREfast': 'true',
+            'ErrorReporting': 'Prompt',
+            'ExceptionHandling': 'Async',
+            'ExpandAttributedSource': 'true',
+            'FavorSizeOrSpeed': 'Neither',
+            'FloatingPointExceptions': 'true',
+            'FloatingPointModel': 'Strict',
+            'ForceConformanceInForLoopScope': 'true',
+            'ForcedIncludeFiles': 'file1;file2;file3',
+            'ForcedUsingFiles': 'file1;file2;file3',
+            'FunctionLevelLinking': 'true',
+            'GenerateXMLDocumentationFiles': 'true',
+            'IgnoreStandardIncludePath': 'true',
+            'InlineFunctionExpansion': 'AnySuitable',
+            'IntrinsicFunctions': 'true',
+            'MinimalRebuild': 'true',
+            'ObjectFileName': 'a_file_name',
+            'OmitDefaultLibName': 'true',
+            'OmitFramePointers': 'true',
+            'OpenMPSupport': 'true',
+            'Optimization': 'Full',
+            'PrecompiledHeader': 'Create',
+            'PrecompiledHeaderFile': 'a_file_name',
+            'PrecompiledHeaderOutputFile': 'a_file_name',
+            'PreprocessKeepComments': 'true',
+            'PreprocessorDefinitions': 'd1;d2;d3',
+            'PreprocessSuppressLineNumbers': 'false',
+            'PreprocessToFile': 'true',
+            'ProgramDataBaseFileName': 'a_file_name',
+            'RuntimeLibrary': 'MultiThreaded',
+            'RuntimeTypeInfo': 'true',
+            'ShowIncludes': 'true',
+            'SmallerTypeCheck': 'true',
+            'StringPooling': 'true',
+            'StructMemberAlignment': '1Byte',
+            'SuppressStartupBanner': 'true',
+            'TreatWarningAsError': 'true',
+            'TreatWChar_tAsBuiltInType': 'true',
+            'UndefineAllPreprocessorDefinitions': 'true',
+            'UndefinePreprocessorDefinitions': 'd1;d2;d3',
+            'UseFullPaths': 'true',
+            'WarningLevel': 'Level2',
+            'WholeProgramOptimization': 'true',
+            'XMLDocumentationFileName': 'a_file_name'},
+        'Link': {
+            'AdditionalDependencies': 'file1;file2;file3',
+            'AdditionalLibraryDirectories': 'folder1;folder2;folder3',
+            'AdditionalManifestDependencies': 'file1;file2;file3',
+            'AdditionalOptions': 'a_string',
+            'AddModuleNamesToAssembly': 'file1;file2;file3',
+            'AllowIsolation': 'true',
+            'AssemblyDebug': '',
+            'AssemblyLinkResource': 'file1;file2;file3',
+            'BaseAddress': 'a_string',
+            'CLRImageType': 'ForceIJWImage',
+            'CLRThreadAttribute': 'STAThreadingAttribute',
+            'CLRUnmanagedCodeCheck': 'true',
+            'DataExecutionPrevention': '',
+            'DelayLoadDLLs': 'file1;file2;file3',
+            'DelaySign': 'true',
+            'Driver': 'Driver',
+            'EmbedManagedResourceFile': 'file1;file2;file3',
+            'EnableCOMDATFolding': '',
+            'EnableUAC': 'true',
+            'EntryPointSymbol': 'a_string',
+            'FixedBaseAddress': 'false',
+            'ForceSymbolReferences': 'file1;file2;file3',
+            'FunctionOrder': 'a_file_name',
+            'GenerateDebugInformation': 'true',
+            'GenerateMapFile': 'true',
+            'HeapCommitSize': 'a_string',
+            'HeapReserveSize': 'a_string',
+            'IgnoreAllDefaultLibraries': 'true',
+            'IgnoreEmbeddedIDL': 'true',
+            'IgnoreSpecificDefaultLibraries': 'file1;file2;file3',
+            'ImportLibrary': 'a_file_name',
+            'KeyContainer': 'a_file_name',
+            'KeyFile': 'a_file_name',
+            'LargeAddressAware': 'true',
+            'LinkErrorReporting': 'NoErrorReport',
+            'LinkTimeCodeGeneration': 'PGInstrument',
+            'ManifestFile': 'a_file_name',
+            'MapExports': 'true',
+            'MapFileName': 'a_file_name',
+            'MergedIDLBaseFileName': 'a_file_name',
+            'MergeSections': 'a_string',
+            'MidlCommandFile': 'a_file_name',
+            'ModuleDefinitionFile': 'a_file_name',
+            'NoEntryPoint': 'true',
+            'OptimizeReferences': '',
+            'OutputFile': 'a_file_name',
+            'PerUserRedirection': 'true',
+            'Profile': 'true',
+            'ProfileGuidedDatabase': 'a_file_name',
+            'ProgramDatabaseFile': 'a_file_name',
+            'RandomizedBaseAddress': 'false',
+            'RegisterOutput': 'true',
+            'SetChecksum': 'true',
+            'ShowProgress': 'NotSet',
+            'StackCommitSize': 'a_string',
+            'StackReserveSize': 'a_string',
+            'StripPrivateSymbols': 'a_file_name',
+            'SubSystem': 'Windows',
+            'SupportUnloadOfDelayLoadedDLL': 'true',
+            'SuppressStartupBanner': 'true',
+            'SwapRunFromCD': 'true',
+            'SwapRunFromNET': 'true',
+            'TargetMachine': 'MachineARM',
+            'TerminalServerAware': 'true',
+            'TurnOffAssemblyGeneration': 'true',
+            'TypeLibraryFile': 'a_file_name',
+            'TypeLibraryResourceID': '33',
+            'UACExecutionLevel': 'HighestAvailable',
+            'UACUIAccess': 'true',
+            'Version': 'a_string'},
+        'ResourceCompile': {
+            'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+            'AdditionalOptions': 'a_string',
+            'Culture': '0x03eb',
+            'IgnoreStandardIncludePath': 'true',
+            'PreprocessorDefinitions': 'd1;d2;d3',
+            'ResourceOutputFileName': 'a_string',
+            'ShowProgress': 'true',
+            'SuppressStartupBanner': 'true',
+            'UndefinePreprocessorDefinitions': 'd1;d2;d3'},
+        'Midl': {
+            'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+            'AdditionalOptions': 'a_string',
+            'CPreprocessOptions': 'a_string',
+            'DefaultCharType': 'Unsigned',
+            'DllDataFileName': 'a_file_name',
+            'EnableErrorChecks': 'All',
+            'ErrorCheckAllocations': 'true',
+            'ErrorCheckBounds': 'true',
+            'ErrorCheckEnumRange': 'true',
+            'ErrorCheckRefPointers': 'true',
+            'ErrorCheckStubData': 'true',
+            'GenerateStublessProxies': 'true',
+            'GenerateTypeLibrary': 'true',
+            'HeaderFileName': 'a_file_name',
+            'IgnoreStandardIncludePath': 'true',
+            'InterfaceIdentifierFileName': 'a_file_name',
+            'MkTypLibCompatible': 'true',
+            'OutputDirectory': 'a_string',
+            'PreprocessorDefinitions': 'd1;d2;d3',
+            'ProxyFileName': 'a_file_name',
+            'RedirectOutputAndErrors': 'a_file_name',
+            'StructMemberAlignment': '4',
+            'SuppressStartupBanner': 'true',
+            'TargetEnvironment': 'Win32',
+            'TypeLibraryName': 'a_file_name',
+            'UndefinePreprocessorDefinitions': 'd1;d2;d3',
+            'ValidateAllParameters': 'true',
+            'WarnAsError': 'true',
+            'WarningLevel': '4'},
+        'Lib': {
+            'AdditionalDependencies': 'file1;file2;file3',
+            'AdditionalLibraryDirectories': 'folder1;folder2;folder3',
+            'AdditionalOptions': 'a_string',
+            'ExportNamedFunctions': 'd1;d2;d3',
+            'ForceSymbolReferences': 'a_string',
+            'IgnoreAllDefaultLibraries': 'true',
+            'IgnoreSpecificDefaultLibraries': 'file1;file2;file3',
+            'ModuleDefinitionFile': 'a_file_name',
+            'OutputFile': 'a_file_name',
+            'SuppressStartupBanner': 'true',
+            'UseUnicodeResponseFiles': 'true'},
+        'Manifest': {
+            'AdditionalManifestFiles': 'file1;file2;file3',
+            'AdditionalOptions': 'a_string',
+            'AssemblyIdentity': 'a_string',
+            'ComponentFileName': 'a_file_name',
+            'GenerateCatalogFiles': 'true',
+            'InputResourceManifests': 'a_string',
+            'OutputManifestFile': 'a_file_name',
+            'RegistrarScriptFile': 'a_file_name',
+            'ReplacementsFile': 'a_file_name',
+            'SuppressStartupBanner': 'true',
+            'TypeLibraryFile': 'a_file_name',
+            'UpdateFileHashes': 'true',
+            'UpdateFileHashesSearchPath': 'a_file_name',
+            'VerboseOutput': 'true'},
+        'ManifestResourceCompile': {
+            'ResourceOutputFileName': 'my_name'},
+        'ProjectReference': {
+            'LinkLibraryDependencies': 'true',
+            'UseLibraryDependencyInputs': 'false'},
+        '': {
+            'EmbedManifest': 'true',
+            'GenerateManifest': 'true',
+            'IgnoreImportLibrary': 'true',
+            'LinkIncremental': 'false'}}
+    actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings(
+        msvs_settings,
+        self.stderr)
+    self.assertEqual(expected_msbuild_settings, actual_msbuild_settings)
+    self._ExpectedWarnings([])
+
+  def testConvertToMSBuildSettings_actual(self):
+    """Tests the conversion of an actual project.
+
+    A VS2008 project with most of the options defined was created through the
+    VS2008 IDE.  It was then converted to VS2010.  The tool settings found in
+    the .vcproj and .vcxproj files were converted to the two dictionaries
+    msvs_settings and expected_msbuild_settings.
+
+    Note that for many settings, the VS2010 converter adds macros like
+    %(AdditionalIncludeDirectories) to make sure than inherited values are
+    included.  Since the Gyp projects we generate do not use inheritance,
+    we removed these macros.  They were:
+        ClCompile:
+            AdditionalIncludeDirectories:  ';%(AdditionalIncludeDirectories)'
+            AdditionalOptions:  ' %(AdditionalOptions)'
+            AdditionalUsingDirectories:  ';%(AdditionalUsingDirectories)'
+            DisableSpecificWarnings: ';%(DisableSpecificWarnings)',
+            ForcedIncludeFiles:  ';%(ForcedIncludeFiles)',
+            ForcedUsingFiles:  ';%(ForcedUsingFiles)',
+            PreprocessorDefinitions:  ';%(PreprocessorDefinitions)',
+            UndefinePreprocessorDefinitions:
+                ';%(UndefinePreprocessorDefinitions)',
+        Link:
+            AdditionalDependencies:  ';%(AdditionalDependencies)',
+            AdditionalLibraryDirectories:  ';%(AdditionalLibraryDirectories)',
+            AdditionalManifestDependencies:
+                ';%(AdditionalManifestDependencies)',
+            AdditionalOptions:  ' %(AdditionalOptions)',
+            AddModuleNamesToAssembly:  ';%(AddModuleNamesToAssembly)',
+            AssemblyLinkResource:  ';%(AssemblyLinkResource)',
+            DelayLoadDLLs:  ';%(DelayLoadDLLs)',
+            EmbedManagedResourceFile:  ';%(EmbedManagedResourceFile)',
+            ForceSymbolReferences:  ';%(ForceSymbolReferences)',
+            IgnoreSpecificDefaultLibraries:
+                ';%(IgnoreSpecificDefaultLibraries)',
+        ResourceCompile:
+            AdditionalIncludeDirectories:  ';%(AdditionalIncludeDirectories)',
+            AdditionalOptions:  ' %(AdditionalOptions)',
+            PreprocessorDefinitions:  ';%(PreprocessorDefinitions)',
+        Manifest:
+            AdditionalManifestFiles:  ';%(AdditionalManifestFiles)',
+            AdditionalOptions:  ' %(AdditionalOptions)',
+            InputResourceManifests:  ';%(InputResourceManifests)',
+    """
+    msvs_settings = {
+        'VCCLCompilerTool': {
+            'AdditionalIncludeDirectories': 'dir1',
+            'AdditionalOptions': '/more',
+            'AdditionalUsingDirectories': 'test',
+            'AssemblerListingLocation': '$(IntDir)\\a',
+            'AssemblerOutput': '1',
+            'BasicRuntimeChecks': '3',
+            'BrowseInformation': '1',
+            'BrowseInformationFile': '$(IntDir)\\e',
+            'BufferSecurityCheck': 'false',
+            'CallingConvention': '1',
+            'CompileAs': '1',
+            'DebugInformationFormat': '4',
+            'DefaultCharIsUnsigned': 'true',
+            'Detect64BitPortabilityProblems': 'true',
+            'DisableLanguageExtensions': 'true',
+            'DisableSpecificWarnings': 'abc',
+            'EnableEnhancedInstructionSet': '1',
+            'EnableFiberSafeOptimizations': 'true',
+            'EnableFunctionLevelLinking': 'true',
+            'EnableIntrinsicFunctions': 'true',
+            'EnablePREfast': 'true',
+            'ErrorReporting': '2',
+            'ExceptionHandling': '2',
+            'ExpandAttributedSource': 'true',
+            'FavorSizeOrSpeed': '2',
+            'FloatingPointExceptions': 'true',
+            'FloatingPointModel': '1',
+            'ForceConformanceInForLoopScope': 'false',
+            'ForcedIncludeFiles': 'def',
+            'ForcedUsingFiles': 'ge',
+            'GeneratePreprocessedFile': '2',
+            'GenerateXMLDocumentationFiles': 'true',
+            'IgnoreStandardIncludePath': 'true',
+            'InlineFunctionExpansion': '1',
+            'KeepComments': 'true',
+            'MinimalRebuild': 'true',
+            'ObjectFile': '$(IntDir)\\b',
+            'OmitDefaultLibName': 'true',
+            'OmitFramePointers': 'true',
+            'OpenMP': 'true',
+            'Optimization': '3',
+            'PrecompiledHeaderFile': '$(IntDir)\\$(TargetName).pche',
+            'PrecompiledHeaderThrough': 'StdAfx.hd',
+            'PreprocessorDefinitions': 'WIN32;_DEBUG;_CONSOLE',
+            'ProgramDataBaseFileName': '$(IntDir)\\vc90b.pdb',
+            'RuntimeLibrary': '3',
+            'RuntimeTypeInfo': 'false',
+            'ShowIncludes': 'true',
+            'SmallerTypeCheck': 'true',
+            'StringPooling': 'true',
+            'StructMemberAlignment': '3',
+            'SuppressStartupBanner': 'false',
+            'TreatWChar_tAsBuiltInType': 'false',
+            'UndefineAllPreprocessorDefinitions': 'true',
+            'UndefinePreprocessorDefinitions': 'wer',
+            'UseFullPaths': 'true',
+            'UsePrecompiledHeader': '0',
+            'UseUnicodeResponseFiles': 'false',
+            'WarnAsError': 'true',
+            'WarningLevel': '3',
+            'WholeProgramOptimization': 'true',
+            'XMLDocumentationFileName': '$(IntDir)\\c'},
+        'VCLinkerTool': {
+            'AdditionalDependencies': 'zx',
+            'AdditionalLibraryDirectories': 'asd',
+            'AdditionalManifestDependencies': 's2',
+            'AdditionalOptions': '/mor2',
+            'AddModuleNamesToAssembly': 'd1',
+            'AllowIsolation': 'false',
+            'AssemblyDebug': '1',
+            'AssemblyLinkResource': 'd5',
+            'BaseAddress': '23423',
+            'CLRImageType': '3',
+            'CLRThreadAttribute': '1',
+            'CLRUnmanagedCodeCheck': 'true',
+            'DataExecutionPrevention': '0',
+            'DelayLoadDLLs': 'd4',
+            'DelaySign': 'true',
+            'Driver': '2',
+            'EmbedManagedResourceFile': 'd2',
+            'EnableCOMDATFolding': '1',
+            'EnableUAC': 'false',
+            'EntryPointSymbol': 'f5',
+            'ErrorReporting': '2',
+            'FixedBaseAddress': '1',
+            'ForceSymbolReferences': 'd3',
+            'FunctionOrder': 'fssdfsd',
+            'GenerateDebugInformation': 'true',
+            'GenerateManifest': 'false',
+            'GenerateMapFile': 'true',
+            'HeapCommitSize': '13',
+            'HeapReserveSize': '12',
+            'IgnoreAllDefaultLibraries': 'true',
+            'IgnoreDefaultLibraryNames': 'flob;flok',
+            'IgnoreEmbeddedIDL': 'true',
+            'IgnoreImportLibrary': 'true',
+            'ImportLibrary': 'f4',
+            'KeyContainer': 'f7',
+            'KeyFile': 'f6',
+            'LargeAddressAware': '2',
+            'LinkIncremental': '0',
+            'LinkLibraryDependencies': 'false',
+            'LinkTimeCodeGeneration': '1',
+            'ManifestFile':
+            '$(IntDir)\\$(TargetFileName).2intermediate.manifest',
+            'MapExports': 'true',
+            'MapFileName': 'd5',
+            'MergedIDLBaseFileName': 'f2',
+            'MergeSections': 'f5',
+            'MidlCommandFile': 'f1',
+            'ModuleDefinitionFile': 'sdsd',
+            'OptimizeForWindows98': '2',
+            'OptimizeReferences': '2',
+            'OutputFile': '$(OutDir)\\$(ProjectName)2.exe',
+            'PerUserRedirection': 'true',
+            'Profile': 'true',
+            'ProfileGuidedDatabase': '$(TargetDir)$(TargetName).pgdd',
+            'ProgramDatabaseFile': 'Flob.pdb',
+            'RandomizedBaseAddress': '1',
+            'RegisterOutput': 'true',
+            'ResourceOnlyDLL': 'true',
+            'SetChecksum': 'false',
+            'ShowProgress': '1',
+            'StackCommitSize': '15',
+            'StackReserveSize': '14',
+            'StripPrivateSymbols': 'd3',
+            'SubSystem': '1',
+            'SupportUnloadOfDelayLoadedDLL': 'true',
+            'SuppressStartupBanner': 'false',
+            'SwapRunFromCD': 'true',
+            'SwapRunFromNet': 'true',
+            'TargetMachine': '1',
+            'TerminalServerAware': '1',
+            'TurnOffAssemblyGeneration': 'true',
+            'TypeLibraryFile': 'f3',
+            'TypeLibraryResourceID': '12',
+            'UACExecutionLevel': '2',
+            'UACUIAccess': 'true',
+            'UseLibraryDependencyInputs': 'true',
+            'UseUnicodeResponseFiles': 'false',
+            'Version': '333'},
+        'VCResourceCompilerTool': {
+            'AdditionalIncludeDirectories': 'f3',
+            'AdditionalOptions': '/more3',
+            'Culture': '3084',
+            'IgnoreStandardIncludePath': 'true',
+            'PreprocessorDefinitions': '_UNICODE;UNICODE2',
+            'ResourceOutputFileName': '$(IntDir)/$(InputName)3.res',
+            'ShowProgress': 'true'},
+        'VCManifestTool': {
+            'AdditionalManifestFiles': 'sfsdfsd',
+            'AdditionalOptions': 'afdsdafsd',
+            'AssemblyIdentity': 'sddfdsadfsa',
+            'ComponentFileName': 'fsdfds',
+            'DependencyInformationFile': '$(IntDir)\\mt.depdfd',
+            'EmbedManifest': 'false',
+            'GenerateCatalogFiles': 'true',
+            'InputResourceManifests': 'asfsfdafs',
+            'ManifestResourceFile':
+            '$(IntDir)\\$(TargetFileName).embed.manifest.resfdsf',
+            'OutputManifestFile': '$(TargetPath).manifestdfs',
+            'RegistrarScriptFile': 'sdfsfd',
+            'ReplacementsFile': 'sdffsd',
+            'SuppressStartupBanner': 'false',
+            'TypeLibraryFile': 'sfsd',
+            'UpdateFileHashes': 'true',
+            'UpdateFileHashesSearchPath': 'sfsd',
+            'UseFAT32Workaround': 'true',
+            'UseUnicodeResponseFiles': 'false',
+            'VerboseOutput': 'true'}}
+    expected_msbuild_settings = {
+        'ClCompile': {
+            'AdditionalIncludeDirectories': 'dir1',
+            'AdditionalOptions': '/more /J',
+            'AdditionalUsingDirectories': 'test',
+            'AssemblerListingLocation': '$(IntDir)a',
+            'AssemblerOutput': 'AssemblyCode',
+            'BasicRuntimeChecks': 'EnableFastChecks',
+            'BrowseInformation': 'true',
+            'BrowseInformationFile': '$(IntDir)e',
+            'BufferSecurityCheck': 'false',
+            'CallingConvention': 'FastCall',
+            'CompileAs': 'CompileAsC',
+            'DebugInformationFormat': 'EditAndContinue',
+            'DisableLanguageExtensions': 'true',
+            'DisableSpecificWarnings': 'abc',
+            'EnableEnhancedInstructionSet': 'StreamingSIMDExtensions',
+            'EnableFiberSafeOptimizations': 'true',
+            'EnablePREfast': 'true',
+            'ErrorReporting': 'Queue',
+            'ExceptionHandling': 'Async',
+            'ExpandAttributedSource': 'true',
+            'FavorSizeOrSpeed': 'Size',
+            'FloatingPointExceptions': 'true',
+            'FloatingPointModel': 'Strict',
+            'ForceConformanceInForLoopScope': 'false',
+            'ForcedIncludeFiles': 'def',
+            'ForcedUsingFiles': 'ge',
+            'FunctionLevelLinking': 'true',
+            'GenerateXMLDocumentationFiles': 'true',
+            'IgnoreStandardIncludePath': 'true',
+            'InlineFunctionExpansion': 'OnlyExplicitInline',
+            'IntrinsicFunctions': 'true',
+            'MinimalRebuild': 'true',
+            'ObjectFileName': '$(IntDir)b',
+            'OmitDefaultLibName': 'true',
+            'OmitFramePointers': 'true',
+            'OpenMPSupport': 'true',
+            'Optimization': 'Full',
+            'PrecompiledHeader': 'NotUsing',  # Actual conversion gives ''
+            'PrecompiledHeaderFile': 'StdAfx.hd',
+            'PrecompiledHeaderOutputFile': '$(IntDir)$(TargetName).pche',
+            'PreprocessKeepComments': 'true',
+            'PreprocessorDefinitions': 'WIN32;_DEBUG;_CONSOLE',
+            'PreprocessSuppressLineNumbers': 'true',
+            'PreprocessToFile': 'true',
+            'ProgramDataBaseFileName': '$(IntDir)vc90b.pdb',
+            'RuntimeLibrary': 'MultiThreadedDebugDLL',
+            'RuntimeTypeInfo': 'false',
+            'ShowIncludes': 'true',
+            'SmallerTypeCheck': 'true',
+            'StringPooling': 'true',
+            'StructMemberAlignment': '4Bytes',
+            'SuppressStartupBanner': 'false',
+            'TreatWarningAsError': 'true',
+            'TreatWChar_tAsBuiltInType': 'false',
+            'UndefineAllPreprocessorDefinitions': 'true',
+            'UndefinePreprocessorDefinitions': 'wer',
+            'UseFullPaths': 'true',
+            'WarningLevel': 'Level3',
+            'WholeProgramOptimization': 'true',
+            'XMLDocumentationFileName': '$(IntDir)c'},
+        'Link': {
+            'AdditionalDependencies': 'zx',
+            'AdditionalLibraryDirectories': 'asd',
+            'AdditionalManifestDependencies': 's2',
+            'AdditionalOptions': '/mor2',
+            'AddModuleNamesToAssembly': 'd1',
+            'AllowIsolation': 'false',
+            'AssemblyDebug': 'true',
+            'AssemblyLinkResource': 'd5',
+            'BaseAddress': '23423',
+            'CLRImageType': 'ForceSafeILImage',
+            'CLRThreadAttribute': 'MTAThreadingAttribute',
+            'CLRUnmanagedCodeCheck': 'true',
+            'DataExecutionPrevention': '',
+            'DelayLoadDLLs': 'd4',
+            'DelaySign': 'true',
+            'Driver': 'UpOnly',
+            'EmbedManagedResourceFile': 'd2',
+            'EnableCOMDATFolding': 'false',
+            'EnableUAC': 'false',
+            'EntryPointSymbol': 'f5',
+            'FixedBaseAddress': 'false',
+            'ForceSymbolReferences': 'd3',
+            'FunctionOrder': 'fssdfsd',
+            'GenerateDebugInformation': 'true',
+            'GenerateMapFile': 'true',
+            'HeapCommitSize': '13',
+            'HeapReserveSize': '12',
+            'IgnoreAllDefaultLibraries': 'true',
+            'IgnoreEmbeddedIDL': 'true',
+            'IgnoreSpecificDefaultLibraries': 'flob;flok',
+            'ImportLibrary': 'f4',
+            'KeyContainer': 'f7',
+            'KeyFile': 'f6',
+            'LargeAddressAware': 'true',
+            'LinkErrorReporting': 'QueueForNextLogin',
+            'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration',
+            'ManifestFile': '$(IntDir)$(TargetFileName).2intermediate.manifest',
+            'MapExports': 'true',
+            'MapFileName': 'd5',
+            'MergedIDLBaseFileName': 'f2',
+            'MergeSections': 'f5',
+            'MidlCommandFile': 'f1',
+            'ModuleDefinitionFile': 'sdsd',
+            'NoEntryPoint': 'true',
+            'OptimizeReferences': 'true',
+            'OutputFile': '$(OutDir)$(ProjectName)2.exe',
+            'PerUserRedirection': 'true',
+            'Profile': 'true',
+            'ProfileGuidedDatabase': '$(TargetDir)$(TargetName).pgdd',
+            'ProgramDatabaseFile': 'Flob.pdb',
+            'RandomizedBaseAddress': 'false',
+            'RegisterOutput': 'true',
+            'SetChecksum': 'false',
+            'ShowProgress': 'LinkVerbose',
+            'StackCommitSize': '15',
+            'StackReserveSize': '14',
+            'StripPrivateSymbols': 'd3',
+            'SubSystem': 'Console',
+            'SupportUnloadOfDelayLoadedDLL': 'true',
+            'SuppressStartupBanner': 'false',
+            'SwapRunFromCD': 'true',
+            'SwapRunFromNET': 'true',
+            'TargetMachine': 'MachineX86',
+            'TerminalServerAware': 'false',
+            'TurnOffAssemblyGeneration': 'true',
+            'TypeLibraryFile': 'f3',
+            'TypeLibraryResourceID': '12',
+            'UACExecutionLevel': 'RequireAdministrator',
+            'UACUIAccess': 'true',
+            'Version': '333'},
+        'ResourceCompile': {
+            'AdditionalIncludeDirectories': 'f3',
+            'AdditionalOptions': '/more3',
+            'Culture': '0x0c0c',
+            'IgnoreStandardIncludePath': 'true',
+            'PreprocessorDefinitions': '_UNICODE;UNICODE2',
+            'ResourceOutputFileName': '$(IntDir)%(Filename)3.res',
+            'ShowProgress': 'true'},
+        'Manifest': {
+            'AdditionalManifestFiles': 'sfsdfsd',
+            'AdditionalOptions': 'afdsdafsd',
+            'AssemblyIdentity': 'sddfdsadfsa',
+            'ComponentFileName': 'fsdfds',
+            'GenerateCatalogFiles': 'true',
+            'InputResourceManifests': 'asfsfdafs',
+            'OutputManifestFile': '$(TargetPath).manifestdfs',
+            'RegistrarScriptFile': 'sdfsfd',
+            'ReplacementsFile': 'sdffsd',
+            'SuppressStartupBanner': 'false',
+            'TypeLibraryFile': 'sfsd',
+            'UpdateFileHashes': 'true',
+            'UpdateFileHashesSearchPath': 'sfsd',
+            'VerboseOutput': 'true'},
+        'ProjectReference': {
+            'LinkLibraryDependencies': 'false',
+            'UseLibraryDependencyInputs': 'true'},
+        '': {
+            'EmbedManifest': 'false',
+            'GenerateManifest': 'false',
+            'IgnoreImportLibrary': 'true',
+            'LinkIncremental': ''
+            },
+        'ManifestResourceCompile': {
+            'ResourceOutputFileName':
+            '$(IntDir)$(TargetFileName).embed.manifest.resfdsf'}
+        }
+    actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings(
+        msvs_settings,
+        self.stderr)
+    self.assertEqual(expected_msbuild_settings, actual_msbuild_settings)
+    self._ExpectedWarnings([])
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/gyp/pylib/gyp/MSVSToolFile.py b/gyp/pylib/gyp/MSVSToolFile.py
new file mode 100644 (file)
index 0000000..74e529a
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Visual Studio project reader/writer."""
+
+import gyp.common
+import gyp.easy_xml as easy_xml
+
+
+class Writer(object):
+  """Visual Studio XML tool file writer."""
+
+  def __init__(self, tool_file_path, name):
+    """Initializes the tool file.
+
+    Args:
+      tool_file_path: Path to the tool file.
+      name: Name of the tool file.
+    """
+    self.tool_file_path = tool_file_path
+    self.name = name
+    self.rules_section = ['Rules']
+
+  def AddCustomBuildRule(self, name, cmd, description,
+                         additional_dependencies,
+                         outputs, extensions):
+    """Adds a rule to the tool file.
+
+    Args:
+      name: Name of the rule.
+      description: Description of the rule.
+      cmd: Command line of the rule.
+      additional_dependencies: other files which may trigger the rule.
+      outputs: outputs of the rule.
+      extensions: extensions handled by the rule.
+    """
+    rule = ['CustomBuildRule',
+            {'Name': name,
+             'ExecutionDescription': description,
+             'CommandLine': cmd,
+             'Outputs': ';'.join(outputs),
+             'FileExtensions': ';'.join(extensions),
+             'AdditionalDependencies':
+                 ';'.join(additional_dependencies)
+            }]
+    self.rules_section.append(rule)
+
+  def WriteIfChanged(self):
+    """Writes the tool file."""
+    content = ['VisualStudioToolFile',
+               {'Version': '8.00',
+                'Name': self.name
+               },
+               self.rules_section
+               ]
+    easy_xml.WriteXmlIfChanged(content, self.tool_file_path,
+                               encoding="Windows-1252")
diff --git a/gyp/pylib/gyp/MSVSUserFile.py b/gyp/pylib/gyp/MSVSUserFile.py
new file mode 100644 (file)
index 0000000..6c07e9a
--- /dev/null
@@ -0,0 +1,147 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Visual Studio user preferences file writer."""
+
+import os
+import re
+import socket # for gethostname
+
+import gyp.common
+import gyp.easy_xml as easy_xml
+
+
+#------------------------------------------------------------------------------
+
+def _FindCommandInPath(command):
+  """If there are no slashes in the command given, this function
+     searches the PATH env to find the given command, and converts it
+     to an absolute path.  We have to do this because MSVS is looking
+     for an actual file to launch a debugger on, not just a command
+     line.  Note that this happens at GYP time, so anything needing to
+     be built needs to have a full path."""
+  if '/' in command or '\\' in command:
+    # If the command already has path elements (either relative or
+    # absolute), then assume it is constructed properly.
+    return command
+  else:
+    # Search through the path list and find an existing file that
+    # we can access.
+    paths = os.environ.get('PATH','').split(os.pathsep)
+    for path in paths:
+      item = os.path.join(path, command)
+      if os.path.isfile(item) and os.access(item, os.X_OK):
+        return item
+  return command
+
+def _QuoteWin32CommandLineArgs(args):
+  new_args = []
+  for arg in args:
+    # Replace all double-quotes with double-double-quotes to escape
+    # them for cmd shell, and then quote the whole thing if there
+    # are any.
+    if arg.find('"') != -1:
+      arg = '""'.join(arg.split('"'))
+      arg = '"%s"' % arg
+
+    # Otherwise, if there are any spaces, quote the whole arg.
+    elif re.search(r'[ \t\n]', arg):
+      arg = '"%s"' % arg
+    new_args.append(arg)
+  return new_args
+
+class Writer(object):
+  """Visual Studio XML user user file writer."""
+
+  def __init__(self, user_file_path, version, name):
+    """Initializes the user file.
+
+    Args:
+      user_file_path: Path to the user file.
+      version: Version info.
+      name: Name of the user file.
+    """
+    self.user_file_path = user_file_path
+    self.version = version
+    self.name = name
+    self.configurations = {}
+
+  def AddConfig(self, name):
+    """Adds a configuration to the project.
+
+    Args:
+      name: Configuration name.
+    """
+    self.configurations[name] = ['Configuration', {'Name': name}]
+
+  def AddDebugSettings(self, config_name, command, environment = {},
+                       working_directory=""):
+    """Adds a DebugSettings node to the user file for a particular config.
+
+    Args:
+      command: command line to run.  First element in the list is the
+        executable.  All elements of the command will be quoted if
+        necessary.
+      working_directory: other files which may trigger the rule. (optional)
+    """
+    command = _QuoteWin32CommandLineArgs(command)
+
+    abs_command = _FindCommandInPath(command[0])
+
+    if environment and isinstance(environment, dict):
+      env_list = ['%s="%s"' % (key, val)
+                  for (key,val) in environment.iteritems()]
+      environment = ' '.join(env_list)
+    else:
+      environment = ''
+
+    n_cmd = ['DebugSettings',
+             {'Command': abs_command,
+              'WorkingDirectory': working_directory,
+              'CommandArguments': " ".join(command[1:]),
+              'RemoteMachine': socket.gethostname(),
+              'Environment': environment,
+              'EnvironmentMerge': 'true',
+              # Currently these are all "dummy" values that we're just setting
+              # in the default manner that MSVS does it.  We could use some of
+              # these to add additional capabilities, I suppose, but they might
+              # not have parity with other platforms then.
+              'Attach': 'false',
+              'DebuggerType': '3',  # 'auto' debugger
+              'Remote': '1',
+              'RemoteCommand': '',
+              'HttpUrl': '',
+              'PDBPath': '',
+              'SQLDebugging': '',
+              'DebuggerFlavor': '0',
+              'MPIRunCommand': '',
+              'MPIRunArguments': '',
+              'MPIRunWorkingDirectory': '',
+              'ApplicationCommand': '',
+              'ApplicationArguments': '',
+              'ShimCommand': '',
+              'MPIAcceptMode': '',
+              'MPIAcceptFilter': ''
+             }]
+
+    # Find the config, and add it if it doesn't exist.
+    if config_name not in self.configurations:
+      self.AddConfig(config_name)
+
+    # Add the DebugSettings onto the appropriate config.
+    self.configurations[config_name].append(n_cmd)
+
+  def WriteIfChanged(self):
+    """Writes the user file."""
+    configs = ['Configurations']
+    for config, spec in sorted(self.configurations.iteritems()):
+      configs.append(spec)
+
+    content = ['VisualStudioUserFile',
+               {'Version': self.version.ProjectVersion(),
+                'Name': self.name
+               },
+               configs]
+    easy_xml.WriteXmlIfChanged(content, self.user_file_path,
+                               encoding="Windows-1252")
diff --git a/gyp/pylib/gyp/MSVSUtil.py b/gyp/pylib/gyp/MSVSUtil.py
new file mode 100644 (file)
index 0000000..fbf3ed2
--- /dev/null
@@ -0,0 +1,268 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Utility functions shared amongst the Windows generators."""
+
+import copy
+import os
+
+
+_TARGET_TYPE_EXT = {
+  'executable': '.exe',
+  'loadable_module': '.dll',
+  'shared_library': '.dll',
+}
+
+
+def _GetLargePdbShimCcPath():
+  """Returns the path of the large_pdb_shim.cc file."""
+  this_dir = os.path.abspath(os.path.dirname(__file__))
+  src_dir = os.path.abspath(os.path.join(this_dir, '..', '..'))
+  win_data_dir = os.path.join(src_dir, 'data', 'win')
+  large_pdb_shim_cc = os.path.join(win_data_dir, 'large-pdb-shim.cc')
+  return large_pdb_shim_cc
+
+
+def _DeepCopySomeKeys(in_dict, keys):
+  """Performs a partial deep-copy on |in_dict|, only copying the keys in |keys|.
+
+  Arguments:
+    in_dict: The dictionary to copy.
+    keys: The keys to be copied. If a key is in this list and doesn't exist in
+        |in_dict| this is not an error.
+  Returns:
+    The partially deep-copied dictionary.
+  """
+  d = {}
+  for key in keys:
+    if key not in in_dict:
+      continue
+    d[key] = copy.deepcopy(in_dict[key])
+  return d
+
+
+def _SuffixName(name, suffix):
+  """Add a suffix to the end of a target.
+
+  Arguments:
+    name: name of the target (foo#target)
+    suffix: the suffix to be added
+  Returns:
+    Target name with suffix added (foo_suffix#target)
+  """
+  parts = name.rsplit('#', 1)
+  parts[0] = '%s_%s' % (parts[0], suffix)
+  return '#'.join(parts)
+
+
+def _ShardName(name, number):
+  """Add a shard number to the end of a target.
+
+  Arguments:
+    name: name of the target (foo#target)
+    number: shard number
+  Returns:
+    Target name with shard added (foo_1#target)
+  """
+  return _SuffixName(name, str(number))
+
+
+def ShardTargets(target_list, target_dicts):
+  """Shard some targets apart to work around the linkers limits.
+
+  Arguments:
+    target_list: List of target pairs: 'base/base.gyp:base'.
+    target_dicts: Dict of target properties keyed on target pair.
+  Returns:
+    Tuple of the new sharded versions of the inputs.
+  """
+  # Gather the targets to shard, and how many pieces.
+  targets_to_shard = {}
+  for t in target_dicts:
+    shards = int(target_dicts[t].get('msvs_shard', 0))
+    if shards:
+      targets_to_shard[t] = shards
+  # Shard target_list.
+  new_target_list = []
+  for t in target_list:
+    if t in targets_to_shard:
+      for i in range(targets_to_shard[t]):
+        new_target_list.append(_ShardName(t, i))
+    else:
+      new_target_list.append(t)
+  # Shard target_dict.
+  new_target_dicts = {}
+  for t in target_dicts:
+    if t in targets_to_shard:
+      for i in range(targets_to_shard[t]):
+        name = _ShardName(t, i)
+        new_target_dicts[name] = copy.copy(target_dicts[t])
+        new_target_dicts[name]['target_name'] = _ShardName(
+             new_target_dicts[name]['target_name'], i)
+        sources = new_target_dicts[name].get('sources', [])
+        new_sources = []
+        for pos in range(i, len(sources), targets_to_shard[t]):
+          new_sources.append(sources[pos])
+        new_target_dicts[name]['sources'] = new_sources
+    else:
+      new_target_dicts[t] = target_dicts[t]
+  # Shard dependencies.
+  for t in new_target_dicts:
+    for deptype in ('dependencies', 'dependencies_original'):
+      dependencies = copy.copy(new_target_dicts[t].get(deptype, []))
+      new_dependencies = []
+      for d in dependencies:
+        if d in targets_to_shard:
+          for i in range(targets_to_shard[d]):
+            new_dependencies.append(_ShardName(d, i))
+        else:
+          new_dependencies.append(d)
+      new_target_dicts[t][deptype] = new_dependencies
+
+  return (new_target_list, new_target_dicts)
+
+
+def _GetPdbPath(target_dict, config_name, vars):
+  """Returns the path to the PDB file that will be generated by a given
+  configuration.
+
+  The lookup proceeds as follows:
+    - Look for an explicit path in the VCLinkerTool configuration block.
+    - Look for an 'msvs_large_pdb_path' variable.
+    - Use '<(PRODUCT_DIR)/<(product_name).(exe|dll).pdb' if 'product_name' is
+      specified.
+    - Use '<(PRODUCT_DIR)/<(target_name).(exe|dll).pdb'.
+
+  Arguments:
+    target_dict: The target dictionary to be searched.
+    config_name: The name of the configuration of interest.
+    vars: A dictionary of common GYP variables with generator-specific values.
+  Returns:
+    The path of the corresponding PDB file.
+  """
+  config = target_dict['configurations'][config_name]
+  msvs = config.setdefault('msvs_settings', {})
+
+  linker = msvs.get('VCLinkerTool', {})
+
+  pdb_path = linker.get('ProgramDatabaseFile')
+  if pdb_path:
+    return pdb_path
+
+  variables = target_dict.get('variables', {})
+  pdb_path = variables.get('msvs_large_pdb_path', None)
+  if pdb_path:
+    return pdb_path
+
+
+  pdb_base = target_dict.get('product_name', target_dict['target_name'])
+  pdb_base = '%s%s.pdb' % (pdb_base, _TARGET_TYPE_EXT[target_dict['type']])
+  pdb_path = vars['PRODUCT_DIR'] + '/' + pdb_base
+
+  return pdb_path
+
+
+def InsertLargePdbShims(target_list, target_dicts, vars):
+  """Insert a shim target that forces the linker to use 4KB pagesize PDBs.
+
+  This is a workaround for targets with PDBs greater than 1GB in size, the
+  limit for the 1KB pagesize PDBs created by the linker by default.
+
+  Arguments:
+    target_list: List of target pairs: 'base/base.gyp:base'.
+    target_dicts: Dict of target properties keyed on target pair.
+    vars: A dictionary of common GYP variables with generator-specific values.
+  Returns:
+    Tuple of the shimmed version of the inputs.
+  """
+  # Determine which targets need shimming.
+  targets_to_shim = []
+  for t in target_dicts:
+    target_dict = target_dicts[t]
+
+    # We only want to shim targets that have msvs_large_pdb enabled.
+    if not int(target_dict.get('msvs_large_pdb', 0)):
+      continue
+    # This is intended for executable, shared_library and loadable_module
+    # targets where every configuration is set up to produce a PDB output.
+    # If any of these conditions is not true then the shim logic will fail
+    # below.
+    targets_to_shim.append(t)
+
+  large_pdb_shim_cc = _GetLargePdbShimCcPath()
+
+  for t in targets_to_shim:
+    target_dict = target_dicts[t]
+    target_name = target_dict.get('target_name')
+
+    base_dict = _DeepCopySomeKeys(target_dict,
+          ['configurations', 'default_configuration', 'toolset'])
+
+    # This is the dict for copying the source file (part of the GYP tree)
+    # to the intermediate directory of the project. This is necessary because
+    # we can't always build a relative path to the shim source file (on Windows
+    # GYP and the project may be on different drives), and Ninja hates absolute
+    # paths (it ends up generating the .obj and .obj.d alongside the source
+    # file, polluting GYPs tree).
+    copy_suffix = 'large_pdb_copy'
+    copy_target_name = target_name + '_' + copy_suffix
+    full_copy_target_name = _SuffixName(t, copy_suffix)
+    shim_cc_basename = os.path.basename(large_pdb_shim_cc)
+    shim_cc_dir = vars['SHARED_INTERMEDIATE_DIR'] + '/' + copy_target_name
+    shim_cc_path = shim_cc_dir + '/' + shim_cc_basename
+    copy_dict = copy.deepcopy(base_dict)
+    copy_dict['target_name'] = copy_target_name
+    copy_dict['type'] = 'none'
+    copy_dict['sources'] = [ large_pdb_shim_cc ]
+    copy_dict['copies'] = [{
+      'destination': shim_cc_dir,
+      'files': [ large_pdb_shim_cc ]
+    }]
+
+    # This is the dict for the PDB generating shim target. It depends on the
+    # copy target.
+    shim_suffix = 'large_pdb_shim'
+    shim_target_name = target_name + '_' + shim_suffix
+    full_shim_target_name = _SuffixName(t, shim_suffix)
+    shim_dict = copy.deepcopy(base_dict)
+    shim_dict['target_name'] = shim_target_name
+    shim_dict['type'] = 'static_library'
+    shim_dict['sources'] = [ shim_cc_path ]
+    shim_dict['dependencies'] = [ full_copy_target_name ]
+
+    # Set up the shim to output its PDB to the same location as the final linker
+    # target.
+    for config_name, config in shim_dict.get('configurations').iteritems():
+      pdb_path = _GetPdbPath(target_dict, config_name, vars)
+
+      # A few keys that we don't want to propagate.
+      for key in ['msvs_precompiled_header', 'msvs_precompiled_source', 'test']:
+        config.pop(key, None)
+
+      msvs = config.setdefault('msvs_settings', {})
+
+      # Update the compiler directives in the shim target.
+      compiler = msvs.setdefault('VCCLCompilerTool', {})
+      compiler['DebugInformationFormat'] = '3'
+      compiler['ProgramDataBaseFileName'] = pdb_path
+
+      # Set the explicit PDB path in the appropriate configuration of the
+      # original target.
+      config = target_dict['configurations'][config_name]
+      msvs = config.setdefault('msvs_settings', {})
+      linker = msvs.setdefault('VCLinkerTool', {})
+      linker['GenerateDebugInformation'] = 'true'
+      linker['ProgramDatabaseFile'] = pdb_path
+
+    # Add the new targets. They must go to the beginning of the list so that
+    # the dependency generation works as expected in ninja.
+    target_list.insert(0, full_copy_target_name)
+    target_list.insert(0, full_shim_target_name)
+    target_dicts[full_copy_target_name] = copy_dict
+    target_dicts[full_shim_target_name] = shim_dict
+
+    # Update the original target to depend on the shim target.
+    target_dict.setdefault('dependencies', []).append(full_shim_target_name)
+
+  return (target_list, target_dicts)
diff --git a/gyp/pylib/gyp/MSVSVersion.py b/gyp/pylib/gyp/MSVSVersion.py
new file mode 100644 (file)
index 0000000..bcd6122
--- /dev/null
@@ -0,0 +1,409 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Handle version information related to Visual Stuio."""
+
+import errno
+import os
+import re
+import subprocess
+import sys
+import gyp
+import glob
+
+
+class VisualStudioVersion(object):
+  """Information regarding a version of Visual Studio."""
+
+  def __init__(self, short_name, description,
+               solution_version, project_version, flat_sln, uses_vcxproj,
+               path, sdk_based, default_toolset=None):
+    self.short_name = short_name
+    self.description = description
+    self.solution_version = solution_version
+    self.project_version = project_version
+    self.flat_sln = flat_sln
+    self.uses_vcxproj = uses_vcxproj
+    self.path = path
+    self.sdk_based = sdk_based
+    self.default_toolset = default_toolset
+
+  def ShortName(self):
+    return self.short_name
+
+  def Description(self):
+    """Get the full description of the version."""
+    return self.description
+
+  def SolutionVersion(self):
+    """Get the version number of the sln files."""
+    return self.solution_version
+
+  def ProjectVersion(self):
+    """Get the version number of the vcproj or vcxproj files."""
+    return self.project_version
+
+  def FlatSolution(self):
+    return self.flat_sln
+
+  def UsesVcxproj(self):
+    """Returns true if this version uses a vcxproj file."""
+    return self.uses_vcxproj
+
+  def ProjectExtension(self):
+    """Returns the file extension for the project."""
+    return self.uses_vcxproj and '.vcxproj' or '.vcproj'
+
+  def Path(self):
+    """Returns the path to Visual Studio installation."""
+    return self.path
+
+  def ToolPath(self, tool):
+    """Returns the path to a given compiler tool. """
+    return os.path.normpath(os.path.join(self.path, "VC/bin", tool))
+
+  def DefaultToolset(self):
+    """Returns the msbuild toolset version that will be used in the absence
+    of a user override."""
+    return self.default_toolset
+
+  def SetupScript(self, target_arch):
+    """Returns a command (with arguments) to be used to set up the
+    environment."""
+    # Check if we are running in the SDK command line environment and use
+    # the setup script from the SDK if so. |target_arch| should be either
+    # 'x86' or 'x64'.
+    assert target_arch in ('x86', 'x64')
+    sdk_dir = os.environ.get('WindowsSDKDir')
+    if self.sdk_based and sdk_dir:
+      return [os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd')),
+              '/' + target_arch]
+    else:
+      # We don't use VC/vcvarsall.bat for x86 because vcvarsall calls
+      # vcvars32, which it can only find if VS??COMNTOOLS is set, which it
+      # isn't always.
+      if target_arch == 'x86':
+        if self.short_name == '2013' and (
+            os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or
+            os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'):
+          # VS2013 non-Express has a x64-x86 cross that we want to prefer.
+          return [os.path.normpath(
+             os.path.join(self.path, 'VC/vcvarsall.bat')), 'amd64_x86']
+        # Otherwise, the standard x86 compiler.
+        return [os.path.normpath(
+          os.path.join(self.path, 'Common7/Tools/vsvars32.bat'))]
+      else:
+        assert target_arch == 'x64'
+        arg = 'x86_amd64'
+        # Use the 64-on-64 compiler if we're not using an express
+        # edition and we're running on a 64bit OS.
+        if self.short_name[-1] != 'e' and (
+            os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or
+            os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'):
+          arg = 'amd64'
+        return [os.path.normpath(
+            os.path.join(self.path, 'VC/vcvarsall.bat')), arg]
+
+
+def _RegistryQueryBase(sysdir, key, value):
+  """Use reg.exe to read a particular key.
+
+  While ideally we might use the win32 module, we would like gyp to be
+  python neutral, so for instance cygwin python lacks this module.
+
+  Arguments:
+    sysdir: The system subdirectory to attempt to launch reg.exe from.
+    key: The registry key to read from.
+    value: The particular value to read.
+  Return:
+    stdout from reg.exe, or None for failure.
+  """
+  # Skip if not on Windows or Python Win32 setup issue
+  if sys.platform not in ('win32', 'cygwin'):
+    return None
+  # Setup params to pass to and attempt to launch reg.exe
+  cmd = [os.path.join(os.environ.get('WINDIR', ''), sysdir, 'reg.exe'),
+         'query', key]
+  if value:
+    cmd.extend(['/v', value])
+  p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+  # Obtain the stdout from reg.exe, reading to the end so p.returncode is valid
+  # Note that the error text may be in [1] in some cases
+  text = p.communicate()[0]
+  # Check return code from reg.exe; officially 0==success and 1==error
+  if p.returncode:
+    return None
+  return text
+
+
+def _RegistryQuery(key, value=None):
+  """Use reg.exe to read a particular key through _RegistryQueryBase.
+
+  First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If
+  that fails, it falls back to System32.  Sysnative is available on Vista and
+  up and available on Windows Server 2003 and XP through KB patch 942589. Note
+  that Sysnative will always fail if using 64-bit python due to it being a
+  virtual directory and System32 will work correctly in the first place.
+
+  KB 942589 - http://support.microsoft.com/kb/942589/en-us.
+
+  Arguments:
+    key: The registry key.
+    value: The particular registry value to read (optional).
+  Return:
+    stdout from reg.exe, or None for failure.
+  """
+  text = None
+  try:
+    text = _RegistryQueryBase('Sysnative', key, value)
+  except OSError, e:
+    if e.errno == errno.ENOENT:
+      text = _RegistryQueryBase('System32', key, value)
+    else:
+      raise
+  return text
+
+
+def _RegistryGetValue(key, value):
+  """Use reg.exe to obtain the value of a registry key.
+
+  Args:
+    key: The registry key.
+    value: The particular registry value to read.
+  Return:
+    contents of the registry key's value, or None on failure.
+  """
+  text = _RegistryQuery(key, value)
+  if not text:
+    return None
+  # Extract value.
+  match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text)
+  if not match:
+    return None
+  return match.group(1)
+
+
+def _RegistryKeyExists(key):
+  """Use reg.exe to see if a key exists.
+
+  Args:
+    key: The registry key to check.
+  Return:
+    True if the key exists
+  """
+  if not _RegistryQuery(key):
+    return False
+  return True
+
+
+def _CreateVersion(name, path, sdk_based=False):
+  """Sets up MSVS project generation.
+
+  Setup is based off the GYP_MSVS_VERSION environment variable or whatever is
+  autodetected if GYP_MSVS_VERSION is not explicitly specified. If a version is
+  passed in that doesn't match a value in versions python will throw a error.
+  """
+  if path:
+    path = os.path.normpath(path)
+  versions = {
+      '2013': VisualStudioVersion('2013',
+                                  'Visual Studio 2013',
+                                  solution_version='13.00',
+                                  project_version='12.0',
+                                  flat_sln=False,
+                                  uses_vcxproj=True,
+                                  path=path,
+                                  sdk_based=sdk_based,
+                                  default_toolset='v120'),
+      '2013e': VisualStudioVersion('2013e',
+                                   'Visual Studio 2013',
+                                   solution_version='13.00',
+                                   project_version='12.0',
+                                   flat_sln=True,
+                                   uses_vcxproj=True,
+                                   path=path,
+                                   sdk_based=sdk_based,
+                                   default_toolset='v120'),
+      '2012': VisualStudioVersion('2012',
+                                  'Visual Studio 2012',
+                                  solution_version='12.00',
+                                  project_version='4.0',
+                                  flat_sln=False,
+                                  uses_vcxproj=True,
+                                  path=path,
+                                  sdk_based=sdk_based,
+                                  default_toolset='v110'),
+      '2012e': VisualStudioVersion('2012e',
+                                   'Visual Studio 2012',
+                                   solution_version='12.00',
+                                   project_version='4.0',
+                                   flat_sln=True,
+                                   uses_vcxproj=True,
+                                   path=path,
+                                   sdk_based=sdk_based,
+                                   default_toolset='v110'),
+      '2010': VisualStudioVersion('2010',
+                                  'Visual Studio 2010',
+                                  solution_version='11.00',
+                                  project_version='4.0',
+                                  flat_sln=False,
+                                  uses_vcxproj=True,
+                                  path=path,
+                                  sdk_based=sdk_based),
+      '2010e': VisualStudioVersion('2010e',
+                                   'Visual C++ Express 2010',
+                                   solution_version='11.00',
+                                   project_version='4.0',
+                                   flat_sln=True,
+                                   uses_vcxproj=True,
+                                   path=path,
+                                   sdk_based=sdk_based),
+      '2008': VisualStudioVersion('2008',
+                                  'Visual Studio 2008',
+                                  solution_version='10.00',
+                                  project_version='9.00',
+                                  flat_sln=False,
+                                  uses_vcxproj=False,
+                                  path=path,
+                                  sdk_based=sdk_based),
+      '2008e': VisualStudioVersion('2008e',
+                                   'Visual Studio 2008',
+                                   solution_version='10.00',
+                                   project_version='9.00',
+                                   flat_sln=True,
+                                   uses_vcxproj=False,
+                                   path=path,
+                                   sdk_based=sdk_based),
+      '2005': VisualStudioVersion('2005',
+                                  'Visual Studio 2005',
+                                  solution_version='9.00',
+                                  project_version='8.00',
+                                  flat_sln=False,
+                                  uses_vcxproj=False,
+                                  path=path,
+                                  sdk_based=sdk_based),
+      '2005e': VisualStudioVersion('2005e',
+                                   'Visual Studio 2005',
+                                   solution_version='9.00',
+                                   project_version='8.00',
+                                   flat_sln=True,
+                                   uses_vcxproj=False,
+                                   path=path,
+                                   sdk_based=sdk_based),
+  }
+  return versions[str(name)]
+
+
+def _ConvertToCygpath(path):
+  """Convert to cygwin path if we are using cygwin."""
+  if sys.platform == 'cygwin':
+    p = subprocess.Popen(['cygpath', path], stdout=subprocess.PIPE)
+    path = p.communicate()[0].strip()
+  return path
+
+
+def _DetectVisualStudioVersions(versions_to_check, force_express):
+  """Collect the list of installed visual studio versions.
+
+  Returns:
+    A list of visual studio versions installed in descending order of
+    usage preference.
+    Base this on the registry and a quick check if devenv.exe exists.
+    Only versions 8-10 are considered.
+    Possibilities are:
+      2005(e) - Visual Studio 2005 (8)
+      2008(e) - Visual Studio 2008 (9)
+      2010(e) - Visual Studio 2010 (10)
+      2012(e) - Visual Studio 2012 (11)
+      2013(e) - Visual Studio 2013 (11)
+    Where (e) is e for express editions of MSVS and blank otherwise.
+  """
+  version_to_year = {
+      '8.0': '2005',
+      '9.0': '2008',
+      '10.0': '2010',
+      '11.0': '2012',
+      '12.0': '2013',
+  }
+  versions = []
+  for version in versions_to_check:
+    # Old method of searching for which VS version is installed
+    # We don't use the 2010-encouraged-way because we also want to get the
+    # path to the binaries, which it doesn't offer.
+    keys = [r'HKLM\Software\Microsoft\VisualStudio\%s' % version,
+            r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version,
+            r'HKLM\Software\Microsoft\VCExpress\%s' % version,
+            r'HKLM\Software\Wow6432Node\Microsoft\VCExpress\%s' % version]
+    for index in range(len(keys)):
+      path = _RegistryGetValue(keys[index], 'InstallDir')
+      if not path:
+        continue
+      path = _ConvertToCygpath(path)
+      # Check for full.
+      full_path = os.path.join(path, 'devenv.exe')
+      express_path = os.path.join(path, '*express.exe')
+      if not force_express and os.path.exists(full_path):
+        # Add this one.
+        versions.append(_CreateVersion(version_to_year[version],
+            os.path.join(path, '..', '..')))
+      # Check for express.
+      elif glob.glob(express_path):
+        # Add this one.
+        versions.append(_CreateVersion(version_to_year[version] + 'e',
+            os.path.join(path, '..', '..')))
+
+    # The old method above does not work when only SDK is installed.
+    keys = [r'HKLM\Software\Microsoft\VisualStudio\SxS\VC7',
+            r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VC7']
+    for index in range(len(keys)):
+      path = _RegistryGetValue(keys[index], version)
+      if not path:
+        continue
+      path = _ConvertToCygpath(path)
+      versions.append(_CreateVersion(version_to_year[version] + 'e',
+          os.path.join(path, '..'), sdk_based=True))
+
+  return versions
+
+
+def SelectVisualStudioVersion(version='auto'):
+  """Select which version of Visual Studio projects to generate.
+
+  Arguments:
+    version: Hook to allow caller to force a particular version (vs auto).
+  Returns:
+    An object representing a visual studio project format version.
+  """
+  # In auto mode, check environment variable for override.
+  if version == 'auto':
+    version = os.environ.get('GYP_MSVS_VERSION', 'auto')
+  version_map = {
+    'auto': ('12.0', '10.0', '9.0', '8.0', '11.0'),
+    '2005': ('8.0',),
+    '2005e': ('8.0',),
+    '2008': ('9.0',),
+    '2008e': ('9.0',),
+    '2010': ('10.0',),
+    '2010e': ('10.0',),
+    '2012': ('11.0',),
+    '2012e': ('11.0',),
+    '2013': ('12.0',),
+    '2013e': ('12.0',),
+  }
+  override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH')
+  if override_path:
+    msvs_version = os.environ.get('GYP_MSVS_VERSION')
+    if not msvs_version:
+      raise ValueError('GYP_MSVS_OVERRIDE_PATH requires GYP_MSVS_VERSION to be '
+                       'set to a particular version (e.g. 2010e).')
+    return _CreateVersion(msvs_version, override_path, sdk_based=True)
+  version = str(version)
+  versions = _DetectVisualStudioVersions(version_map[version], 'e' in version)
+  if not versions:
+    if version == 'auto':
+      # Default to 2005 if we couldn't find anything
+      return _CreateVersion('2005', None)
+    else:
+      return _CreateVersion(version, None)
+  return versions[0]
diff --git a/gyp/pylib/gyp/__init__.py b/gyp/pylib/gyp/__init__.py
new file mode 100755 (executable)
index 0000000..1cd57b0
--- /dev/null
@@ -0,0 +1,547 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import copy
+import gyp.input
+import optparse
+import os.path
+import re
+import shlex
+import sys
+import traceback
+from gyp.common import GypError
+
+# Default debug modes for GYP
+debug = {}
+
+# List of "official" debug modes, but you can use anything you like.
+DEBUG_GENERAL = 'general'
+DEBUG_VARIABLES = 'variables'
+DEBUG_INCLUDES = 'includes'
+
+
+def DebugOutput(mode, message, *args):
+  if 'all' in gyp.debug or mode in gyp.debug:
+    ctx = ('unknown', 0, 'unknown')
+    try:
+      f = traceback.extract_stack(limit=2)
+      if f:
+        ctx = f[0][:3]
+    except:
+      pass
+    if args:
+      message %= args
+    print '%s:%s:%d:%s %s' % (mode.upper(), os.path.basename(ctx[0]),
+                              ctx[1], ctx[2], message)
+
+def FindBuildFiles():
+  extension = '.gyp'
+  files = os.listdir(os.getcwd())
+  build_files = []
+  for file in files:
+    if file.endswith(extension):
+      build_files.append(file)
+  return build_files
+
+
+def Load(build_files, format, default_variables={},
+         includes=[], depth='.', params=None, check=False,
+         circular_check=True, duplicate_basename_check=True):
+  """
+  Loads one or more specified build files.
+  default_variables and includes will be copied before use.
+  Returns the generator for the specified format and the
+  data returned by loading the specified build files.
+  """
+  if params is None:
+    params = {}
+
+  flavor = None
+  if '-' in format:
+    format, params['flavor'] = format.split('-', 1)
+
+  default_variables = copy.copy(default_variables)
+
+  # Default variables provided by this program and its modules should be
+  # named WITH_CAPITAL_LETTERS to provide a distinct "best practice" namespace,
+  # avoiding collisions with user and automatic variables.
+  default_variables['GENERATOR'] = format
+
+  # Format can be a custom python file, or by default the name of a module
+  # within gyp.generator.
+  if format.endswith('.py'):
+    generator_name = os.path.splitext(format)[0]
+    path, generator_name = os.path.split(generator_name)
+
+    # Make sure the path to the custom generator is in sys.path
+    # Don't worry about removing it once we are done.  Keeping the path
+    # to each generator that is used in sys.path is likely harmless and
+    # arguably a good idea.
+    path = os.path.abspath(path)
+    if path not in sys.path:
+      sys.path.insert(0, path)
+  else:
+    generator_name = 'gyp.generator.' + format
+
+  # These parameters are passed in order (as opposed to by key)
+  # because ActivePython cannot handle key parameters to __import__.
+  generator = __import__(generator_name, globals(), locals(), generator_name)
+  for (key, val) in generator.generator_default_variables.items():
+    default_variables.setdefault(key, val)
+
+  # Give the generator the opportunity to set additional variables based on
+  # the params it will receive in the output phase.
+  if getattr(generator, 'CalculateVariables', None):
+    generator.CalculateVariables(default_variables, params)
+
+  # Give the generator the opportunity to set generator_input_info based on
+  # the params it will receive in the output phase.
+  if getattr(generator, 'CalculateGeneratorInputInfo', None):
+    generator.CalculateGeneratorInputInfo(params)
+
+  # Fetch the generator specific info that gets fed to input, we use getattr
+  # so we can default things and the generators only have to provide what
+  # they need.
+  generator_input_info = {
+    'non_configuration_keys':
+        getattr(generator, 'generator_additional_non_configuration_keys', []),
+    'path_sections':
+        getattr(generator, 'generator_additional_path_sections', []),
+    'extra_sources_for_rules':
+        getattr(generator, 'generator_extra_sources_for_rules', []),
+    'generator_supports_multiple_toolsets':
+        getattr(generator, 'generator_supports_multiple_toolsets', False),
+    'generator_wants_static_library_dependencies_adjusted':
+        getattr(generator,
+                'generator_wants_static_library_dependencies_adjusted', True),
+    'generator_wants_sorted_dependencies':
+        getattr(generator, 'generator_wants_sorted_dependencies', False),
+    'generator_filelist_paths':
+        getattr(generator, 'generator_filelist_paths', None),
+  }
+
+  # Process the input specific to this generator.
+  result = gyp.input.Load(build_files, default_variables, includes[:],
+                          depth, generator_input_info, check, circular_check,
+                          duplicate_basename_check,
+                          params['parallel'], params['root_targets'])
+  return [generator] + result
+
+def NameValueListToDict(name_value_list):
+  """
+  Takes an array of strings of the form 'NAME=VALUE' and creates a dictionary
+  of the pairs.  If a string is simply NAME, then the value in the dictionary
+  is set to True.  If VALUE can be converted to an integer, it is.
+  """
+  result = { }
+  for item in name_value_list:
+    tokens = item.split('=', 1)
+    if len(tokens) == 2:
+      # If we can make it an int, use that, otherwise, use the string.
+      try:
+        token_value = int(tokens[1])
+      except ValueError:
+        token_value = tokens[1]
+      # Set the variable to the supplied value.
+      result[tokens[0]] = token_value
+    else:
+      # No value supplied, treat it as a boolean and set it.
+      result[tokens[0]] = True
+  return result
+
+def ShlexEnv(env_name):
+  flags = os.environ.get(env_name, [])
+  if flags:
+    flags = shlex.split(flags)
+  return flags
+
+def FormatOpt(opt, value):
+  if opt.startswith('--'):
+    return '%s=%s' % (opt, value)
+  return opt + value
+
+def RegenerateAppendFlag(flag, values, predicate, env_name, options):
+  """Regenerate a list of command line flags, for an option of action='append'.
+
+  The |env_name|, if given, is checked in the environment and used to generate
+  an initial list of options, then the options that were specified on the
+  command line (given in |values|) are appended.  This matches the handling of
+  environment variables and command line flags where command line flags override
+  the environment, while not requiring the environment to be set when the flags
+  are used again.
+  """
+  flags = []
+  if options.use_environment and env_name:
+    for flag_value in ShlexEnv(env_name):
+      value = FormatOpt(flag, predicate(flag_value))
+      if value in flags:
+        flags.remove(value)
+      flags.append(value)
+  if values:
+    for flag_value in values:
+      flags.append(FormatOpt(flag, predicate(flag_value)))
+  return flags
+
+def RegenerateFlags(options):
+  """Given a parsed options object, and taking the environment variables into
+  account, returns a list of flags that should regenerate an equivalent options
+  object (even in the absence of the environment variables.)
+
+  Any path options will be normalized relative to depth.
+
+  The format flag is not included, as it is assumed the calling generator will
+  set that as appropriate.
+  """
+  def FixPath(path):
+    path = gyp.common.FixIfRelativePath(path, options.depth)
+    if not path:
+      return os.path.curdir
+    return path
+
+  def Noop(value):
+    return value
+
+  # We always want to ignore the environment when regenerating, to avoid
+  # duplicate or changed flags in the environment at the time of regeneration.
+  flags = ['--ignore-environment']
+  for name, metadata in options._regeneration_metadata.iteritems():
+    opt = metadata['opt']
+    value = getattr(options, name)
+    value_predicate = metadata['type'] == 'path' and FixPath or Noop
+    action = metadata['action']
+    env_name = metadata['env_name']
+    if action == 'append':
+      flags.extend(RegenerateAppendFlag(opt, value, value_predicate,
+                                        env_name, options))
+    elif action in ('store', None):  # None is a synonym for 'store'.
+      if value:
+        flags.append(FormatOpt(opt, value_predicate(value)))
+      elif options.use_environment and env_name and os.environ.get(env_name):
+        flags.append(FormatOpt(opt, value_predicate(os.environ.get(env_name))))
+    elif action in ('store_true', 'store_false'):
+      if ((action == 'store_true' and value) or
+          (action == 'store_false' and not value)):
+        flags.append(opt)
+      elif options.use_environment and env_name:
+        print >>sys.stderr, ('Warning: environment regeneration unimplemented '
+                             'for %s flag %r env_name %r' % (action, opt,
+                                                             env_name))
+    else:
+      print >>sys.stderr, ('Warning: regeneration unimplemented for action %r '
+                           'flag %r' % (action, opt))
+
+  return flags
+
+class RegeneratableOptionParser(optparse.OptionParser):
+  def __init__(self):
+    self.__regeneratable_options = {}
+    optparse.OptionParser.__init__(self)
+
+  def add_option(self, *args, **kw):
+    """Add an option to the parser.
+
+    This accepts the same arguments as OptionParser.add_option, plus the
+    following:
+      regenerate: can be set to False to prevent this option from being included
+                  in regeneration.
+      env_name: name of environment variable that additional values for this
+                option come from.
+      type: adds type='path', to tell the regenerator that the values of
+            this option need to be made relative to options.depth
+    """
+    env_name = kw.pop('env_name', None)
+    if 'dest' in kw and kw.pop('regenerate', True):
+      dest = kw['dest']
+
+      # The path type is needed for regenerating, for optparse we can just treat
+      # it as a string.
+      type = kw.get('type')
+      if type == 'path':
+        kw['type'] = 'string'
+
+      self.__regeneratable_options[dest] = {
+          'action': kw.get('action'),
+          'type': type,
+          'env_name': env_name,
+          'opt': args[0],
+        }
+
+    optparse.OptionParser.add_option(self, *args, **kw)
+
+  def parse_args(self, *args):
+    values, args = optparse.OptionParser.parse_args(self, *args)
+    values._regeneration_metadata = self.__regeneratable_options
+    return values, args
+
+def gyp_main(args):
+  my_name = os.path.basename(sys.argv[0])
+
+  parser = RegeneratableOptionParser()
+  usage = 'usage: %s [options ...] [build_file ...]'
+  parser.set_usage(usage.replace('%s', '%prog'))
+  parser.add_option('--build', dest='configs', action='append',
+                    help='configuration for build after project generation')
+  parser.add_option('--check', dest='check', action='store_true',
+                    help='check format of gyp files')
+  parser.add_option('--config-dir', dest='config_dir', action='store',
+                    env_name='GYP_CONFIG_DIR', default=None,
+                    help='The location for configuration files like '
+                    'include.gypi.')
+  parser.add_option('-d', '--debug', dest='debug', metavar='DEBUGMODE',
+                    action='append', default=[], help='turn on a debugging '
+                    'mode for debugging GYP.  Supported modes are "variables", '
+                    '"includes" and "general" or "all" for all of them.')
+  parser.add_option('-D', dest='defines', action='append', metavar='VAR=VAL',
+                    env_name='GYP_DEFINES',
+                    help='sets variable VAR to value VAL')
+  parser.add_option('--depth', dest='depth', metavar='PATH', type='path',
+                    help='set DEPTH gyp variable to a relative path to PATH')
+  parser.add_option('-f', '--format', dest='formats', action='append',
+                    env_name='GYP_GENERATORS', regenerate=False,
+                    help='output formats to generate')
+  parser.add_option('-G', dest='generator_flags', action='append', default=[],
+                    metavar='FLAG=VAL', env_name='GYP_GENERATOR_FLAGS',
+                    help='sets generator flag FLAG to VAL')
+  parser.add_option('--generator-output', dest='generator_output',
+                    action='store', default=None, metavar='DIR', type='path',
+                    env_name='GYP_GENERATOR_OUTPUT',
+                    help='puts generated build files under DIR')
+  parser.add_option('--ignore-environment', dest='use_environment',
+                    action='store_false', default=True, regenerate=False,
+                    help='do not read options from environment variables')
+  parser.add_option('-I', '--include', dest='includes', action='append',
+                    metavar='INCLUDE', type='path',
+                    help='files to include in all loaded .gyp files')
+  # --no-circular-check disables the check for circular relationships between
+  # .gyp files.  These relationships should not exist, but they've only been
+  # observed to be harmful with the Xcode generator.  Chromium's .gyp files
+  # currently have some circular relationships on non-Mac platforms, so this
+  # option allows the strict behavior to be used on Macs and the lenient
+  # behavior to be used elsewhere.
+  # TODO(mark): Remove this option when http://crbug.com/35878 is fixed.
+  parser.add_option('--no-circular-check', dest='circular_check',
+                    action='store_false', default=True, regenerate=False,
+                    help="don't check for circular relationships between files")
+  # --no-duplicate-basename-check disables the check for duplicate basenames
+  # in a static_library/shared_library project. Visual C++ 2008 generator
+  # doesn't support this configuration. Libtool on Mac also generates warnings
+  # when duplicate basenames are passed into Make generator on Mac.
+  # TODO(yukawa): Remove this option when these legacy generators are
+  # deprecated.
+  parser.add_option('--no-duplicate-basename-check',
+                    dest='duplicate_basename_check', action='store_false',
+                    default=True, regenerate=False,
+                    help="don't check for duplicate basenames")
+  parser.add_option('--no-parallel', action='store_true', default=False,
+                    help='Disable multiprocessing')
+  parser.add_option('-S', '--suffix', dest='suffix', default='',
+                    help='suffix to add to generated files')
+  parser.add_option('--toplevel-dir', dest='toplevel_dir', action='store',
+                    default=None, metavar='DIR', type='path',
+                    help='directory to use as the root of the source tree')
+  parser.add_option('-R', '--root-target', dest='root_targets',
+                    action='append', metavar='TARGET',
+                    help='include only TARGET and its deep dependencies')
+
+  options, build_files_arg = parser.parse_args(args)
+  build_files = build_files_arg
+
+  # Set up the configuration directory (defaults to ~/.gyp)
+  if not options.config_dir:
+    home = None
+    home_dot_gyp = None
+    if options.use_environment:
+      home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None)
+      if home_dot_gyp:
+        home_dot_gyp = os.path.expanduser(home_dot_gyp)
+
+    if not home_dot_gyp:
+      home_vars = ['HOME']
+      if sys.platform in ('cygwin', 'win32'):
+        home_vars.append('USERPROFILE')
+      for home_var in home_vars:
+        home = os.getenv(home_var)
+        if home != None:
+          home_dot_gyp = os.path.join(home, '.gyp')
+          if not os.path.exists(home_dot_gyp):
+            home_dot_gyp = None
+          else:
+            break
+  else:
+    home_dot_gyp = os.path.expanduser(options.config_dir)
+
+  if home_dot_gyp and not os.path.exists(home_dot_gyp):
+    home_dot_gyp = None
+
+  if not options.formats:
+    # If no format was given on the command line, then check the env variable.
+    generate_formats = []
+    if options.use_environment:
+      generate_formats = os.environ.get('GYP_GENERATORS', [])
+    if generate_formats:
+      generate_formats = re.split('[\s,]', generate_formats)
+    if generate_formats:
+      options.formats = generate_formats
+    else:
+      # Nothing in the variable, default based on platform.
+      if sys.platform == 'darwin':
+        options.formats = ['xcode']
+      elif sys.platform in ('win32', 'cygwin'):
+        options.formats = ['msvs']
+      else:
+        options.formats = ['make']
+
+  if not options.generator_output and options.use_environment:
+    g_o = os.environ.get('GYP_GENERATOR_OUTPUT')
+    if g_o:
+      options.generator_output = g_o
+
+  options.parallel = not options.no_parallel
+
+  for mode in options.debug:
+    gyp.debug[mode] = 1
+
+  # Do an extra check to avoid work when we're not debugging.
+  if DEBUG_GENERAL in gyp.debug:
+    DebugOutput(DEBUG_GENERAL, 'running with these options:')
+    for option, value in sorted(options.__dict__.items()):
+      if option[0] == '_':
+        continue
+      if isinstance(value, basestring):
+        DebugOutput(DEBUG_GENERAL, "  %s: '%s'", option, value)
+      else:
+        DebugOutput(DEBUG_GENERAL, "  %s: %s", option, value)
+
+  if not build_files:
+    build_files = FindBuildFiles()
+  if not build_files:
+    raise GypError((usage + '\n\n%s: error: no build_file') %
+                   (my_name, my_name))
+
+  # TODO(mark): Chromium-specific hack!
+  # For Chromium, the gyp "depth" variable should always be a relative path
+  # to Chromium's top-level "src" directory.  If no depth variable was set
+  # on the command line, try to find a "src" directory by looking at the
+  # absolute path to each build file's directory.  The first "src" component
+  # found will be treated as though it were the path used for --depth.
+  if not options.depth:
+    for build_file in build_files:
+      build_file_dir = os.path.abspath(os.path.dirname(build_file))
+      build_file_dir_components = build_file_dir.split(os.path.sep)
+      components_len = len(build_file_dir_components)
+      for index in xrange(components_len - 1, -1, -1):
+        if build_file_dir_components[index] == 'src':
+          options.depth = os.path.sep.join(build_file_dir_components)
+          break
+        del build_file_dir_components[index]
+
+      # If the inner loop found something, break without advancing to another
+      # build file.
+      if options.depth:
+        break
+
+    if not options.depth:
+      raise GypError('Could not automatically locate src directory.  This is'
+                     'a temporary Chromium feature that will be removed.  Use'
+                     '--depth as a workaround.')
+
+  # If toplevel-dir is not set, we assume that depth is the root of our source
+  # tree.
+  if not options.toplevel_dir:
+    options.toplevel_dir = options.depth
+
+  # -D on the command line sets variable defaults - D isn't just for define,
+  # it's for default.  Perhaps there should be a way to force (-F?) a
+  # variable's value so that it can't be overridden by anything else.
+  cmdline_default_variables = {}
+  defines = []
+  if options.use_environment:
+    defines += ShlexEnv('GYP_DEFINES')
+  if options.defines:
+    defines += options.defines
+  cmdline_default_variables = NameValueListToDict(defines)
+  if DEBUG_GENERAL in gyp.debug:
+    DebugOutput(DEBUG_GENERAL,
+                "cmdline_default_variables: %s", cmdline_default_variables)
+
+  # Set up includes.
+  includes = []
+
+  # If ~/.gyp/include.gypi exists, it'll be forcibly included into every
+  # .gyp file that's loaded, before anything else is included.
+  if home_dot_gyp != None:
+    default_include = os.path.join(home_dot_gyp, 'include.gypi')
+    if os.path.exists(default_include):
+      print 'Using overrides found in ' + default_include
+      includes.append(default_include)
+
+  # Command-line --include files come after the default include.
+  if options.includes:
+    includes.extend(options.includes)
+
+  # Generator flags should be prefixed with the target generator since they
+  # are global across all generator runs.
+  gen_flags = []
+  if options.use_environment:
+    gen_flags += ShlexEnv('GYP_GENERATOR_FLAGS')
+  if options.generator_flags:
+    gen_flags += options.generator_flags
+  generator_flags = NameValueListToDict(gen_flags)
+  if DEBUG_GENERAL in gyp.debug.keys():
+    DebugOutput(DEBUG_GENERAL, "generator_flags: %s", generator_flags)
+
+  # Generate all requested formats (use a set in case we got one format request
+  # twice)
+  for format in set(options.formats):
+    params = {'options': options,
+              'build_files': build_files,
+              'generator_flags': generator_flags,
+              'cwd': os.getcwd(),
+              'build_files_arg': build_files_arg,
+              'gyp_binary': sys.argv[0],
+              'home_dot_gyp': home_dot_gyp,
+              'parallel': options.parallel,
+              'root_targets': options.root_targets}
+
+    # Start with the default variables from the command line.
+    [generator, flat_list, targets, data] = Load(
+        build_files, format, cmdline_default_variables, includes, options.depth,
+        params, options.check, options.circular_check,
+        options.duplicate_basename_check)
+
+    # TODO(mark): Pass |data| for now because the generator needs a list of
+    # build files that came in.  In the future, maybe it should just accept
+    # a list, and not the whole data dict.
+    # NOTE: flat_list is the flattened dependency graph specifying the order
+    # that targets may be built.  Build systems that operate serially or that
+    # need to have dependencies defined before dependents reference them should
+    # generate targets in the order specified in flat_list.
+    generator.GenerateOutput(flat_list, targets, data, params)
+
+    if options.configs:
+      valid_configs = targets[flat_list[0]]['configurations'].keys()
+      for conf in options.configs:
+        if conf not in valid_configs:
+          raise GypError('Invalid config specified via --build: %s' % conf)
+      generator.PerformBuild(data, options.configs, params)
+
+  # Done
+  return 0
+
+
+def main(args):
+  try:
+    return gyp_main(args)
+  except GypError, e:
+    sys.stderr.write("gyp: %s\n" % e)
+    return 1
+
+# NOTE: setuptools generated console_scripts calls function with no arguments
+def script_main():
+  return main(sys.argv[1:])
+
+if __name__ == '__main__':
+  sys.exit(script_main())
diff --git a/gyp/pylib/gyp/common.py b/gyp/pylib/gyp/common.py
new file mode 100644 (file)
index 0000000..df71d97
--- /dev/null
@@ -0,0 +1,588 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from __future__ import with_statement
+
+import collections
+import errno
+import filecmp
+import os.path
+import re
+import tempfile
+import sys
+
+
+# A minimal memoizing decorator. It'll blow up if the args aren't immutable,
+# among other "problems".
+class memoize(object):
+  def __init__(self, func):
+    self.func = func
+    self.cache = {}
+  def __call__(self, *args):
+    try:
+      return self.cache[args]
+    except KeyError:
+      result = self.func(*args)
+      self.cache[args] = result
+      return result
+
+
+class GypError(Exception):
+  """Error class representing an error, which is to be presented
+  to the user.  The main entry point will catch and display this.
+  """
+  pass
+
+
+def ExceptionAppend(e, msg):
+  """Append a message to the given exception's message."""
+  if not e.args:
+    e.args = (msg,)
+  elif len(e.args) == 1:
+    e.args = (str(e.args[0]) + ' ' + msg,)
+  else:
+    e.args = (str(e.args[0]) + ' ' + msg,) + e.args[1:]
+
+
+def FindQualifiedTargets(target, qualified_list):
+  """
+  Given a list of qualified targets, return the qualified targets for the
+  specified |target|.
+  """
+  return [t for t in qualified_list if ParseQualifiedTarget(t)[1] == target]
+
+
+def ParseQualifiedTarget(target):
+  # Splits a qualified target into a build file, target name and toolset.
+
+  # NOTE: rsplit is used to disambiguate the Windows drive letter separator.
+  target_split = target.rsplit(':', 1)
+  if len(target_split) == 2:
+    [build_file, target] = target_split
+  else:
+    build_file = None
+
+  target_split = target.rsplit('#', 1)
+  if len(target_split) == 2:
+    [target, toolset] = target_split
+  else:
+    toolset = None
+
+  return [build_file, target, toolset]
+
+
+def ResolveTarget(build_file, target, toolset):
+  # This function resolves a target into a canonical form:
+  # - a fully defined build file, either absolute or relative to the current
+  # directory
+  # - a target name
+  # - a toolset
+  #
+  # build_file is the file relative to which 'target' is defined.
+  # target is the qualified target.
+  # toolset is the default toolset for that target.
+  [parsed_build_file, target, parsed_toolset] = ParseQualifiedTarget(target)
+
+  if parsed_build_file:
+    if build_file:
+      # If a relative path, parsed_build_file is relative to the directory
+      # containing build_file.  If build_file is not in the current directory,
+      # parsed_build_file is not a usable path as-is.  Resolve it by
+      # interpreting it as relative to build_file.  If parsed_build_file is
+      # absolute, it is usable as a path regardless of the current directory,
+      # and os.path.join will return it as-is.
+      build_file = os.path.normpath(os.path.join(os.path.dirname(build_file),
+                                                 parsed_build_file))
+      # Further (to handle cases like ../cwd), make it relative to cwd)
+      if not os.path.isabs(build_file):
+        build_file = RelativePath(build_file, '.')
+    else:
+      build_file = parsed_build_file
+
+  if parsed_toolset:
+    toolset = parsed_toolset
+
+  return [build_file, target, toolset]
+
+
+def BuildFile(fully_qualified_target):
+  # Extracts the build file from the fully qualified target.
+  return ParseQualifiedTarget(fully_qualified_target)[0]
+
+
+def GetEnvironFallback(var_list, default):
+  """Look up a key in the environment, with fallback to secondary keys
+  and finally falling back to a default value."""
+  for var in var_list:
+    if var in os.environ:
+      return os.environ[var]
+  return default
+
+
+def QualifiedTarget(build_file, target, toolset):
+  # "Qualified" means the file that a target was defined in and the target
+  # name, separated by a colon, suffixed by a # and the toolset name:
+  # /path/to/file.gyp:target_name#toolset
+  fully_qualified = build_file + ':' + target
+  if toolset:
+    fully_qualified = fully_qualified + '#' + toolset
+  return fully_qualified
+
+
+@memoize
+def RelativePath(path, relative_to):
+  # Assuming both |path| and |relative_to| are relative to the current
+  # directory, returns a relative path that identifies path relative to
+  # relative_to.
+
+  # Convert to normalized (and therefore absolute paths).
+  path = os.path.realpath(path)
+  relative_to = os.path.realpath(relative_to)
+
+  # On Windows, we can't create a relative path to a different drive, so just
+  # use the absolute path.
+  if sys.platform == 'win32':
+    if (os.path.splitdrive(path)[0].lower() !=
+        os.path.splitdrive(relative_to)[0].lower()):
+      return path
+
+  # Split the paths into components.
+  path_split = path.split(os.path.sep)
+  relative_to_split = relative_to.split(os.path.sep)
+
+  # Determine how much of the prefix the two paths share.
+  prefix_len = len(os.path.commonprefix([path_split, relative_to_split]))
+
+  # Put enough ".." components to back up out of relative_to to the common
+  # prefix, and then append the part of path_split after the common prefix.
+  relative_split = [os.path.pardir] * (len(relative_to_split) - prefix_len) + \
+                   path_split[prefix_len:]
+
+  if len(relative_split) == 0:
+    # The paths were the same.
+    return ''
+
+  # Turn it back into a string and we're done.
+  return os.path.join(*relative_split)
+
+
+@memoize
+def InvertRelativePath(path, toplevel_dir=None):
+  """Given a path like foo/bar that is relative to toplevel_dir, return
+  the inverse relative path back to the toplevel_dir.
+
+  E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
+  should always produce the empty string, unless the path contains symlinks.
+  """
+  if not path:
+    return path
+  toplevel_dir = '.' if toplevel_dir is None else toplevel_dir
+  return RelativePath(toplevel_dir, os.path.join(toplevel_dir, path))
+
+
+def FixIfRelativePath(path, relative_to):
+  # Like RelativePath but returns |path| unchanged if it is absolute.
+  if os.path.isabs(path):
+    return path
+  return RelativePath(path, relative_to)
+
+
+def UnrelativePath(path, relative_to):
+  # Assuming that |relative_to| is relative to the current directory, and |path|
+  # is a path relative to the dirname of |relative_to|, returns a path that
+  # identifies |path| relative to the current directory.
+  rel_dir = os.path.dirname(relative_to)
+  return os.path.normpath(os.path.join(rel_dir, path))
+
+
+# re objects used by EncodePOSIXShellArgument.  See IEEE 1003.1 XCU.2.2 at
+# http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_02
+# and the documentation for various shells.
+
+# _quote is a pattern that should match any argument that needs to be quoted
+# with double-quotes by EncodePOSIXShellArgument.  It matches the following
+# characters appearing anywhere in an argument:
+#   \t, \n, space  parameter separators
+#   #              comments
+#   $              expansions (quoted to always expand within one argument)
+#   %              called out by IEEE 1003.1 XCU.2.2
+#   &              job control
+#   '              quoting
+#   (, )           subshell execution
+#   *, ?, [        pathname expansion
+#   ;              command delimiter
+#   <, >, |        redirection
+#   =              assignment
+#   {, }           brace expansion (bash)
+#   ~              tilde expansion
+# It also matches the empty string, because "" (or '') is the only way to
+# represent an empty string literal argument to a POSIX shell.
+#
+# This does not match the characters in _escape, because those need to be
+# backslash-escaped regardless of whether they appear in a double-quoted
+# string.
+_quote = re.compile('[\t\n #$%&\'()*;<=>?[{|}~]|^$')
+
+# _escape is a pattern that should match any character that needs to be
+# escaped with a backslash, whether or not the argument matched the _quote
+# pattern.  _escape is used with re.sub to backslash anything in _escape's
+# first match group, hence the (parentheses) in the regular expression.
+#
+# _escape matches the following characters appearing anywhere in an argument:
+#   "  to prevent POSIX shells from interpreting this character for quoting
+#   \  to prevent POSIX shells from interpreting this character for escaping
+#   `  to prevent POSIX shells from interpreting this character for command
+#      substitution
+# Missing from this list is $, because the desired behavior of
+# EncodePOSIXShellArgument is to permit parameter (variable) expansion.
+#
+# Also missing from this list is !, which bash will interpret as the history
+# expansion character when history is enabled.  bash does not enable history
+# by default in non-interactive shells, so this is not thought to be a problem.
+# ! was omitted from this list because bash interprets "\!" as a literal string
+# including the backslash character (avoiding history expansion but retaining
+# the backslash), which would not be correct for argument encoding.  Handling
+# this case properly would also be problematic because bash allows the history
+# character to be changed with the histchars shell variable.  Fortunately,
+# as history is not enabled in non-interactive shells and
+# EncodePOSIXShellArgument is only expected to encode for non-interactive
+# shells, there is no room for error here by ignoring !.
+_escape = re.compile(r'(["\\`])')
+
+def EncodePOSIXShellArgument(argument):
+  """Encodes |argument| suitably for consumption by POSIX shells.
+
+  argument may be quoted and escaped as necessary to ensure that POSIX shells
+  treat the returned value as a literal representing the argument passed to
+  this function.  Parameter (variable) expansions beginning with $ are allowed
+  to remain intact without escaping the $, to allow the argument to contain
+  references to variables to be expanded by the shell.
+  """
+
+  if not isinstance(argument, str):
+    argument = str(argument)
+
+  if _quote.search(argument):
+    quote = '"'
+  else:
+    quote = ''
+
+  encoded = quote + re.sub(_escape, r'\\\1', argument) + quote
+
+  return encoded
+
+
+def EncodePOSIXShellList(list):
+  """Encodes |list| suitably for consumption by POSIX shells.
+
+  Returns EncodePOSIXShellArgument for each item in list, and joins them
+  together using the space character as an argument separator.
+  """
+
+  encoded_arguments = []
+  for argument in list:
+    encoded_arguments.append(EncodePOSIXShellArgument(argument))
+  return ' '.join(encoded_arguments)
+
+
+def DeepDependencyTargets(target_dicts, roots):
+  """Returns the recursive list of target dependencies."""
+  dependencies = set()
+  pending = set(roots)
+  while pending:
+    # Pluck out one.
+    r = pending.pop()
+    # Skip if visited already.
+    if r in dependencies:
+      continue
+    # Add it.
+    dependencies.add(r)
+    # Add its children.
+    spec = target_dicts[r]
+    pending.update(set(spec.get('dependencies', [])))
+    pending.update(set(spec.get('dependencies_original', [])))
+  return list(dependencies - set(roots))
+
+
+def BuildFileTargets(target_list, build_file):
+  """From a target_list, returns the subset from the specified build_file.
+  """
+  return [p for p in target_list if BuildFile(p) == build_file]
+
+
+def AllTargets(target_list, target_dicts, build_file):
+  """Returns all targets (direct and dependencies) for the specified build_file.
+  """
+  bftargets = BuildFileTargets(target_list, build_file)
+  deptargets = DeepDependencyTargets(target_dicts, bftargets)
+  return bftargets + deptargets
+
+
+def WriteOnDiff(filename):
+  """Write to a file only if the new contents differ.
+
+  Arguments:
+    filename: name of the file to potentially write to.
+  Returns:
+    A file like object which will write to temporary file and only overwrite
+    the target if it differs (on close).
+  """
+
+  class Writer:
+    """Wrapper around file which only covers the target if it differs."""
+    def __init__(self):
+      # Pick temporary file.
+      tmp_fd, self.tmp_path = tempfile.mkstemp(
+          suffix='.tmp',
+          prefix=os.path.split(filename)[1] + '.gyp.',
+          dir=os.path.split(filename)[0])
+      try:
+        self.tmp_file = os.fdopen(tmp_fd, 'wb')
+      except Exception:
+        # Don't leave turds behind.
+        os.unlink(self.tmp_path)
+        raise
+
+    def __getattr__(self, attrname):
+      # Delegate everything else to self.tmp_file
+      return getattr(self.tmp_file, attrname)
+
+    def close(self):
+      try:
+        # Close tmp file.
+        self.tmp_file.close()
+        # Determine if different.
+        same = False
+        try:
+          same = filecmp.cmp(self.tmp_path, filename, False)
+        except OSError, e:
+          if e.errno != errno.ENOENT:
+            raise
+
+        if same:
+          # The new file is identical to the old one, just get rid of the new
+          # one.
+          os.unlink(self.tmp_path)
+        else:
+          # The new file is different from the old one, or there is no old one.
+          # Rename the new file to the permanent name.
+          #
+          # tempfile.mkstemp uses an overly restrictive mode, resulting in a
+          # file that can only be read by the owner, regardless of the umask.
+          # There's no reason to not respect the umask here, which means that
+          # an extra hoop is required to fetch it and reset the new file's mode.
+          #
+          # No way to get the umask without setting a new one?  Set a safe one
+          # and then set it back to the old value.
+          umask = os.umask(077)
+          os.umask(umask)
+          os.chmod(self.tmp_path, 0666 & ~umask)
+          if sys.platform == 'win32' and os.path.exists(filename):
+            # NOTE: on windows (but not cygwin) rename will not replace an
+            # existing file, so it must be preceded with a remove. Sadly there
+            # is no way to make the switch atomic.
+            os.remove(filename)
+          os.rename(self.tmp_path, filename)
+      except Exception:
+        # Don't leave turds behind.
+        os.unlink(self.tmp_path)
+        raise
+
+  return Writer()
+
+
+def EnsureDirExists(path):
+  """Make sure the directory for |path| exists."""
+  try:
+    os.makedirs(os.path.dirname(path))
+  except OSError:
+    pass
+
+
+def GetFlavor(params):
+  """Returns |params.flavor| if it's set, the system's default flavor else."""
+  flavors = {
+    'cygwin': 'win',
+    'win32': 'win',
+    'darwin': 'mac',
+  }
+
+  if 'flavor' in params:
+    return params['flavor']
+  if sys.platform in flavors:
+    return flavors[sys.platform]
+  if sys.platform.startswith('sunos'):
+    return 'solaris'
+  if sys.platform.startswith('freebsd'):
+    return 'freebsd'
+  if sys.platform.startswith('openbsd'):
+    return 'openbsd'
+  if sys.platform.startswith('aix'):
+    return 'aix'
+
+  return 'linux'
+
+
+def CopyTool(flavor, out_path):
+  """Finds (flock|mac|win)_tool.gyp in the gyp directory and copies it
+  to |out_path|."""
+  # aix and solaris just need flock emulation. mac and win use more complicated
+  # support scripts.
+  prefix = {
+      'aix': 'flock',
+      'solaris': 'flock',
+      'mac': 'mac',
+      'win': 'win'
+      }.get(flavor, None)
+  if not prefix:
+    return
+
+  # Slurp input file.
+  source_path = os.path.join(
+      os.path.dirname(os.path.abspath(__file__)), '%s_tool.py' % prefix)
+  with open(source_path) as source_file:
+    source = source_file.readlines()
+
+  # Add header and write it out.
+  tool_path = os.path.join(out_path, 'gyp-%s-tool' % prefix)
+  with open(tool_path, 'w') as tool_file:
+    tool_file.write(
+        ''.join([source[0], '# Generated by gyp. Do not edit.\n'] + source[1:]))
+
+  # Make file executable.
+  os.chmod(tool_path, 0755)
+
+
+# From Alex Martelli,
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560
+# ASPN: Python Cookbook: Remove duplicates from a sequence
+# First comment, dated 2001/10/13.
+# (Also in the printed Python Cookbook.)
+
+def uniquer(seq, idfun=None):
+    if idfun is None:
+        idfun = lambda x: x
+    seen = {}
+    result = []
+    for item in seq:
+        marker = idfun(item)
+        if marker in seen: continue
+        seen[marker] = 1
+        result.append(item)
+    return result
+
+
+# Based on http://code.activestate.com/recipes/576694/.
+class OrderedSet(collections.MutableSet):
+  def __init__(self, iterable=None):
+    self.end = end = []
+    end += [None, end, end]         # sentinel node for doubly linked list
+    self.map = {}                   # key --> [key, prev, next]
+    if iterable is not None:
+      self |= iterable
+
+  def __len__(self):
+    return len(self.map)
+
+  def __contains__(self, key):
+    return key in self.map
+
+  def add(self, key):
+    if key not in self.map:
+      end = self.end
+      curr = end[1]
+      curr[2] = end[1] = self.map[key] = [key, curr, end]
+
+  def discard(self, key):
+    if key in self.map:
+      key, prev_item, next_item = self.map.pop(key)
+      prev_item[2] = next_item
+      next_item[1] = prev_item
+
+  def __iter__(self):
+    end = self.end
+    curr = end[2]
+    while curr is not end:
+      yield curr[0]
+      curr = curr[2]
+
+  def __reversed__(self):
+    end = self.end
+    curr = end[1]
+    while curr is not end:
+      yield curr[0]
+      curr = curr[1]
+
+  # The second argument is an addition that causes a pylint warning.
+  def pop(self, last=True):  # pylint: disable=W0221
+    if not self:
+      raise KeyError('set is empty')
+    key = self.end[1][0] if last else self.end[2][0]
+    self.discard(key)
+    return key
+
+  def __repr__(self):
+    if not self:
+      return '%s()' % (self.__class__.__name__,)
+    return '%s(%r)' % (self.__class__.__name__, list(self))
+
+  def __eq__(self, other):
+    if isinstance(other, OrderedSet):
+      return len(self) == len(other) and list(self) == list(other)
+    return set(self) == set(other)
+
+  # Extensions to the recipe.
+  def update(self, iterable):
+    for i in iterable:
+      if i not in self:
+        self.add(i)
+
+
+class CycleError(Exception):
+  """An exception raised when an unexpected cycle is detected."""
+  def __init__(self, nodes):
+    self.nodes = nodes
+  def __str__(self):
+    return 'CycleError: cycle involving: ' + str(self.nodes)
+
+
+def TopologicallySorted(graph, get_edges):
+  """Topologically sort based on a user provided edge definition.
+
+  Args:
+    graph: A list of node names.
+    get_edges: A function mapping from node name to a hashable collection
+               of node names which this node has outgoing edges to.
+  Returns:
+    A list containing all of the node in graph in topological order.
+    It is assumed that calling get_edges once for each node and caching is
+    cheaper than repeatedly calling get_edges.
+  Raises:
+    CycleError in the event of a cycle.
+  Example:
+    graph = {'a': '$(b) $(c)', 'b': 'hi', 'c': '$(b)'}
+    def GetEdges(node):
+      return re.findall(r'\$\(([^))]\)', graph[node])
+    print TopologicallySorted(graph.keys(), GetEdges)
+    ==>
+    ['a', 'c', b']
+  """
+  get_edges = memoize(get_edges)
+  visited = set()
+  visiting = set()
+  ordered_nodes = []
+  def Visit(node):
+    if node in visiting:
+      raise CycleError(visiting)
+    if node in visited:
+      return
+    visited.add(node)
+    visiting.add(node)
+    for neighbor in get_edges(node):
+      Visit(neighbor)
+    visiting.remove(node)
+    ordered_nodes.insert(0, node)
+  for node in sorted(graph):
+    Visit(node)
+  return ordered_nodes
diff --git a/gyp/pylib/gyp/common_test.py b/gyp/pylib/gyp/common_test.py
new file mode 100755 (executable)
index 0000000..ad6f9a1
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unit tests for the common.py file."""
+
+import gyp.common
+import unittest
+import sys
+
+
+class TestTopologicallySorted(unittest.TestCase):
+  def test_Valid(self):
+    """Test that sorting works on a valid graph with one possible order."""
+    graph = {
+        'a': ['b', 'c'],
+        'b': [],
+        'c': ['d'],
+        'd': ['b'],
+        }
+    def GetEdge(node):
+      return tuple(graph[node])
+    self.assertEqual(
+      gyp.common.TopologicallySorted(graph.keys(), GetEdge),
+      ['a', 'c', 'd', 'b'])
+
+  def test_Cycle(self):
+    """Test that an exception is thrown on a cyclic graph."""
+    graph = {
+        'a': ['b'],
+        'b': ['c'],
+        'c': ['d'],
+        'd': ['a'],
+        }
+    def GetEdge(node):
+      return tuple(graph[node])
+    self.assertRaises(
+      gyp.common.CycleError, gyp.common.TopologicallySorted,
+      graph.keys(), GetEdge)
+
+
+class TestGetFlavor(unittest.TestCase):
+  """Test that gyp.common.GetFlavor works as intended"""
+  original_platform = ''
+
+  def setUp(self):
+    self.original_platform = sys.platform
+
+  def tearDown(self):
+    sys.platform = self.original_platform
+
+  def assertFlavor(self, expected, argument, param):
+    sys.platform = argument
+    self.assertEqual(expected, gyp.common.GetFlavor(param))
+
+  def test_platform_default(self):
+    self.assertFlavor('freebsd', 'freebsd9' , {})
+    self.assertFlavor('freebsd', 'freebsd10', {})
+    self.assertFlavor('openbsd', 'openbsd5' , {})
+    self.assertFlavor('solaris', 'sunos5'   , {});
+    self.assertFlavor('solaris', 'sunos'    , {});
+    self.assertFlavor('linux'  , 'linux2'   , {});
+    self.assertFlavor('linux'  , 'linux3'   , {});
+
+  def test_param(self):
+    self.assertFlavor('foobar', 'linux2' , {'flavor': 'foobar'})
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/gyp/pylib/gyp/easy_xml.py b/gyp/pylib/gyp/easy_xml.py
new file mode 100644 (file)
index 0000000..bf949b6
--- /dev/null
@@ -0,0 +1,157 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import re
+import os
+
+
+def XmlToString(content, encoding='utf-8', pretty=False):
+  """ Writes the XML content to disk, touching the file only if it has changed.
+
+  Visual Studio files have a lot of pre-defined structures.  This function makes
+  it easy to represent these structures as Python data structures, instead of
+  having to create a lot of function calls.
+
+  Each XML element of the content is represented as a list composed of:
+  1. The name of the element, a string,
+  2. The attributes of the element, a dictionary (optional), and
+  3+. The content of the element, if any.  Strings are simple text nodes and
+      lists are child elements.
+
+  Example 1:
+      <test/>
+  becomes
+      ['test']
+
+  Example 2:
+      <myelement a='value1' b='value2'>
+         <childtype>This is</childtype>
+         <childtype>it!</childtype>
+      </myelement>
+
+  becomes
+      ['myelement', {'a':'value1', 'b':'value2'},
+         ['childtype', 'This is'],
+         ['childtype', 'it!'],
+      ]
+
+  Args:
+    content:  The structured content to be converted.
+    encoding: The encoding to report on the first XML line.
+    pretty: True if we want pretty printing with indents and new lines.
+
+  Returns:
+    The XML content as a string.
+  """
+  # We create a huge list of all the elements of the file.
+  xml_parts = ['<?xml version="1.0" encoding="%s"?>' % encoding]
+  if pretty:
+    xml_parts.append('\n')
+  _ConstructContentList(xml_parts, content, pretty)
+
+  # Convert it to a string
+  return ''.join(xml_parts)
+
+
+def _ConstructContentList(xml_parts, specification, pretty, level=0):
+  """ Appends the XML parts corresponding to the specification.
+
+  Args:
+    xml_parts: A list of XML parts to be appended to.
+    specification:  The specification of the element.  See EasyXml docs.
+    pretty: True if we want pretty printing with indents and new lines.
+    level: Indentation level.
+  """
+  # The first item in a specification is the name of the element.
+  if pretty:
+    indentation = '  ' * level
+    new_line = '\n'
+  else:
+    indentation = ''
+    new_line = ''
+  name = specification[0]
+  if not isinstance(name, str):
+    raise Exception('The first item of an EasyXml specification should be '
+                    'a string.  Specification was ' + str(specification))
+  xml_parts.append(indentation + '<' + name)
+
+  # Optionally in second position is a dictionary of the attributes.
+  rest = specification[1:]
+  if rest and isinstance(rest[0], dict):
+    for at, val in sorted(rest[0].iteritems()):
+      xml_parts.append(' %s="%s"' % (at, _XmlEscape(val, attr=True)))
+    rest = rest[1:]
+  if rest:
+    xml_parts.append('>')
+    all_strings = reduce(lambda x, y: x and isinstance(y, str), rest, True)
+    multi_line = not all_strings
+    if multi_line and new_line:
+      xml_parts.append(new_line)
+    for child_spec in rest:
+      # If it's a string, append a text node.
+      # Otherwise recurse over that child definition
+      if isinstance(child_spec, str):
+       xml_parts.append(_XmlEscape(child_spec))
+      else:
+        _ConstructContentList(xml_parts, child_spec, pretty, level + 1)
+    if multi_line and indentation:
+      xml_parts.append(indentation)
+    xml_parts.append('</%s>%s' % (name, new_line))
+  else:
+    xml_parts.append('/>%s' % new_line)
+
+
+def WriteXmlIfChanged(content, path, encoding='utf-8', pretty=False,
+                      win32=False):
+  """ Writes the XML content to disk, touching the file only if it has changed.
+
+  Args:
+    content:  The structured content to be written.
+    path: Location of the file.
+    encoding: The encoding to report on the first line of the XML file.
+    pretty: True if we want pretty printing with indents and new lines.
+  """
+  xml_string = XmlToString(content, encoding, pretty)
+  if win32 and os.linesep != '\r\n':
+    xml_string = xml_string.replace('\n', '\r\n')
+
+  # Get the old content
+  try:
+    f = open(path, 'r')
+    existing = f.read()
+    f.close()
+  except:
+    existing = None
+
+  # It has changed, write it
+  if existing != xml_string:
+    f = open(path, 'w')
+    f.write(xml_string)
+    f.close()
+
+
+_xml_escape_map = {
+    '"': '&quot;',
+    "'": '&apos;',
+    '<': '&lt;',
+    '>': '&gt;',
+    '&': '&amp;',
+    '\n': '&#xA;',
+    '\r': '&#xD;',
+}
+
+
+_xml_escape_re = re.compile(
+    "(%s)" % "|".join(map(re.escape, _xml_escape_map.keys())))
+
+
+def _XmlEscape(value, attr=False):
+  """ Escape a string for inclusion in XML."""
+  def replace(match):
+    m = match.string[match.start() : match.end()]
+    # don't replace single quotes in attrs
+    if attr and m == "'":
+      return m
+    return _xml_escape_map[m]
+  return _xml_escape_re.sub(replace, value)
diff --git a/gyp/pylib/gyp/easy_xml_test.py b/gyp/pylib/gyp/easy_xml_test.py
new file mode 100755 (executable)
index 0000000..df64354
--- /dev/null
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Unit tests for the easy_xml.py file. """
+
+import gyp.easy_xml as easy_xml
+import unittest
+import StringIO
+
+
+class TestSequenceFunctions(unittest.TestCase):
+
+  def setUp(self):
+    self.stderr = StringIO.StringIO()
+
+  def test_EasyXml_simple(self):
+    self.assertEqual(
+      easy_xml.XmlToString(['test']),
+      '<?xml version="1.0" encoding="utf-8"?><test/>')
+
+    self.assertEqual(
+      easy_xml.XmlToString(['test'], encoding='Windows-1252'),
+      '<?xml version="1.0" encoding="Windows-1252"?><test/>')
+
+  def test_EasyXml_simple_with_attributes(self):
+    self.assertEqual(
+      easy_xml.XmlToString(['test2', {'a': 'value1', 'b': 'value2'}]),
+      '<?xml version="1.0" encoding="utf-8"?><test2 a="value1" b="value2"/>')
+
+  def test_EasyXml_escaping(self):
+    original = '<test>\'"\r&\nfoo'
+    converted = '&lt;test&gt;\'&quot;&#xD;&amp;&#xA;foo'
+    converted_apos = converted.replace("'", '&apos;')
+    self.assertEqual(
+      easy_xml.XmlToString(['test3', {'a': original}, original]),
+      '<?xml version="1.0" encoding="utf-8"?><test3 a="%s">%s</test3>' %
+      (converted, converted_apos))
+
+  def test_EasyXml_pretty(self):
+    self.assertEqual(
+      easy_xml.XmlToString(
+          ['test3',
+            ['GrandParent',
+              ['Parent1',
+                ['Child']
+              ],
+              ['Parent2']
+            ]
+          ],
+          pretty=True),
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<test3>\n'
+      '  <GrandParent>\n'
+      '    <Parent1>\n'
+      '      <Child/>\n'
+      '    </Parent1>\n'
+      '    <Parent2/>\n'
+      '  </GrandParent>\n'
+      '</test3>\n')
+
+
+  def test_EasyXml_complex(self):
+    # We want to create:
+    target = (
+      '<?xml version="1.0" encoding="utf-8"?>'
+      '<Project>'
+        '<PropertyGroup Label="Globals">'
+          '<ProjectGuid>{D2250C20-3A94-4FB9-AF73-11BC5B73884B}</ProjectGuid>'
+          '<Keyword>Win32Proj</Keyword>'
+          '<RootNamespace>automated_ui_tests</RootNamespace>'
+        '</PropertyGroup>'
+        '<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props"/>'
+        '<PropertyGroup '
+            'Condition="\'$(Configuration)|$(Platform)\'=='
+                       '\'Debug|Win32\'" Label="Configuration">'
+          '<ConfigurationType>Application</ConfigurationType>'
+          '<CharacterSet>Unicode</CharacterSet>'
+        '</PropertyGroup>'
+      '</Project>')
+
+    xml = easy_xml.XmlToString(
+        ['Project',
+          ['PropertyGroup', {'Label': 'Globals'},
+            ['ProjectGuid', '{D2250C20-3A94-4FB9-AF73-11BC5B73884B}'],
+            ['Keyword', 'Win32Proj'],
+            ['RootNamespace', 'automated_ui_tests']
+          ],
+          ['Import', {'Project': '$(VCTargetsPath)\\Microsoft.Cpp.props'}],
+          ['PropertyGroup',
+            {'Condition': "'$(Configuration)|$(Platform)'=='Debug|Win32'",
+             'Label': 'Configuration'},
+            ['ConfigurationType', 'Application'],
+            ['CharacterSet', 'Unicode']
+          ]
+        ])
+    self.assertEqual(xml, target)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/gyp/pylib/gyp/flock_tool.py b/gyp/pylib/gyp/flock_tool.py
new file mode 100755 (executable)
index 0000000..3e7efff
--- /dev/null
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""These functions are executed via gyp-flock-tool when using the Makefile
+generator.  Used on systems that don't have a built-in flock."""
+
+import fcntl
+import os
+import struct
+import subprocess
+import sys
+
+
+def main(args):
+  executor = FlockTool()
+  executor.Dispatch(args)
+
+
+class FlockTool(object):
+  """This class emulates the 'flock' command."""
+  def Dispatch(self, args):
+    """Dispatches a string command to a method."""
+    if len(args) < 1:
+      raise Exception("Not enough arguments")
+
+    method = "Exec%s" % self._CommandifyName(args[0])
+    getattr(self, method)(*args[1:])
+
+  def _CommandifyName(self, name_string):
+    """Transforms a tool name like copy-info-plist to CopyInfoPlist"""
+    return name_string.title().replace('-', '')
+
+  def ExecFlock(self, lockfile, *cmd_list):
+    """Emulates the most basic behavior of Linux's flock(1)."""
+    # Rely on exception handling to report errors.
+    # Note that the stock python on SunOS has a bug
+    # where fcntl.flock(fd, LOCK_EX) always fails
+    # with EBADF, that's why we use this F_SETLK
+    # hack instead.
+    fd = os.open(lockfile, os.O_WRONLY|os.O_NOCTTY|os.O_CREAT, 0666)
+    op = struct.pack('hhllhhl', fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0)
+    fcntl.fcntl(fd, fcntl.F_SETLK, op)
+    return subprocess.call(cmd_list)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/gyp/pylib/gyp/generator/__init__.py b/gyp/pylib/gyp/generator/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/pylib/gyp/generator/analyzer.py b/gyp/pylib/gyp/generator/analyzer.py
new file mode 100644 (file)
index 0000000..8a8ac70
--- /dev/null
@@ -0,0 +1,454 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+This script is intended for use as a GYP_GENERATOR. It takes as input (by way of
+the generator flag config_path) the path of a json file that dictates the files
+and targets to search for. The following keys are supported:
+files: list of paths (relative) of the files to search for.
+targets: list of targets to search for. The target names are unqualified.
+
+The following is output:
+error: only supplied if there is an error.
+warning: only supplied if there is a warning.
+targets: the set of targets passed in via targets that either directly or
+  indirectly depend upon the set of paths supplied in files.
+status: indicates if any of the supplied files matched at least one target.
+
+If the generator flag analyzer_output_path is specified, output is written
+there. Otherwise output is written to stdout.
+"""
+
+import gyp.common
+import gyp.ninja_syntax as ninja_syntax
+import json
+import os
+import posixpath
+import sys
+
+debug = False
+
+found_dependency_string = 'Found dependency'
+no_dependency_string = 'No dependencies'
+
+# MatchStatus is used indicate if and how a target depends upon the supplied
+# sources.
+# The target's sources contain one of the supplied paths.
+MATCH_STATUS_MATCHES = 1
+# The target has a dependency on another target that contains one of the
+# supplied paths.
+MATCH_STATUS_MATCHES_BY_DEPENDENCY = 2
+# The target's sources weren't in the supplied paths and none of the target's
+# dependencies depend upon a target that matched.
+MATCH_STATUS_DOESNT_MATCH = 3
+# The target doesn't contain the source, but the dependent targets have not yet
+# been visited to determine a more specific status yet.
+MATCH_STATUS_TBD = 4
+
+generator_supports_multiple_toolsets = True
+
+generator_wants_static_library_dependencies_adjusted = False
+
+generator_default_variables = {
+}
+for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR',
+                'LIB_DIR', 'SHARED_LIB_DIR']:
+  generator_default_variables[dirname] = '!!!'
+
+for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
+               'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
+               'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
+               'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
+               'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
+               'CONFIGURATION_NAME']:
+  generator_default_variables[unused] = ''
+
+
+def _ToGypPath(path):
+  """Converts a path to the format used by gyp."""
+  if os.sep == '\\' and os.altsep == '/':
+    return path.replace('\\', '/')
+  return path
+
+
+def _ResolveParent(path, base_path_components):
+  """Resolves |path|, which starts with at least one '../'. Returns an empty
+  string if the path shouldn't be considered. See _AddSources() for a
+  description of |base_path_components|."""
+  depth = 0
+  while path.startswith('../'):
+    depth += 1
+    path = path[3:]
+  # Relative includes may go outside the source tree. For example, an action may
+  # have inputs in /usr/include, which are not in the source tree.
+  if depth > len(base_path_components):
+    return ''
+  if depth == len(base_path_components):
+    return path
+  return '/'.join(base_path_components[0:len(base_path_components) - depth]) + \
+      '/' + path
+
+
+def _AddSources(sources, base_path, base_path_components, result):
+  """Extracts valid sources from |sources| and adds them to |result|. Each
+  source file is relative to |base_path|, but may contain '..'. To make
+  resolving '..' easier |base_path_components| contains each of the
+  directories in |base_path|. Additionally each source may contain variables.
+  Such sources are ignored as it is assumed dependencies on them are expressed
+  and tracked in some other means."""
+  # NOTE: gyp paths are always posix style.
+  for source in sources:
+    if not len(source) or source.startswith('!!!') or source.startswith('$'):
+      continue
+    # variable expansion may lead to //.
+    org_source = source
+    source = source[0] + source[1:].replace('//', '/')
+    if source.startswith('../'):
+      source = _ResolveParent(source, base_path_components)
+      if len(source):
+        result.append(source)
+      continue
+    result.append(base_path + source)
+    if debug:
+      print 'AddSource', org_source, result[len(result) - 1]
+
+
+def _ExtractSourcesFromAction(action, base_path, base_path_components,
+                              results):
+  if 'inputs' in action:
+    _AddSources(action['inputs'], base_path, base_path_components, results)
+
+
+def _ExtractSources(target, target_dict, toplevel_dir):
+  # |target| is either absolute or relative and in the format of the OS. Gyp
+  # source paths are always posix. Convert |target| to a posix path relative to
+  # |toplevel_dir_|. This is done to make it easy to build source paths.
+  base_path = _ToGypPath(target)
+  if base_path == toplevel_dir:
+    base_path = ''
+  elif base_path.startswith(toplevel_dir + '/'):
+    base_path = base_path[len(toplevel_dir) + len('/'):]
+  base_path = posixpath.dirname(base_path)
+  base_path_components = base_path.split('/')
+
+  # Add a trailing '/' so that _AddSources() can easily build paths.
+  if len(base_path):
+    base_path += '/'
+
+  if debug:
+    print 'ExtractSources', target, base_path
+
+  results = []
+  if 'sources' in target_dict:
+    _AddSources(target_dict['sources'], base_path, base_path_components,
+                results)
+  # Include the inputs from any actions. Any changes to these effect the
+  # resulting output.
+  if 'actions' in target_dict:
+    for action in target_dict['actions']:
+      _ExtractSourcesFromAction(action, base_path, base_path_components,
+                                results)
+  if 'rules' in target_dict:
+    for rule in target_dict['rules']:
+      _ExtractSourcesFromAction(rule, base_path, base_path_components, results)
+
+  return results
+
+
+class Target(object):
+  """Holds information about a particular target:
+  deps: set of the names of direct dependent targets.
+  match_staus: one of the MatchStatus values"""
+  def __init__(self):
+    self.deps = set()
+    self.match_status = MATCH_STATUS_TBD
+
+
+class Config(object):
+  """Details what we're looking for
+  look_for_dependency_only: if true only search for a target listing any of
+                            the files in files.
+  files: set of files to search for
+  targets: see file description for details"""
+  def __init__(self):
+    self.look_for_dependency_only = True
+    self.files = []
+    self.targets = []
+
+  def Init(self, params):
+    """Initializes Config. This is a separate method as it may raise an
+    exception if there is a parse error."""
+    generator_flags = params.get('generator_flags', {})
+    # TODO(sky): nuke file_path and look_for_dependency_only once migrate
+    # recipes.
+    file_path = generator_flags.get('file_path', None)
+    if file_path:
+      self._InitFromFilePath(file_path)
+      return
+
+    # If |file_path| wasn't specified then we look for config_path.
+    # TODO(sky): always look for config_path once migrated recipes.
+    config_path = generator_flags.get('config_path', None)
+    if not config_path:
+      return
+    self.look_for_dependency_only = False
+    try:
+      f = open(config_path, 'r')
+      config = json.load(f)
+      f.close()
+    except IOError:
+      raise Exception('Unable to open file ' + config_path)
+    except ValueError as e:
+      raise Exception('Unable to parse config file ' + config_path + str(e))
+    if not isinstance(config, dict):
+      raise Exception('config_path must be a JSON file containing a dictionary')
+    self.files = config.get('files', [])
+    # Coalesce duplicates
+    self.targets = list(set(config.get('targets', [])))
+
+  def _InitFromFilePath(self, file_path):
+    try:
+      f = open(file_path, 'r')
+      for file_name in f:
+        if file_name.endswith('\n'):
+          file_name = file_name[0:len(file_name) - 1]
+          if len(file_name):
+            self.files.append(file_name)
+      f.close()
+    except IOError:
+      raise Exception('Unable to open file', file_path)
+
+
+def _WasBuildFileModified(build_file, data, files):
+  """Returns true if the build file |build_file| is either in |files| or
+  one of the files included by |build_file| is in |files|."""
+  if _ToGypPath(build_file) in files:
+    if debug:
+      print 'gyp file modified', build_file
+    return True
+
+  # First element of included_files is the file itself.
+  if len(data[build_file]['included_files']) <= 1:
+    return False
+
+  for include_file in data[build_file]['included_files'][1:]:
+    # |included_files| are relative to the directory of the |build_file|.
+    rel_include_file = \
+        _ToGypPath(gyp.common.UnrelativePath(include_file, build_file))
+    if rel_include_file in files:
+      if debug:
+        print 'included gyp file modified, gyp_file=', build_file, \
+            'included file=', rel_include_file
+      return True
+  return False
+
+
+def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files):
+  """Generates a dictionary with the key the name of a target and the value a
+  Target. |toplevel_dir| is the root of the source tree. If the sources of
+  a target match that of |files|, then |target.matched| is set to True.
+  This returns a tuple of the dictionary and whether at least one target's
+  sources listed one of the paths in |files|."""
+  targets = {}
+
+  # Queue of targets to visit.
+  targets_to_visit = target_list[:]
+
+  matched = False
+
+  # Maps from build file to a boolean indicating whether the build file is in
+  # |files|.
+  build_file_in_files = {}
+
+  while len(targets_to_visit) > 0:
+    target_name = targets_to_visit.pop()
+    if target_name in targets:
+      continue
+
+    target = Target()
+    targets[target_name] = target
+
+    build_file = gyp.common.ParseQualifiedTarget(target_name)[0]
+    if not build_file in build_file_in_files:
+      build_file_in_files[build_file] = \
+          _WasBuildFileModified(build_file, data, files)
+
+    # If a build file (or any of its included files) is modified we assume all
+    # targets in the file are modified.
+    if build_file_in_files[build_file]:
+      target.match_status = MATCH_STATUS_MATCHES
+      matched = True
+    else:
+      sources = _ExtractSources(target_name, target_dicts[target_name],
+                                toplevel_dir)
+      for source in sources:
+        if source in files:
+          target.match_status = MATCH_STATUS_MATCHES
+          matched = True
+          break
+
+    for dep in target_dicts[target_name].get('dependencies', []):
+      targets[target_name].deps.add(dep)
+      targets_to_visit.append(dep)
+
+  return targets, matched
+
+
+def _GetUnqualifiedToQualifiedMapping(all_targets, to_find):
+  """Returns a mapping (dictionary) from unqualified name to qualified name for
+  all the targets in |to_find|."""
+  result = {}
+  if not to_find:
+    return result
+  to_find = set(to_find)
+  for target_name in all_targets.keys():
+    extracted = gyp.common.ParseQualifiedTarget(target_name)
+    if len(extracted) > 1 and extracted[1] in to_find:
+      to_find.remove(extracted[1])
+      result[extracted[1]] = target_name
+      if not to_find:
+        return result
+  return result
+
+
+def _DoesTargetDependOn(target, all_targets):
+  """Returns true if |target| or any of its dependencies matches the supplied
+  set of paths. This updates |matches| of the Targets as it recurses.
+  target: the Target to look for.
+  all_targets: mapping from target name to Target.
+  matching_targets: set of targets looking for."""
+  if target.match_status == MATCH_STATUS_DOESNT_MATCH:
+    return False
+  if target.match_status == MATCH_STATUS_MATCHES or \
+      target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY:
+    return True
+  for dep_name in target.deps:
+    dep_target = all_targets[dep_name]
+    if _DoesTargetDependOn(dep_target, all_targets):
+      dep_target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
+      return True
+    dep_target.match_status = MATCH_STATUS_DOESNT_MATCH
+  return False
+
+
+def _GetTargetsDependingOn(all_targets, possible_targets):
+  """Returns the list of targets in |possible_targets| that depend (either
+  directly on indirectly) on the matched files.
+  all_targets: mapping from target name to Target.
+  possible_targets: targets to search from."""
+  found = []
+  for target in possible_targets:
+    if _DoesTargetDependOn(all_targets[target], all_targets):
+      # possible_targets was initially unqualified, keep it unqualified.
+      found.append(gyp.common.ParseQualifiedTarget(target)[1])
+  return found
+
+
+def _WriteOutput(params, **values):
+  """Writes the output, either to stdout or a file is specified."""
+  output_path = params.get('generator_flags', {}).get(
+      'analyzer_output_path', None)
+  if not output_path:
+    print json.dumps(values)
+    return
+  try:
+    f = open(output_path, 'w')
+    f.write(json.dumps(values) + '\n')
+    f.close()
+  except IOError as e:
+    print 'Error writing to output file', output_path, str(e)
+
+
+def CalculateVariables(default_variables, params):
+  """Calculate additional variables for use in the build (called by gyp)."""
+  flavor = gyp.common.GetFlavor(params)
+  if flavor == 'mac':
+    default_variables.setdefault('OS', 'mac')
+  elif flavor == 'win':
+    default_variables.setdefault('OS', 'win')
+    # Copy additional generator configuration data from VS, which is shared
+    # by the Windows Ninja generator.
+    import gyp.generator.msvs as msvs_generator
+    generator_additional_non_configuration_keys = getattr(msvs_generator,
+        'generator_additional_non_configuration_keys', [])
+    generator_additional_path_sections = getattr(msvs_generator,
+        'generator_additional_path_sections', [])
+
+    gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
+  else:
+    operating_system = flavor
+    if flavor == 'android':
+      operating_system = 'linux'  # Keep this legacy behavior for now.
+    default_variables.setdefault('OS', operating_system)
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  """Called by gyp as the final stage. Outputs results."""
+  config = Config()
+  try:
+    config.Init(params)
+    if not config.files:
+      if config.look_for_dependency_only:
+        print 'Must specify files to analyze via file_path generator flag'
+        return
+      raise Exception('Must specify files to analyze via config_path generator '
+                      'flag')
+
+    toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
+    if debug:
+      print 'toplevel_dir', toplevel_dir
+
+    matched = False
+    matched_include = False
+
+    # If one of the modified files is an include file then everything is
+    # affected.
+    if params['options'].includes:
+      for include in params['options'].includes:
+        if _ToGypPath(include) in config.files:
+          if debug:
+            print 'include path modified', include
+          matched_include = True
+          matched = True
+          break
+
+    if not matched:
+      all_targets, matched = _GenerateTargets(data, target_list, target_dicts,
+                                              toplevel_dir,
+                                              frozenset(config.files))
+
+    # Set of targets that refer to one of the files.
+    if config.look_for_dependency_only:
+      print found_dependency_string if matched else no_dependency_string
+      return
+
+    warning = None
+    if matched_include:
+      output_targets = config.targets
+    elif matched:
+      unqualified_mapping = _GetUnqualifiedToQualifiedMapping(
+          all_targets, config.targets)
+      if len(unqualified_mapping) != len(config.targets):
+        not_found = []
+        for target in config.targets:
+          if not target in unqualified_mapping:
+            not_found.append(target)
+        warning = 'Unable to find all targets: ' + str(not_found)
+      qualified_targets = []
+      for target in config.targets:
+        if target in unqualified_mapping:
+          qualified_targets.append(unqualified_mapping[target])
+      output_targets = _GetTargetsDependingOn(all_targets, qualified_targets)
+    else:
+      output_targets = []
+
+    result_dict = { 'targets': output_targets,
+                    'status': found_dependency_string if matched else
+                              no_dependency_string }
+    if warning:
+      result_dict['warning'] = warning
+    _WriteOutput(params, **result_dict)
+
+  except Exception as e:
+    _WriteOutput(params, error=str(e))
diff --git a/gyp/pylib/gyp/generator/android.py b/gyp/pylib/gyp/generator/android.py
new file mode 100644 (file)
index 0000000..5d8c74e
--- /dev/null
@@ -0,0 +1,1093 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Notes:
+#
+# This generates makefiles suitable for inclusion into the Android build system
+# via an Android.mk file. It is based on make.py, the standard makefile
+# generator.
+#
+# The code below generates a separate .mk file for each target, but
+# all are sourced by the top-level GypAndroid.mk.  This means that all
+# variables in .mk-files clobber one another, and furthermore that any
+# variables set potentially clash with other Android build system variables.
+# Try to avoid setting global variables where possible.
+
+import gyp
+import gyp.common
+import gyp.generator.make as make  # Reuse global functions from make backend.
+import os
+import re
+import subprocess
+
+generator_default_variables = {
+  'OS': 'android',
+  'EXECUTABLE_PREFIX': '',
+  'EXECUTABLE_SUFFIX': '',
+  'STATIC_LIB_PREFIX': 'lib',
+  'SHARED_LIB_PREFIX': 'lib',
+  'STATIC_LIB_SUFFIX': '.a',
+  'SHARED_LIB_SUFFIX': '.so',
+  'INTERMEDIATE_DIR': '$(gyp_intermediate_dir)',
+  'SHARED_INTERMEDIATE_DIR': '$(gyp_shared_intermediate_dir)',
+  'PRODUCT_DIR': '$(gyp_shared_intermediate_dir)',
+  'SHARED_LIB_DIR': '$(builddir)/lib.$(TOOLSET)',
+  'LIB_DIR': '$(obj).$(TOOLSET)',
+  'RULE_INPUT_ROOT': '%(INPUT_ROOT)s',  # This gets expanded by Python.
+  'RULE_INPUT_DIRNAME': '%(INPUT_DIRNAME)s',  # This gets expanded by Python.
+  'RULE_INPUT_PATH': '$(RULE_SOURCES)',
+  'RULE_INPUT_EXT': '$(suffix $<)',
+  'RULE_INPUT_NAME': '$(notdir $<)',
+  'CONFIGURATION_NAME': '$(GYP_CONFIGURATION)',
+}
+
+# Make supports multiple toolsets
+generator_supports_multiple_toolsets = True
+
+
+# Generator-specific gyp specs.
+generator_additional_non_configuration_keys = [
+    # Boolean to declare that this target does not want its name mangled.
+    'android_unmangled_name',
+]
+generator_additional_path_sections = []
+generator_extra_sources_for_rules = []
+
+
+ALL_MODULES_FOOTER = """\
+# "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
+# all the included sub-makefiles. This is just here to clarify.
+gyp_all_modules:
+"""
+
+header = """\
+# This file is generated by gyp; do not edit.
+
+"""
+
+android_standard_include_paths = set([
+    # JNI_H_INCLUDE in build/core/binary.mk
+    'dalvik/libnativehelper/include/nativehelper',
+    # from SRC_HEADERS in build/core/config.mk
+    'system/core/include',
+    'hardware/libhardware/include',
+    'hardware/libhardware_legacy/include',
+    'hardware/ril/include',
+    'dalvik/libnativehelper/include',
+    'frameworks/native/include',
+    'frameworks/native/opengl/include',
+    'frameworks/base/include',
+    'frameworks/base/opengl/include',
+    'frameworks/base/native/include',
+    'external/skia/include',
+    # TARGET_C_INCLUDES in build/core/combo/TARGET_linux-arm.mk
+    'bionic/libc/arch-arm/include',
+    'bionic/libc/include',
+    'bionic/libstdc++/include',
+    'bionic/libc/kernel/common',
+    'bionic/libc/kernel/arch-arm',
+    'bionic/libm/include',
+    'bionic/libm/include/arm',
+    'bionic/libthread_db/include',
+    ])
+
+
+# Map gyp target types to Android module classes.
+MODULE_CLASSES = {
+    'static_library': 'STATIC_LIBRARIES',
+    'shared_library': 'SHARED_LIBRARIES',
+    'executable': 'EXECUTABLES',
+}
+
+
+def IsCPPExtension(ext):
+  return make.COMPILABLE_EXTENSIONS.get(ext) == 'cxx'
+
+
+def Sourceify(path):
+  """Convert a path to its source directory form. The Android backend does not
+     support options.generator_output, so this function is a noop."""
+  return path
+
+
+# Map from qualified target to path to output.
+# For Android, the target of these maps is a tuple ('static', 'modulename'),
+# ('dynamic', 'modulename'), or ('path', 'some/path') instead of a string,
+# since we link by module.
+target_outputs = {}
+# Map from qualified target to any linkable output.  A subset
+# of target_outputs.  E.g. when mybinary depends on liba, we want to
+# include liba in the linker line; when otherbinary depends on
+# mybinary, we just want to build mybinary first.
+target_link_deps = {}
+
+
+class AndroidMkWriter(object):
+  """AndroidMkWriter packages up the writing of one target-specific Android.mk.
+
+  Its only real entry point is Write(), and is mostly used for namespacing.
+  """
+
+  def __init__(self, android_top_dir):
+    self.android_top_dir = android_top_dir
+
+  def Write(self, qualified_target, relative_target, base_path, output_filename,
+            spec, configs, part_of_all, write_alias_target):
+    """The main entry point: writes a .mk file for a single target.
+
+    Arguments:
+      qualified_target: target we're generating
+      relative_target: qualified target name relative to the root
+      base_path: path relative to source root we're building in, used to resolve
+                 target-relative paths
+      output_filename: output .mk file name to write
+      spec, configs: gyp info
+      part_of_all: flag indicating this target is part of 'all'
+      write_alias_target: flag indicating whether to create short aliases for
+                          this target
+    """
+    gyp.common.EnsureDirExists(output_filename)
+
+    self.fp = open(output_filename, 'w')
+
+    self.fp.write(header)
+
+    self.qualified_target = qualified_target
+    self.relative_target = relative_target
+    self.path = base_path
+    self.target = spec['target_name']
+    self.type = spec['type']
+    self.toolset = spec['toolset']
+
+    deps, link_deps = self.ComputeDeps(spec)
+
+    # Some of the generation below can add extra output, sources, or
+    # link dependencies.  All of the out params of the functions that
+    # follow use names like extra_foo.
+    extra_outputs = []
+    extra_sources = []
+
+    self.android_class = MODULE_CLASSES.get(self.type, 'GYP')
+    self.android_module = self.ComputeAndroidModule(spec)
+    (self.android_stem, self.android_suffix) = self.ComputeOutputParts(spec)
+    self.output = self.output_binary = self.ComputeOutput(spec)
+
+    # Standard header.
+    self.WriteLn('include $(CLEAR_VARS)\n')
+
+    # Module class and name.
+    self.WriteLn('LOCAL_MODULE_CLASS := ' + self.android_class)
+    self.WriteLn('LOCAL_MODULE := ' + self.android_module)
+    # Only emit LOCAL_MODULE_STEM if it's different to LOCAL_MODULE.
+    # The library module classes fail if the stem is set. ComputeOutputParts
+    # makes sure that stem == modulename in these cases.
+    if self.android_stem != self.android_module:
+      self.WriteLn('LOCAL_MODULE_STEM := ' + self.android_stem)
+    self.WriteLn('LOCAL_MODULE_SUFFIX := ' + self.android_suffix)
+    self.WriteLn('LOCAL_MODULE_TAGS := optional')
+    if self.toolset == 'host':
+      self.WriteLn('LOCAL_IS_HOST_MODULE := true')
+    else:
+      self.WriteLn('LOCAL_MODULE_TARGET_ARCH := '
+                   '$(TARGET_$(GYP_VAR_PREFIX)ARCH)')
+
+    # Grab output directories; needed for Actions and Rules.
+    if self.toolset == 'host':
+      self.WriteLn('gyp_intermediate_dir := '
+                   '$(call local-intermediates-dir)')
+    else:
+      self.WriteLn('gyp_intermediate_dir := '
+                   '$(call local-intermediates-dir,,$(GYP_VAR_PREFIX))')
+    self.WriteLn('gyp_shared_intermediate_dir := '
+                 '$(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))')
+    self.WriteLn()
+
+    # List files this target depends on so that actions/rules/copies/sources
+    # can depend on the list.
+    # TODO: doesn't pull in things through transitive link deps; needed?
+    target_dependencies = [x[1] for x in deps if x[0] == 'path']
+    self.WriteLn('# Make sure our deps are built first.')
+    self.WriteList(target_dependencies, 'GYP_TARGET_DEPENDENCIES',
+                   local_pathify=True)
+
+    # Actions must come first, since they can generate more OBJs for use below.
+    if 'actions' in spec:
+      self.WriteActions(spec['actions'], extra_sources, extra_outputs)
+
+    # Rules must be early like actions.
+    if 'rules' in spec:
+      self.WriteRules(spec['rules'], extra_sources, extra_outputs)
+
+    if 'copies' in spec:
+      self.WriteCopies(spec['copies'], extra_outputs)
+
+    # GYP generated outputs.
+    self.WriteList(extra_outputs, 'GYP_GENERATED_OUTPUTS', local_pathify=True)
+
+    # Set LOCAL_ADDITIONAL_DEPENDENCIES so that Android's build rules depend
+    # on both our dependency targets and our generated files.
+    self.WriteLn('# Make sure our deps and generated files are built first.')
+    self.WriteLn('LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) '
+                 '$(GYP_GENERATED_OUTPUTS)')
+    self.WriteLn()
+
+    # Sources.
+    if spec.get('sources', []) or extra_sources:
+      self.WriteSources(spec, configs, extra_sources)
+
+    self.WriteTarget(spec, configs, deps, link_deps, part_of_all,
+                     write_alias_target)
+
+    # Update global list of target outputs, used in dependency tracking.
+    target_outputs[qualified_target] = ('path', self.output_binary)
+
+    # Update global list of link dependencies.
+    if self.type == 'static_library':
+      target_link_deps[qualified_target] = ('static', self.android_module)
+    elif self.type == 'shared_library':
+      target_link_deps[qualified_target] = ('shared', self.android_module)
+
+    self.fp.close()
+    return self.android_module
+
+
+  def WriteActions(self, actions, extra_sources, extra_outputs):
+    """Write Makefile code for any 'actions' from the gyp input.
+
+    extra_sources: a list that will be filled in with newly generated source
+                   files, if any
+    extra_outputs: a list that will be filled in with any outputs of these
+                   actions (used to make other pieces dependent on these
+                   actions)
+    """
+    for action in actions:
+      name = make.StringToMakefileVariable('%s_%s' % (self.relative_target,
+                                                      action['action_name']))
+      self.WriteLn('### Rules for action "%s":' % action['action_name'])
+      inputs = action['inputs']
+      outputs = action['outputs']
+
+      # Build up a list of outputs.
+      # Collect the output dirs we'll need.
+      dirs = set()
+      for out in outputs:
+        if not out.startswith('$'):
+          print ('WARNING: Action for target "%s" writes output to local path '
+                 '"%s".' % (self.target, out))
+        dir = os.path.split(out)[0]
+        if dir:
+          dirs.add(dir)
+      if int(action.get('process_outputs_as_sources', False)):
+        extra_sources += outputs
+
+      # Prepare the actual command.
+      command = gyp.common.EncodePOSIXShellList(action['action'])
+      if 'message' in action:
+        quiet_cmd = 'Gyp action: %s ($@)' % action['message']
+      else:
+        quiet_cmd = 'Gyp action: %s ($@)' % name
+      if len(dirs) > 0:
+        command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
+
+      cd_action = 'cd $(gyp_local_path)/%s; ' % self.path
+      command = cd_action + command
+
+      # The makefile rules are all relative to the top dir, but the gyp actions
+      # are defined relative to their containing dir.  This replaces the gyp_*
+      # variables for the action rule with an absolute version so that the
+      # output goes in the right place.
+      # Only write the gyp_* rules for the "primary" output (:1);
+      # it's superfluous for the "extra outputs", and this avoids accidentally
+      # writing duplicate dummy rules for those outputs.
+      main_output = make.QuoteSpaces(self.LocalPathify(outputs[0]))
+      self.WriteLn('%s: gyp_local_path := $(LOCAL_PATH)' % main_output)
+      self.WriteLn('%s: gyp_var_prefix := $(GYP_VAR_PREFIX)' % main_output)
+      self.WriteLn('%s: gyp_intermediate_dir := '
+                   '$(abspath $(gyp_intermediate_dir))' % main_output)
+      self.WriteLn('%s: gyp_shared_intermediate_dir := '
+                   '$(abspath $(gyp_shared_intermediate_dir))' % main_output)
+
+      # Android's envsetup.sh adds a number of directories to the path including
+      # the built host binary directory. This causes actions/rules invoked by
+      # gyp to sometimes use these instead of system versions, e.g. bison.
+      # The built host binaries may not be suitable, and can cause errors.
+      # So, we remove them from the PATH using the ANDROID_BUILD_PATHS variable
+      # set by envsetup.
+      self.WriteLn('%s: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))'
+                   % main_output)
+
+      # Don't allow spaces in input/output filenames, but make an exception for
+      # filenames which start with '$(' since it's okay for there to be spaces
+      # inside of make function/macro invocations.
+      for input in inputs:
+        if not input.startswith('$(') and ' ' in input:
+          raise gyp.common.GypError(
+              'Action input filename "%s" in target %s contains a space' %
+              (input, self.target))
+      for output in outputs:
+        if not output.startswith('$(') and ' ' in output:
+          raise gyp.common.GypError(
+              'Action output filename "%s" in target %s contains a space' %
+              (output, self.target))
+
+      self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES)' %
+                   (main_output, ' '.join(map(self.LocalPathify, inputs))))
+      self.WriteLn('\t@echo "%s"' % quiet_cmd)
+      self.WriteLn('\t$(hide)%s\n' % command)
+      for output in outputs[1:]:
+        # Make each output depend on the main output, with an empty command
+        # to force make to notice that the mtime has changed.
+        self.WriteLn('%s: %s ;' % (self.LocalPathify(output), main_output))
+
+      extra_outputs += outputs
+      self.WriteLn()
+
+    self.WriteLn()
+
+
+  def WriteRules(self, rules, extra_sources, extra_outputs):
+    """Write Makefile code for any 'rules' from the gyp input.
+
+    extra_sources: a list that will be filled in with newly generated source
+                   files, if any
+    extra_outputs: a list that will be filled in with any outputs of these
+                   rules (used to make other pieces dependent on these rules)
+    """
+    if len(rules) == 0:
+      return
+
+    for rule in rules:
+      if len(rule.get('rule_sources', [])) == 0:
+        continue
+      name = make.StringToMakefileVariable('%s_%s' % (self.relative_target,
+                                                      rule['rule_name']))
+      self.WriteLn('\n### Generated for rule "%s":' % name)
+      self.WriteLn('# "%s":' % rule)
+
+      inputs = rule.get('inputs')
+      for rule_source in rule.get('rule_sources', []):
+        (rule_source_dirname, rule_source_basename) = os.path.split(rule_source)
+        (rule_source_root, rule_source_ext) = \
+            os.path.splitext(rule_source_basename)
+
+        outputs = [self.ExpandInputRoot(out, rule_source_root,
+                                        rule_source_dirname)
+                   for out in rule['outputs']]
+
+        dirs = set()
+        for out in outputs:
+          if not out.startswith('$'):
+            print ('WARNING: Rule for target %s writes output to local path %s'
+                   % (self.target, out))
+          dir = os.path.dirname(out)
+          if dir:
+            dirs.add(dir)
+        extra_outputs += outputs
+        if int(rule.get('process_outputs_as_sources', False)):
+          extra_sources.extend(outputs)
+
+        components = []
+        for component in rule['action']:
+          component = self.ExpandInputRoot(component, rule_source_root,
+                                           rule_source_dirname)
+          if '$(RULE_SOURCES)' in component:
+            component = component.replace('$(RULE_SOURCES)',
+                                          rule_source)
+          components.append(component)
+
+        command = gyp.common.EncodePOSIXShellList(components)
+        cd_action = 'cd $(gyp_local_path)/%s; ' % self.path
+        command = cd_action + command
+        if dirs:
+          command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
+
+        # We set up a rule to build the first output, and then set up
+        # a rule for each additional output to depend on the first.
+        outputs = map(self.LocalPathify, outputs)
+        main_output = outputs[0]
+        self.WriteLn('%s: gyp_local_path := $(LOCAL_PATH)' % main_output)
+        self.WriteLn('%s: gyp_var_prefix := $(GYP_VAR_PREFIX)' % main_output)
+        self.WriteLn('%s: gyp_intermediate_dir := '
+                     '$(abspath $(gyp_intermediate_dir))' % main_output)
+        self.WriteLn('%s: gyp_shared_intermediate_dir := '
+                     '$(abspath $(gyp_shared_intermediate_dir))' % main_output)
+
+        # See explanation in WriteActions.
+        self.WriteLn('%s: export PATH := '
+                     '$(subst $(ANDROID_BUILD_PATHS),,$(PATH))' % main_output)
+
+        main_output_deps = self.LocalPathify(rule_source)
+        if inputs:
+          main_output_deps += ' '
+          main_output_deps += ' '.join([self.LocalPathify(f) for f in inputs])
+
+        self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES)' %
+                     (main_output, main_output_deps))
+        self.WriteLn('\t%s\n' % command)
+        for output in outputs[1:]:
+          # Make each output depend on the main output, with an empty command
+          # to force make to notice that the mtime has changed.
+          self.WriteLn('%s: %s ;' % (output, main_output))
+        self.WriteLn()
+
+    self.WriteLn()
+
+
+  def WriteCopies(self, copies, extra_outputs):
+    """Write Makefile code for any 'copies' from the gyp input.
+
+    extra_outputs: a list that will be filled in with any outputs of this action
+                   (used to make other pieces dependent on this action)
+    """
+    self.WriteLn('### Generated for copy rule.')
+
+    variable = make.StringToMakefileVariable(self.relative_target + '_copies')
+    outputs = []
+    for copy in copies:
+      for path in copy['files']:
+        # The Android build system does not allow generation of files into the
+        # source tree. The destination should start with a variable, which will
+        # typically be $(gyp_intermediate_dir) or
+        # $(gyp_shared_intermediate_dir). Note that we can't use an assertion
+        # because some of the gyp tests depend on this.
+        if not copy['destination'].startswith('$'):
+          print ('WARNING: Copy rule for target %s writes output to '
+                 'local path %s' % (self.target, copy['destination']))
+
+        # LocalPathify() calls normpath, stripping trailing slashes.
+        path = Sourceify(self.LocalPathify(path))
+        filename = os.path.split(path)[1]
+        output = Sourceify(self.LocalPathify(os.path.join(copy['destination'],
+                                                          filename)))
+
+        self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES) | $(ACP)' %
+                     (output, path))
+        self.WriteLn('\t@echo Copying: $@')
+        self.WriteLn('\t$(hide) mkdir -p $(dir $@)')
+        self.WriteLn('\t$(hide) $(ACP) -rpf $< $@')
+        self.WriteLn()
+        outputs.append(output)
+    self.WriteLn('%s = %s' % (variable,
+                              ' '.join(map(make.QuoteSpaces, outputs))))
+    extra_outputs.append('$(%s)' % variable)
+    self.WriteLn()
+
+
+  def WriteSourceFlags(self, spec, configs):
+    """Write out the flags and include paths used to compile source files for
+    the current target.
+
+    Args:
+      spec, configs: input from gyp.
+    """
+    for configname, config in sorted(configs.iteritems()):
+      extracted_includes = []
+
+      self.WriteLn('\n# Flags passed to both C and C++ files.')
+      cflags, includes_from_cflags = self.ExtractIncludesFromCFlags(
+          config.get('cflags', []) + config.get('cflags_c', []))
+      extracted_includes.extend(includes_from_cflags)
+      self.WriteList(cflags, 'MY_CFLAGS_%s' % configname)
+
+      self.WriteList(config.get('defines'), 'MY_DEFS_%s' % configname,
+                     prefix='-D', quoter=make.EscapeCppDefine)
+
+      self.WriteLn('\n# Include paths placed before CFLAGS/CPPFLAGS')
+      includes = list(config.get('include_dirs', []))
+      includes.extend(extracted_includes)
+      includes = map(Sourceify, map(self.LocalPathify, includes))
+      includes = self.NormalizeIncludePaths(includes)
+      self.WriteList(includes, 'LOCAL_C_INCLUDES_%s' % configname)
+
+      self.WriteLn('\n# Flags passed to only C++ (and not C) files.')
+      self.WriteList(config.get('cflags_cc'), 'LOCAL_CPPFLAGS_%s' % configname)
+
+    self.WriteLn('\nLOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) '
+                 '$(MY_DEFS_$(GYP_CONFIGURATION))')
+    # Undefine ANDROID for host modules
+    # TODO: the source code should not use macro ANDROID to tell if it's host
+    # or target module.
+    if self.toolset == 'host':
+      self.WriteLn('# Undefine ANDROID for host modules')
+      self.WriteLn('LOCAL_CFLAGS += -UANDROID')
+    self.WriteLn('LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) '
+                                     '$(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))')
+    self.WriteLn('LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))')
+    # Android uses separate flags for assembly file invocations, but gyp expects
+    # the same CFLAGS to be applied:
+    self.WriteLn('LOCAL_ASFLAGS := $(LOCAL_CFLAGS)')
+
+
+  def WriteSources(self, spec, configs, extra_sources):
+    """Write Makefile code for any 'sources' from the gyp input.
+    These are source files necessary to build the current target.
+    We need to handle shared_intermediate directory source files as
+    a special case by copying them to the intermediate directory and
+    treating them as a genereated sources. Otherwise the Android build
+    rules won't pick them up.
+
+    Args:
+      spec, configs: input from gyp.
+      extra_sources: Sources generated from Actions or Rules.
+    """
+    sources = filter(make.Compilable, spec.get('sources', []))
+    generated_not_sources = [x for x in extra_sources if not make.Compilable(x)]
+    extra_sources = filter(make.Compilable, extra_sources)
+
+    # Determine and output the C++ extension used by these sources.
+    # We simply find the first C++ file and use that extension.
+    all_sources = sources + extra_sources
+    local_cpp_extension = '.cpp'
+    for source in all_sources:
+      (root, ext) = os.path.splitext(source)
+      if IsCPPExtension(ext):
+        local_cpp_extension = ext
+        break
+    if local_cpp_extension != '.cpp':
+      self.WriteLn('LOCAL_CPP_EXTENSION := %s' % local_cpp_extension)
+
+    # We need to move any non-generated sources that are coming from the
+    # shared intermediate directory out of LOCAL_SRC_FILES and put them
+    # into LOCAL_GENERATED_SOURCES. We also need to move over any C++ files
+    # that don't match our local_cpp_extension, since Android will only
+    # generate Makefile rules for a single LOCAL_CPP_EXTENSION.
+    local_files = []
+    for source in sources:
+      (root, ext) = os.path.splitext(source)
+      if '$(gyp_shared_intermediate_dir)' in source:
+        extra_sources.append(source)
+      elif '$(gyp_intermediate_dir)' in source:
+        extra_sources.append(source)
+      elif IsCPPExtension(ext) and ext != local_cpp_extension:
+        extra_sources.append(source)
+      else:
+        local_files.append(os.path.normpath(os.path.join(self.path, source)))
+
+    # For any generated source, if it is coming from the shared intermediate
+    # directory then we add a Make rule to copy them to the local intermediate
+    # directory first. This is because the Android LOCAL_GENERATED_SOURCES
+    # must be in the local module intermediate directory for the compile rules
+    # to work properly. If the file has the wrong C++ extension, then we add
+    # a rule to copy that to intermediates and use the new version.
+    final_generated_sources = []
+    # If a source file gets copied, we still need to add the orginal source
+    # directory as header search path, for GCC searches headers in the
+    # directory that contains the source file by default.
+    origin_src_dirs = []
+    for source in extra_sources:
+      local_file = source
+      if not '$(gyp_intermediate_dir)/' in local_file:
+        basename = os.path.basename(local_file)
+        local_file = '$(gyp_intermediate_dir)/' + basename
+      (root, ext) = os.path.splitext(local_file)
+      if IsCPPExtension(ext) and ext != local_cpp_extension:
+        local_file = root + local_cpp_extension
+      if local_file != source:
+        self.WriteLn('%s: %s' % (local_file, self.LocalPathify(source)))
+        self.WriteLn('\tmkdir -p $(@D); cp $< $@')
+        origin_src_dirs.append(os.path.dirname(source))
+      final_generated_sources.append(local_file)
+
+    # We add back in all of the non-compilable stuff to make sure that the
+    # make rules have dependencies on them.
+    final_generated_sources.extend(generated_not_sources)
+    self.WriteList(final_generated_sources, 'LOCAL_GENERATED_SOURCES')
+
+    origin_src_dirs = gyp.common.uniquer(origin_src_dirs)
+    origin_src_dirs = map(Sourceify, map(self.LocalPathify, origin_src_dirs))
+    self.WriteList(origin_src_dirs, 'GYP_COPIED_SOURCE_ORIGIN_DIRS')
+
+    self.WriteList(local_files, 'LOCAL_SRC_FILES')
+
+    # Write out the flags used to compile the source; this must be done last
+    # so that GYP_COPIED_SOURCE_ORIGIN_DIRS can be used as an include path.
+    self.WriteSourceFlags(spec, configs)
+
+
+  def ComputeAndroidModule(self, spec):
+    """Return the Android module name used for a gyp spec.
+
+    We use the complete qualified target name to avoid collisions between
+    duplicate targets in different directories. We also add a suffix to
+    distinguish gyp-generated module names.
+    """
+
+    if int(spec.get('android_unmangled_name', 0)):
+      assert self.type != 'shared_library' or self.target.startswith('lib')
+      return self.target
+
+    if self.type == 'shared_library':
+      # For reasons of convention, the Android build system requires that all
+      # shared library modules are named 'libfoo' when generating -l flags.
+      prefix = 'lib_'
+    else:
+      prefix = ''
+
+    if spec['toolset'] == 'host':
+      suffix = '_$(TARGET_$(GYP_VAR_PREFIX)ARCH)_host_gyp'
+    else:
+      suffix = '_gyp'
+
+    if self.path:
+      middle = make.StringToMakefileVariable('%s_%s' % (self.path, self.target))
+    else:
+      middle = make.StringToMakefileVariable(self.target)
+
+    return ''.join([prefix, middle, suffix])
+
+
+  def ComputeOutputParts(self, spec):
+    """Return the 'output basename' of a gyp spec, split into filename + ext.
+
+    Android libraries must be named the same thing as their module name,
+    otherwise the linker can't find them, so product_name and so on must be
+    ignored if we are building a library, and the "lib" prepending is
+    not done for Android.
+    """
+    assert self.type != 'loadable_module' # TODO: not supported?
+
+    target = spec['target_name']
+    target_prefix = ''
+    target_ext = ''
+    if self.type == 'static_library':
+      target = self.ComputeAndroidModule(spec)
+      target_ext = '.a'
+    elif self.type == 'shared_library':
+      target = self.ComputeAndroidModule(spec)
+      target_ext = '.so'
+    elif self.type == 'none':
+      target_ext = '.stamp'
+    elif self.type != 'executable':
+      print ("ERROR: What output file should be generated?",
+             "type", self.type, "target", target)
+
+    if self.type != 'static_library' and self.type != 'shared_library':
+      target_prefix = spec.get('product_prefix', target_prefix)
+      target = spec.get('product_name', target)
+      product_ext = spec.get('product_extension')
+      if product_ext:
+        target_ext = '.' + product_ext
+
+    target_stem = target_prefix + target
+    return (target_stem, target_ext)
+
+
+  def ComputeOutputBasename(self, spec):
+    """Return the 'output basename' of a gyp spec.
+
+    E.g., the loadable module 'foobar' in directory 'baz' will produce
+      'libfoobar.so'
+    """
+    return ''.join(self.ComputeOutputParts(spec))
+
+
+  def ComputeOutput(self, spec):
+    """Return the 'output' (full output path) of a gyp spec.
+
+    E.g., the loadable module 'foobar' in directory 'baz' will produce
+      '$(obj)/baz/libfoobar.so'
+    """
+    if self.type == 'executable':
+      # We install host executables into shared_intermediate_dir so they can be
+      # run by gyp rules that refer to PRODUCT_DIR.
+      path = '$(gyp_shared_intermediate_dir)'
+    elif self.type == 'shared_library':
+      if self.toolset == 'host':
+        path = '$(HOST_OUT_INTERMEDIATE_LIBRARIES)'
+      else:
+        path = '$($(GYP_VAR_PREFIX)TARGET_OUT_INTERMEDIATE_LIBRARIES)'
+    else:
+      # Other targets just get built into their intermediate dir.
+      if self.toolset == 'host':
+        path = '$(call intermediates-dir-for,%s,%s,true)' % (self.android_class,
+                                                            self.android_module)
+      else:
+        path = ('$(call intermediates-dir-for,%s,%s,,,$(GYP_VAR_PREFIX))'
+                % (self.android_class, self.android_module))
+
+    assert spec.get('product_dir') is None # TODO: not supported?
+    return os.path.join(path, self.ComputeOutputBasename(spec))
+
+  def NormalizeIncludePaths(self, include_paths):
+    """ Normalize include_paths.
+    Convert absolute paths to relative to the Android top directory;
+    filter out include paths that are already brought in by the Android build
+    system.
+
+    Args:
+      include_paths: A list of unprocessed include paths.
+    Returns:
+      A list of normalized include paths.
+    """
+    normalized = []
+    for path in include_paths:
+      if path[0] == '/':
+        path = gyp.common.RelativePath(path, self.android_top_dir)
+
+      # Filter out the Android standard search path.
+      if path not in android_standard_include_paths:
+        normalized.append(path)
+    return normalized
+
+  def ExtractIncludesFromCFlags(self, cflags):
+    """Extract includes "-I..." out from cflags
+
+    Args:
+      cflags: A list of compiler flags, which may be mixed with "-I.."
+    Returns:
+      A tuple of lists: (clean_clfags, include_paths). "-I.." is trimmed.
+    """
+    clean_cflags = []
+    include_paths = []
+    for flag in cflags:
+      if flag.startswith('-I'):
+        include_paths.append(flag[2:])
+      else:
+        clean_cflags.append(flag)
+
+    return (clean_cflags, include_paths)
+
+  def ComputeAndroidLibraryModuleNames(self, libraries):
+    """Compute the Android module names from libraries, ie spec.get('libraries')
+
+    Args:
+      libraries: the value of spec.get('libraries')
+    Returns:
+      A tuple (static_lib_modules, dynamic_lib_modules)
+    """
+    static_lib_modules = []
+    dynamic_lib_modules = []
+    for libs in libraries:
+      # Libs can have multiple words.
+      for lib in libs.split():
+        # Filter the system libraries, which are added by default by the Android
+        # build system.
+        if (lib == '-lc' or lib == '-lstdc++' or lib == '-lm' or
+            lib.endswith('libgcc.a')):
+          continue
+        match = re.search(r'([^/]+)\.a$', lib)
+        if match:
+          static_lib_modules.append(match.group(1))
+          continue
+        match = re.search(r'([^/]+)\.so$', lib)
+        if match:
+          dynamic_lib_modules.append(match.group(1))
+          continue
+        # "-lstlport" -> libstlport
+        if lib.startswith('-l'):
+          if lib.endswith('_static'):
+            static_lib_modules.append('lib' + lib[2:])
+          else:
+            dynamic_lib_modules.append('lib' + lib[2:])
+    return (static_lib_modules, dynamic_lib_modules)
+
+
+  def ComputeDeps(self, spec):
+    """Compute the dependencies of a gyp spec.
+
+    Returns a tuple (deps, link_deps), where each is a list of
+    filenames that will need to be put in front of make for either
+    building (deps) or linking (link_deps).
+    """
+    deps = []
+    link_deps = []
+    if 'dependencies' in spec:
+      deps.extend([target_outputs[dep] for dep in spec['dependencies']
+                   if target_outputs[dep]])
+      for dep in spec['dependencies']:
+        if dep in target_link_deps:
+          link_deps.append(target_link_deps[dep])
+      deps.extend(link_deps)
+    return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps))
+
+
+  def WriteTargetFlags(self, spec, configs, link_deps):
+    """Write Makefile code to specify the link flags and library dependencies.
+
+    spec, configs: input from gyp.
+    link_deps: link dependency list; see ComputeDeps()
+    """
+    for configname, config in sorted(configs.iteritems()):
+      ldflags = list(config.get('ldflags', []))
+      self.WriteLn('')
+      self.WriteList(ldflags, 'LOCAL_LDFLAGS_%s' % configname)
+    self.WriteLn('\nLOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))')
+
+    # Libraries (i.e. -lfoo)
+    libraries = gyp.common.uniquer(spec.get('libraries', []))
+    static_libs, dynamic_libs = self.ComputeAndroidLibraryModuleNames(
+        libraries)
+
+    # Link dependencies (i.e. libfoo.a, libfoo.so)
+    static_link_deps = [x[1] for x in link_deps if x[0] == 'static']
+    shared_link_deps = [x[1] for x in link_deps if x[0] == 'shared']
+    self.WriteLn('')
+    self.WriteList(static_libs + static_link_deps,
+                   'LOCAL_STATIC_LIBRARIES')
+    self.WriteLn('# Enable grouping to fix circular references')
+    self.WriteLn('LOCAL_GROUP_STATIC_LIBRARIES := true')
+    self.WriteLn('')
+    self.WriteList(dynamic_libs + shared_link_deps,
+                   'LOCAL_SHARED_LIBRARIES')
+
+
+  def WriteTarget(self, spec, configs, deps, link_deps, part_of_all,
+                  write_alias_target):
+    """Write Makefile code to produce the final target of the gyp spec.
+
+    spec, configs: input from gyp.
+    deps, link_deps: dependency lists; see ComputeDeps()
+    part_of_all: flag indicating this target is part of 'all'
+    write_alias_target: flag indicating whether to create short aliases for this
+                        target
+    """
+    self.WriteLn('### Rules for final target.')
+
+    if self.type != 'none':
+      self.WriteTargetFlags(spec, configs, link_deps)
+
+    # Add to the set of targets which represent the gyp 'all' target. We use the
+    # name 'gyp_all_modules' as the Android build system doesn't allow the use
+    # of the Make target 'all' and because 'all_modules' is the equivalent of
+    # the Make target 'all' on Android.
+    if part_of_all and write_alias_target:
+      self.WriteLn('# Add target alias to "gyp_all_modules" target.')
+      self.WriteLn('.PHONY: gyp_all_modules')
+      self.WriteLn('gyp_all_modules: %s' % self.android_module)
+      self.WriteLn('')
+
+    # Add an alias from the gyp target name to the Android module name. This
+    # simplifies manual builds of the target, and is required by the test
+    # framework.
+    if self.target != self.android_module and write_alias_target:
+      self.WriteLn('# Alias gyp target name.')
+      self.WriteLn('.PHONY: %s' % self.target)
+      self.WriteLn('%s: %s' % (self.target, self.android_module))
+      self.WriteLn('')
+
+    # Add the command to trigger build of the target type depending
+    # on the toolset. Ex: BUILD_STATIC_LIBRARY vs. BUILD_HOST_STATIC_LIBRARY
+    # NOTE: This has to come last!
+    modifier = ''
+    if self.toolset == 'host':
+      modifier = 'HOST_'
+    if self.type == 'static_library':
+      self.WriteLn('include $(BUILD_%sSTATIC_LIBRARY)' % modifier)
+    elif self.type == 'shared_library':
+      self.WriteLn('LOCAL_PRELINK_MODULE := false')
+      self.WriteLn('include $(BUILD_%sSHARED_LIBRARY)' % modifier)
+    elif self.type == 'executable':
+      # Executables are for build and test purposes only, so they're installed
+      # to a directory that doesn't get included in the system image.
+      self.WriteLn('LOCAL_MODULE_PATH := $(gyp_shared_intermediate_dir)')
+      self.WriteLn('include $(BUILD_%sEXECUTABLE)' % modifier)
+    else:
+      self.WriteLn('LOCAL_MODULE_PATH := $(PRODUCT_OUT)/gyp_stamp')
+      self.WriteLn('LOCAL_UNINSTALLABLE_MODULE := true')
+      if self.toolset == 'target':
+        self.WriteLn('LOCAL_2ND_ARCH_VAR_PREFIX := $(GYP_VAR_PREFIX)')
+      self.WriteLn()
+      self.WriteLn('include $(BUILD_SYSTEM)/base_rules.mk')
+      self.WriteLn()
+      self.WriteLn('$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)')
+      self.WriteLn('\t$(hide) echo "Gyp timestamp: $@"')
+      self.WriteLn('\t$(hide) mkdir -p $(dir $@)')
+      self.WriteLn('\t$(hide) touch $@')
+      if self.toolset == 'target':
+        self.WriteLn()
+        self.WriteLn('LOCAL_2ND_ARCH_VAR_PREFIX :=')
+
+
+  def WriteList(self, value_list, variable=None, prefix='',
+                quoter=make.QuoteIfNecessary, local_pathify=False):
+    """Write a variable definition that is a list of values.
+
+    E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
+         foo = blaha blahb
+    but in a pretty-printed style.
+    """
+    values = ''
+    if value_list:
+      value_list = [quoter(prefix + l) for l in value_list]
+      if local_pathify:
+        value_list = [self.LocalPathify(l) for l in value_list]
+      values = ' \\\n\t' + ' \\\n\t'.join(value_list)
+    self.fp.write('%s :=%s\n\n' % (variable, values))
+
+
+  def WriteLn(self, text=''):
+    self.fp.write(text + '\n')
+
+
+  def LocalPathify(self, path):
+    """Convert a subdirectory-relative path into a normalized path which starts
+    with the make variable $(LOCAL_PATH) (i.e. the top of the project tree).
+    Absolute paths, or paths that contain variables, are just normalized."""
+    if '$(' in path or os.path.isabs(path):
+      # path is not a file in the project tree in this case, but calling
+      # normpath is still important for trimming trailing slashes.
+      return os.path.normpath(path)
+    local_path = os.path.join('$(LOCAL_PATH)', self.path, path)
+    local_path = os.path.normpath(local_path)
+    # Check that normalizing the path didn't ../ itself out of $(LOCAL_PATH)
+    # - i.e. that the resulting path is still inside the project tree. The
+    # path may legitimately have ended up containing just $(LOCAL_PATH), though,
+    # so we don't look for a slash.
+    assert local_path.startswith('$(LOCAL_PATH)'), (
+           'Path %s attempts to escape from gyp path %s !)' % (path, self.path))
+    return local_path
+
+
+  def ExpandInputRoot(self, template, expansion, dirname):
+    if '%(INPUT_ROOT)s' not in template and '%(INPUT_DIRNAME)s' not in template:
+      return template
+    path = template % {
+        'INPUT_ROOT': expansion,
+        'INPUT_DIRNAME': dirname,
+        }
+    return os.path.normpath(path)
+
+
+def PerformBuild(data, configurations, params):
+  # The android backend only supports the default configuration.
+  options = params['options']
+  makefile = os.path.abspath(os.path.join(options.toplevel_dir,
+                                          'GypAndroid.mk'))
+  env = dict(os.environ)
+  env['ONE_SHOT_MAKEFILE'] = makefile
+  arguments = ['make', '-C', os.environ['ANDROID_BUILD_TOP'], 'gyp_all_modules']
+  print 'Building: %s' % arguments
+  subprocess.check_call(arguments, env=env)
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  options = params['options']
+  generator_flags = params.get('generator_flags', {})
+  builddir_name = generator_flags.get('output_dir', 'out')
+  limit_to_target_all = generator_flags.get('limit_to_target_all', False)
+  write_alias_targets = generator_flags.get('write_alias_targets', True)
+  android_top_dir = os.environ.get('ANDROID_BUILD_TOP')
+  assert android_top_dir, '$ANDROID_BUILD_TOP not set; you need to run lunch.'
+
+  def CalculateMakefilePath(build_file, base_name):
+    """Determine where to write a Makefile for a given gyp file."""
+    # Paths in gyp files are relative to the .gyp file, but we want
+    # paths relative to the source root for the master makefile.  Grab
+    # the path of the .gyp file as the base to relativize against.
+    # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp".
+    base_path = gyp.common.RelativePath(os.path.dirname(build_file),
+                                        options.depth)
+    # We write the file in the base_path directory.
+    output_file = os.path.join(options.depth, base_path, base_name)
+    assert not options.generator_output, (
+        'The Android backend does not support options.generator_output.')
+    base_path = gyp.common.RelativePath(os.path.dirname(build_file),
+                                        options.toplevel_dir)
+    return base_path, output_file
+
+  # TODO:  search for the first non-'Default' target.  This can go
+  # away when we add verification that all targets have the
+  # necessary configurations.
+  default_configuration = None
+  toolsets = set([target_dicts[target]['toolset'] for target in target_list])
+  for target in target_list:
+    spec = target_dicts[target]
+    if spec['default_configuration'] != 'Default':
+      default_configuration = spec['default_configuration']
+      break
+  if not default_configuration:
+    default_configuration = 'Default'
+
+  srcdir = '.'
+  makefile_name = 'GypAndroid' + options.suffix + '.mk'
+  makefile_path = os.path.join(options.toplevel_dir, makefile_name)
+  assert not options.generator_output, (
+      'The Android backend does not support options.generator_output.')
+  gyp.common.EnsureDirExists(makefile_path)
+  root_makefile = open(makefile_path, 'w')
+
+  root_makefile.write(header)
+
+  # We set LOCAL_PATH just once, here, to the top of the project tree. This
+  # allows all the other paths we use to be relative to the Android.mk file,
+  # as the Android build system expects.
+  root_makefile.write('\nLOCAL_PATH := $(call my-dir)\n')
+
+  # Find the list of targets that derive from the gyp file(s) being built.
+  needed_targets = set()
+  for build_file in params['build_files']:
+    for target in gyp.common.AllTargets(target_list, target_dicts, build_file):
+      needed_targets.add(target)
+
+  build_files = set()
+  include_list = set()
+  android_modules = {}
+  for qualified_target in target_list:
+    build_file, target, toolset = gyp.common.ParseQualifiedTarget(
+        qualified_target)
+    relative_build_file = gyp.common.RelativePath(build_file,
+                                                  options.toplevel_dir)
+    build_files.add(relative_build_file)
+    included_files = data[build_file]['included_files']
+    for included_file in included_files:
+      # The included_files entries are relative to the dir of the build file
+      # that included them, so we have to undo that and then make them relative
+      # to the root dir.
+      relative_include_file = gyp.common.RelativePath(
+          gyp.common.UnrelativePath(included_file, build_file),
+          options.toplevel_dir)
+      abs_include_file = os.path.abspath(relative_include_file)
+      # If the include file is from the ~/.gyp dir, we should use absolute path
+      # so that relocating the src dir doesn't break the path.
+      if (params['home_dot_gyp'] and
+          abs_include_file.startswith(params['home_dot_gyp'])):
+        build_files.add(abs_include_file)
+      else:
+        build_files.add(relative_include_file)
+
+    base_path, output_file = CalculateMakefilePath(build_file,
+        target + '.' + toolset + options.suffix + '.mk')
+
+    spec = target_dicts[qualified_target]
+    configs = spec['configurations']
+
+    part_of_all = (qualified_target in needed_targets and
+                   not int(spec.get('suppress_wildcard', False)))
+    if limit_to_target_all and not part_of_all:
+      continue
+
+    relative_target = gyp.common.QualifiedTarget(relative_build_file, target,
+                                                 toolset)
+    writer = AndroidMkWriter(android_top_dir)
+    android_module = writer.Write(qualified_target, relative_target, base_path,
+                                  output_file, spec, configs,
+                                  part_of_all=part_of_all,
+                                  write_alias_target=write_alias_targets)
+    if android_module in android_modules:
+      print ('ERROR: Android module names must be unique. The following '
+             'targets both generate Android module name %s.\n  %s\n  %s' %
+             (android_module, android_modules[android_module],
+              qualified_target))
+      return
+    android_modules[android_module] = qualified_target
+
+    # Our root_makefile lives at the source root.  Compute the relative path
+    # from there to the output_file for including.
+    mkfile_rel_path = gyp.common.RelativePath(output_file,
+                                              os.path.dirname(makefile_path))
+    include_list.add(mkfile_rel_path)
+
+  root_makefile.write('GYP_CONFIGURATION ?= %s\n' % default_configuration)
+  root_makefile.write('GYP_VAR_PREFIX ?=\n')
+
+  # Write out the sorted list of includes.
+  root_makefile.write('\n')
+  for include_file in sorted(include_list):
+    root_makefile.write('include $(LOCAL_PATH)/' + include_file + '\n')
+  root_makefile.write('\n')
+
+  if write_alias_targets:
+    root_makefile.write(ALL_MODULES_FOOTER)
+
+  root_makefile.close()
diff --git a/gyp/pylib/gyp/generator/cmake.py b/gyp/pylib/gyp/generator/cmake.py
new file mode 100644 (file)
index 0000000..10d015e
--- /dev/null
@@ -0,0 +1,1143 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""cmake output module
+
+This module is under development and should be considered experimental.
+
+This module produces cmake (2.8.8+) input as its output. One CMakeLists.txt is
+created for each configuration.
+
+This module's original purpose was to support editing in IDEs like KDevelop
+which use CMake for project management. It is also possible to use CMake to
+generate projects for other IDEs such as eclipse cdt and code::blocks. QtCreator
+will convert the CMakeLists.txt to a code::blocks cbp for the editor to read,
+but build using CMake. As a result QtCreator editor is unaware of compiler
+defines. The generated CMakeLists.txt can also be used to build on Linux. There
+is currently no support for building on platforms other than Linux.
+
+The generated CMakeLists.txt should properly compile all projects. However,
+there is a mismatch between gyp and cmake with regard to linking. All attempts
+are made to work around this, but CMake sometimes sees -Wl,--start-group as a
+library and incorrectly repeats it. As a result the output of this generator
+should not be relied on for building.
+
+When using with kdevelop, use version 4.4+. Previous versions of kdevelop will
+not be able to find the header file directories described in the generated
+CMakeLists.txt file.
+"""
+
+import multiprocessing
+import os
+import signal
+import string
+import subprocess
+import gyp.common
+
+generator_default_variables = {
+  'EXECUTABLE_PREFIX': '',
+  'EXECUTABLE_SUFFIX': '',
+  'STATIC_LIB_PREFIX': 'lib',
+  'STATIC_LIB_SUFFIX': '.a',
+  'SHARED_LIB_PREFIX': 'lib',
+  'SHARED_LIB_SUFFIX': '.so',
+  'SHARED_LIB_DIR': '${builddir}/lib.${TOOLSET}',
+  'LIB_DIR': '${obj}.${TOOLSET}',
+  'INTERMEDIATE_DIR': '${obj}.${TOOLSET}/${TARGET}/geni',
+  'SHARED_INTERMEDIATE_DIR': '${obj}/gen',
+  'PRODUCT_DIR': '${builddir}',
+  'RULE_INPUT_PATH': '${RULE_INPUT_PATH}',
+  'RULE_INPUT_DIRNAME': '${RULE_INPUT_DIRNAME}',
+  'RULE_INPUT_NAME': '${RULE_INPUT_NAME}',
+  'RULE_INPUT_ROOT': '${RULE_INPUT_ROOT}',
+  'RULE_INPUT_EXT': '${RULE_INPUT_EXT}',
+  'CONFIGURATION_NAME': '${configuration}',
+}
+
+FULL_PATH_VARS = ('${CMAKE_SOURCE_DIR}', '${builddir}', '${obj}')
+
+generator_supports_multiple_toolsets = True
+generator_wants_static_library_dependencies_adjusted = True
+
+COMPILABLE_EXTENSIONS = {
+  '.c': 'cc',
+  '.cc': 'cxx',
+  '.cpp': 'cxx',
+  '.cxx': 'cxx',
+  '.s': 's', # cc
+  '.S': 's', # cc
+}
+
+
+def RemovePrefix(a, prefix):
+  """Returns 'a' without 'prefix' if it starts with 'prefix'."""
+  return a[len(prefix):] if a.startswith(prefix) else a
+
+
+def CalculateVariables(default_variables, params):
+  """Calculate additional variables for use in the build (called by gyp)."""
+  default_variables.setdefault('OS', gyp.common.GetFlavor(params))
+
+
+def Compilable(filename):
+  """Return true if the file is compilable (should be in OBJS)."""
+  return any(filename.endswith(e) for e in COMPILABLE_EXTENSIONS)
+
+
+def Linkable(filename):
+  """Return true if the file is linkable (should be on the link line)."""
+  return filename.endswith('.o')
+
+
+def NormjoinPathForceCMakeSource(base_path, rel_path):
+  """Resolves rel_path against base_path and returns the result.
+
+  If rel_path is an absolute path it is returned unchanged.
+  Otherwise it is resolved against base_path and normalized.
+  If the result is a relative path, it is forced to be relative to the
+  CMakeLists.txt.
+  """
+  if os.path.isabs(rel_path):
+    return rel_path
+  if any([rel_path.startswith(var) for var in FULL_PATH_VARS]):
+    return rel_path
+  # TODO: do we need to check base_path for absolute variables as well?
+  return os.path.join('${CMAKE_SOURCE_DIR}',
+                      os.path.normpath(os.path.join(base_path, rel_path)))
+
+
+def NormjoinPath(base_path, rel_path):
+  """Resolves rel_path against base_path and returns the result.
+  TODO: what is this really used for?
+  If rel_path begins with '$' it is returned unchanged.
+  Otherwise it is resolved against base_path if relative, then normalized.
+  """
+  if rel_path.startswith('$') and not rel_path.startswith('${configuration}'):
+    return rel_path
+  return os.path.normpath(os.path.join(base_path, rel_path))
+
+
+def CMakeStringEscape(a):
+  """Escapes the string 'a' for use inside a CMake string.
+
+  This means escaping
+  '\' otherwise it may be seen as modifying the next character
+  '"' otherwise it will end the string
+  ';' otherwise the string becomes a list
+
+  The following do not need to be escaped
+  '#' when the lexer is in string state, this does not start a comment
+
+  The following are yet unknown
+  '$' generator variables (like ${obj}) must not be escaped,
+      but text $ should be escaped
+      what is wanted is to know which $ come from generator variables
+  """
+  return a.replace('\\', '\\\\').replace(';', '\\;').replace('"', '\\"')
+
+
+def SetFileProperty(output, source_name, property_name, values, sep):
+  """Given a set of source file, sets the given property on them."""
+  output.write('set_source_files_properties(')
+  output.write(source_name)
+  output.write(' PROPERTIES ')
+  output.write(property_name)
+  output.write(' "')
+  for value in values:
+    output.write(CMakeStringEscape(value))
+    output.write(sep)
+  output.write('")\n')
+
+
+def SetFilesProperty(output, source_names, 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(property_name)
+  output.write(' "')
+  for value in values:
+    output.write(CMakeStringEscape(value))
+    output.write(sep)
+  output.write('"\n)\n')
+
+
+def SetTargetProperty(output, target_name, property_name, values, sep=''):
+  """Given a target, sets the given property."""
+  output.write('set_target_properties(')
+  output.write(target_name)
+  output.write(' PROPERTIES ')
+  output.write(property_name)
+  output.write(' "')
+  for value in values:
+    output.write(CMakeStringEscape(value))
+    output.write(sep)
+  output.write('")\n')
+
+
+def SetVariable(output, variable_name, value):
+  """Sets a CMake variable."""
+  output.write('set(')
+  output.write(variable_name)
+  output.write(' "')
+  output.write(CMakeStringEscape(value))
+  output.write('")\n')
+
+
+def SetVariableList(output, variable_name, values):
+  """Sets a CMake variable to a list."""
+  if not values:
+    return SetVariable(output, variable_name, "")
+  if len(values) == 1:
+    return SetVariable(output, variable_name, values[0])
+  output.write('list(APPEND ')
+  output.write(variable_name)
+  output.write('\n  "')
+  output.write('"\n  "'.join([CMakeStringEscape(value) for value in values]))
+  output.write('")\n')
+
+
+def UnsetVariable(output, variable_name):
+  """Unsets a CMake variable."""
+  output.write('unset(')
+  output.write(variable_name)
+  output.write(')\n')
+
+
+def WriteVariable(output, variable_name, prepend=None):
+  if prepend:
+    output.write(prepend)
+  output.write('${')
+  output.write(variable_name)
+  output.write('}')
+
+
+class CMakeTargetType:
+  def __init__(self, command, modifier, property_modifier):
+    self.command = command
+    self.modifier = modifier
+    self.property_modifier = property_modifier
+
+
+cmake_target_type_from_gyp_target_type = {
+  'executable': CMakeTargetType('add_executable', None, 'RUNTIME'),
+  'static_library': CMakeTargetType('add_library', 'STATIC', 'ARCHIVE'),
+  'shared_library': CMakeTargetType('add_library', 'SHARED', 'LIBRARY'),
+  'loadable_module': CMakeTargetType('add_library', 'MODULE', 'LIBRARY'),
+  'none': CMakeTargetType('add_custom_target', 'SOURCES', None),
+}
+
+
+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 make: ':'
+  Invalid for unknown reasons but cause failures: '.'
+  """
+  return a.translate(string.maketrans(' /():.', '______'))
+
+
+def WriteActions(target_name, actions, extra_sources, extra_deps,
+                 path_to_gyp, output):
+  """Write CMake for the 'actions' in the target.
+
+  Args:
+    target_name: the name of the CMake target being generated.
+    actions: the Gyp 'actions' dict for this target.
+    extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
+    extra_deps: [<cmake_taget>] to append with generated targets.
+    path_to_gyp: relative path from CMakeLists.txt being generated to
+        the Gyp file in which the target being generated is defined.
+  """
+  for action in actions:
+    action_name = StringToCMakeTargetName(action['action_name'])
+    action_target_name = '%s__%s' % (target_name, action_name)
+
+    inputs = action['inputs']
+    inputs_name = action_target_name + '__input'
+    SetVariableList(output, inputs_name,
+        [NormjoinPathForceCMakeSource(path_to_gyp, dep) for dep in inputs])
+
+    outputs = action['outputs']
+    cmake_outputs = [NormjoinPathForceCMakeSource(path_to_gyp, out)
+                     for out in outputs]
+    outputs_name = action_target_name + '__output'
+    SetVariableList(output, outputs_name, cmake_outputs)
+
+    # Build up a list of outputs.
+    # Collect the output dirs we'll need.
+    dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
+
+    if int(action.get('process_outputs_as_sources', False)):
+      extra_sources.extend(zip(cmake_outputs, outputs))
+
+    # add_custom_command
+    output.write('add_custom_command(OUTPUT ')
+    WriteVariable(output, outputs_name)
+    output.write('\n')
+
+    if len(dirs) > 0:
+      for directory in dirs:
+        output.write('  COMMAND ${CMAKE_COMMAND} -E make_directory ')
+        output.write(directory)
+        output.write('\n')
+
+    output.write('  COMMAND ')
+    output.write(gyp.common.EncodePOSIXShellList(action['action']))
+    output.write('\n')
+
+    output.write('  DEPENDS ')
+    WriteVariable(output, inputs_name)
+    output.write('\n')
+
+    output.write('  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/')
+    output.write(path_to_gyp)
+    output.write('\n')
+
+    output.write('  COMMENT ')
+    if 'message' in action:
+      output.write(action['message'])
+    else:
+      output.write(action_target_name)
+    output.write('\n')
+
+    output.write('  VERBATIM\n')
+    output.write(')\n')
+
+    # add_custom_target
+    output.write('add_custom_target(')
+    output.write(action_target_name)
+    output.write('\n  DEPENDS ')
+    WriteVariable(output, outputs_name)
+    output.write('\n  SOURCES ')
+    WriteVariable(output, inputs_name)
+    output.write('\n)\n')
+
+    extra_deps.append(action_target_name)
+
+
+def NormjoinRulePathForceCMakeSource(base_path, rel_path, rule_source):
+  if rel_path.startswith(("${RULE_INPUT_PATH}","${RULE_INPUT_DIRNAME}")):
+    if any([rule_source.startswith(var) for var in FULL_PATH_VARS]):
+      return rel_path
+  return NormjoinPathForceCMakeSource(base_path, rel_path)
+
+
+def WriteRules(target_name, rules, extra_sources, extra_deps,
+               path_to_gyp, output):
+  """Write CMake for the 'rules' in the target.
+
+  Args:
+    target_name: the name of the CMake target being generated.
+    actions: the Gyp 'actions' dict for this target.
+    extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
+    extra_deps: [<cmake_taget>] to append with generated targets.
+    path_to_gyp: relative path from CMakeLists.txt being generated to
+        the Gyp file in which the target being generated is defined.
+  """
+  for rule in rules:
+    rule_name = StringToCMakeTargetName(target_name + '__' + rule['rule_name'])
+
+    inputs = rule.get('inputs', [])
+    inputs_name = rule_name + '__input'
+    SetVariableList(output, inputs_name,
+        [NormjoinPathForceCMakeSource(path_to_gyp, dep) for dep in inputs])
+    outputs = rule['outputs']
+    var_outputs = []
+
+    for count, rule_source in enumerate(rule.get('rule_sources', [])):
+      action_name = rule_name + '_' + str(count)
+
+      rule_source_dirname, rule_source_basename = os.path.split(rule_source)
+      rule_source_root, rule_source_ext = os.path.splitext(rule_source_basename)
+
+      SetVariable(output, 'RULE_INPUT_PATH', rule_source)
+      SetVariable(output, 'RULE_INPUT_DIRNAME', rule_source_dirname)
+      SetVariable(output, 'RULE_INPUT_NAME', rule_source_basename)
+      SetVariable(output, 'RULE_INPUT_ROOT', rule_source_root)
+      SetVariable(output, 'RULE_INPUT_EXT', rule_source_ext)
+
+      # Build up a list of outputs.
+      # Collect the output dirs we'll need.
+      dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
+
+      # Create variables for the output, as 'local' variable will be unset.
+      these_outputs = []
+      for output_index, out in enumerate(outputs):
+        output_name = action_name + '_' + str(output_index)
+        SetVariable(output, output_name,
+                     NormjoinRulePathForceCMakeSource(path_to_gyp, out,
+                                                      rule_source))
+        if int(rule.get('process_outputs_as_sources', False)):
+          extra_sources.append(('${' + output_name + '}', out))
+        these_outputs.append('${' + output_name + '}')
+        var_outputs.append('${' + output_name + '}')
+
+      # add_custom_command
+      output.write('add_custom_command(OUTPUT\n')
+      for out in these_outputs:
+        output.write('  ')
+        output.write(out)
+        output.write('\n')
+
+      for directory in dirs:
+        output.write('  COMMAND ${CMAKE_COMMAND} -E make_directory ')
+        output.write(directory)
+        output.write('\n')
+
+      output.write('  COMMAND ')
+      output.write(gyp.common.EncodePOSIXShellList(rule['action']))
+      output.write('\n')
+
+      output.write('  DEPENDS ')
+      WriteVariable(output, inputs_name)
+      output.write(' ')
+      output.write(NormjoinPath(path_to_gyp, rule_source))
+      output.write('\n')
+
+      # CMAKE_SOURCE_DIR is where the CMakeLists.txt lives.
+      # The cwd is the current build directory.
+      output.write('  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/')
+      output.write(path_to_gyp)
+      output.write('\n')
+
+      output.write('  COMMENT ')
+      if 'message' in rule:
+        output.write(rule['message'])
+      else:
+        output.write(action_name)
+      output.write('\n')
+
+      output.write('  VERBATIM\n')
+      output.write(')\n')
+
+      UnsetVariable(output, 'RULE_INPUT_PATH')
+      UnsetVariable(output, 'RULE_INPUT_DIRNAME')
+      UnsetVariable(output, 'RULE_INPUT_NAME')
+      UnsetVariable(output, 'RULE_INPUT_ROOT')
+      UnsetVariable(output, 'RULE_INPUT_EXT')
+
+    # add_custom_target
+    output.write('add_custom_target(')
+    output.write(rule_name)
+    output.write(' DEPENDS\n')
+    for out in var_outputs:
+      output.write('  ')
+      output.write(out)
+      output.write('\n')
+    output.write('SOURCES ')
+    WriteVariable(output, inputs_name)
+    output.write('\n')
+    for rule_source in rule.get('rule_sources', []):
+      output.write('  ')
+      output.write(NormjoinPath(path_to_gyp, rule_source))
+      output.write('\n')
+    output.write(')\n')
+
+    extra_deps.append(rule_name)
+
+
+def WriteCopies(target_name, copies, extra_deps, path_to_gyp, output):
+  """Write CMake for the 'copies' in the target.
+
+  Args:
+    target_name: the name of the CMake target being generated.
+    actions: the Gyp 'actions' dict for this target.
+    extra_deps: [<cmake_taget>] to append with generated targets.
+    path_to_gyp: relative path from CMakeLists.txt being generated to
+        the Gyp file in which the target being generated is defined.
+  """
+  copy_name = target_name + '__copies'
+
+  # CMake gets upset with custom targets with OUTPUT which specify no output.
+  have_copies = any(copy['files'] for copy in copies)
+  if not have_copies:
+    output.write('add_custom_target(')
+    output.write(copy_name)
+    output.write(')\n')
+    extra_deps.append(copy_name)
+    return
+
+  class Copy:
+    def __init__(self, ext, command):
+      self.cmake_inputs = []
+      self.cmake_outputs = []
+      self.gyp_inputs = []
+      self.gyp_outputs = []
+      self.ext = ext
+      self.inputs_name = None
+      self.outputs_name = None
+      self.command = command
+
+  file_copy = Copy('', 'copy')
+  dir_copy = Copy('_dirs', 'copy_directory')
+
+  for copy in copies:
+    files = copy['files']
+    destination = copy['destination']
+    for src in files:
+      path = os.path.normpath(src)
+      basename = os.path.split(path)[1]
+      dst = os.path.join(destination, basename)
+
+      copy = file_copy if os.path.basename(src) else dir_copy
+
+      copy.cmake_inputs.append(NormjoinPath(path_to_gyp, src))
+      copy.cmake_outputs.append(NormjoinPathForceCMakeSource(path_to_gyp, dst))
+      copy.gyp_inputs.append(src)
+      copy.gyp_outputs.append(dst)
+
+  for copy in (file_copy, dir_copy):
+    if copy.cmake_inputs:
+      copy.inputs_name = copy_name + '__input' + copy.ext
+      SetVariableList(output, copy.inputs_name, copy.cmake_inputs)
+
+      copy.outputs_name = copy_name + '__output' + copy.ext
+      SetVariableList(output, copy.outputs_name, copy.cmake_outputs)
+
+  # add_custom_command
+  output.write('add_custom_command(\n')
+
+  output.write('OUTPUT')
+  for copy in (file_copy, dir_copy):
+    if copy.outputs_name:
+      WriteVariable(output, copy.outputs_name, ' ')
+  output.write('\n')
+
+  for copy in (file_copy, dir_copy):
+    for src, dst in zip(copy.gyp_inputs, copy.gyp_outputs):
+      # 'cmake -E copy src dst' will create the 'dst' directory if needed.
+      output.write('COMMAND ${CMAKE_COMMAND} -E %s ' % copy.command)
+      output.write(src)
+      output.write(' ')
+      output.write(dst)
+      output.write("\n")
+
+  output.write('DEPENDS')
+  for copy in (file_copy, dir_copy):
+    if copy.inputs_name:
+      WriteVariable(output, copy.inputs_name, ' ')
+  output.write('\n')
+
+  output.write('WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/')
+  output.write(path_to_gyp)
+  output.write('\n')
+
+  output.write('COMMENT Copying for ')
+  output.write(target_name)
+  output.write('\n')
+
+  output.write('VERBATIM\n')
+  output.write(')\n')
+
+  # add_custom_target
+  output.write('add_custom_target(')
+  output.write(copy_name)
+  output.write('\n  DEPENDS')
+  for copy in (file_copy, dir_copy):
+    if copy.outputs_name:
+      WriteVariable(output, copy.outputs_name, ' ')
+  output.write('\n  SOURCES')
+  if file_copy.inputs_name:
+    WriteVariable(output, file_copy.inputs_name, ' ')
+  output.write('\n)\n')
+
+  extra_deps.append(copy_name)
+
+
+def CreateCMakeTargetBaseName(qualified_target):
+  """This is the name we would like the target to have."""
+  _, gyp_target_name, gyp_target_toolset = (
+      gyp.common.ParseQualifiedTarget(qualified_target))
+  cmake_target_base_name = gyp_target_name
+  if gyp_target_toolset and gyp_target_toolset != 'target':
+    cmake_target_base_name += '_' + gyp_target_toolset
+  return StringToCMakeTargetName(cmake_target_base_name)
+
+
+def CreateCMakeTargetFullName(qualified_target):
+  """An unambiguous name for the target."""
+  gyp_file, gyp_target_name, gyp_target_toolset = (
+      gyp.common.ParseQualifiedTarget(qualified_target))
+  cmake_target_full_name = gyp_file + ':' + gyp_target_name
+  if gyp_target_toolset and gyp_target_toolset != 'target':
+    cmake_target_full_name += '_' + gyp_target_toolset
+  return StringToCMakeTargetName(cmake_target_full_name)
+
+
+class CMakeNamer(object):
+  """Converts Gyp target names into CMake target names.
+
+  CMake requires that target names be globally unique. One way to ensure
+  this is to fully qualify the names of the targets. Unfortunatly, this
+  ends up with all targets looking like "chrome_chrome_gyp_chrome" instead
+  of just "chrome". If this generator were only interested in building, it
+  would be possible to fully qualify all target names, then create
+  unqualified target names which depend on all qualified targets which
+  should have had that name. This is more or less what the 'make' generator
+  does with aliases. However, one goal of this generator is to create CMake
+  files for use with IDEs, and fully qualified names are not as user
+  friendly.
+
+  Since target name collision is rare, we do the above only when required.
+
+  Toolset variants are always qualified from the base, as this is required for
+  building. However, it also makes sense for an IDE, as it is possible for
+  defines to be different.
+  """
+  def __init__(self, target_list):
+    self.cmake_target_base_names_conficting = set()
+
+    cmake_target_base_names_seen = set()
+    for qualified_target in target_list:
+      cmake_target_base_name = CreateCMakeTargetBaseName(qualified_target)
+
+      if cmake_target_base_name not in cmake_target_base_names_seen:
+        cmake_target_base_names_seen.add(cmake_target_base_name)
+      else:
+        self.cmake_target_base_names_conficting.add(cmake_target_base_name)
+
+  def CreateCMakeTargetName(self, qualified_target):
+    base_name = CreateCMakeTargetBaseName(qualified_target)
+    if base_name in self.cmake_target_base_names_conficting:
+      return CreateCMakeTargetFullName(qualified_target)
+    return base_name
+
+
+def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
+                options, generator_flags, all_qualified_targets, output):
+
+  # The make generator does this always.
+  # TODO: It would be nice to be able to tell CMake all dependencies.
+  circular_libs = generator_flags.get('circular', True)
+
+  if not generator_flags.get('standalone', False):
+    output.write('\n#')
+    output.write(qualified_target)
+    output.write('\n')
+
+  gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target)
+  rel_gyp_file = gyp.common.RelativePath(gyp_file, options.toplevel_dir)
+  rel_gyp_dir = os.path.dirname(rel_gyp_file)
+
+  # Relative path from build dir to top dir.
+  build_to_top = gyp.common.InvertRelativePath(build_dir, options.toplevel_dir)
+  # Relative path from build dir to gyp dir.
+  build_to_gyp = os.path.join(build_to_top, rel_gyp_dir)
+
+  path_from_cmakelists_to_gyp = build_to_gyp
+
+  spec = target_dicts.get(qualified_target, {})
+  config = spec.get('configurations', {}).get(config_to_use, {})
+
+  target_name = spec.get('target_name', '<missing target name>')
+  target_type = spec.get('type', '<missing target type>')
+  target_toolset = spec.get('toolset')
+
+  SetVariable(output, 'TARGET', target_name)
+  SetVariable(output, 'TOOLSET', target_toolset)
+
+  cmake_target_name = namer.CreateCMakeTargetName(qualified_target)
+
+  extra_sources = []
+  extra_deps = []
+
+  # Actions must come first, since they can generate more OBJs for use below.
+  if 'actions' in spec:
+    WriteActions(cmake_target_name, spec['actions'], extra_sources, extra_deps,
+                 path_from_cmakelists_to_gyp, output)
+
+  # Rules must be early like actions.
+  if 'rules' in spec:
+    WriteRules(cmake_target_name, spec['rules'], extra_sources, extra_deps,
+               path_from_cmakelists_to_gyp, output)
+
+  # Copies
+  if 'copies' in spec:
+    WriteCopies(cmake_target_name, spec['copies'], extra_deps,
+                path_from_cmakelists_to_gyp, output)
+
+  # Target and sources
+  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)
+
+  # 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'
+
+  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
+
+  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
+  # find_library and passing absolute paths to target_link_libraries.
+  # However, CMake does provide the command link_directories, which adds
+  # link directories to targets defined after it is called.
+  # As a result, link_directories must come before the target definition.
+  # CMake unfortunately has no means of removing entries from LINK_DIRECTORIES.
+  library_dirs = config.get('library_dirs')
+  if library_dirs is not None:
+    output.write('link_directories(')
+    for library_dir in library_dirs:
+      output.write(' ')
+      output.write(NormjoinPath(path_from_cmakelists_to_gyp, library_dir))
+      output.write('\n')
+    output.write(')\n')
+
+  output.write(cmake_target_type.command)
+  output.write('(')
+  output.write(cmake_target_name)
+
+  if cmake_target_type.modifier is not None:
+    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')
+
+  output.write(')\n')
+
+  # Output name and location.
+  if target_type != 'none':
+    # Mark uncompiled sources as uncompiled.
+    if other_srcs_name:
+      output.write('set_source_files_properties(')
+      WriteVariable(output, other_srcs_name, '')
+      output.write(' PROPERTIES HEADER_FILE_ONLY "TRUE")\n')
+
+    # Output directory
+    target_output_directory = spec.get('product_dir')
+    if target_output_directory is None:
+      if target_type in ('executable', 'loadable_module'):
+        target_output_directory = generator_default_variables['PRODUCT_DIR']
+      elif target_type in ('shared_library'):
+        target_output_directory = '${builddir}/lib.${TOOLSET}'
+      elif spec.get('standalone_static_library', False):
+        target_output_directory = generator_default_variables['PRODUCT_DIR']
+      else:
+        base_path = gyp.common.RelativePath(os.path.dirname(gyp_file),
+                                            options.toplevel_dir)
+        target_output_directory = '${obj}.${TOOLSET}'
+        target_output_directory = (
+            os.path.join(target_output_directory, base_path))
+
+    cmake_target_output_directory = NormjoinPathForceCMakeSource(
+                                        path_from_cmakelists_to_gyp,
+                                        target_output_directory)
+    SetTargetProperty(output,
+        cmake_target_name,
+        cmake_target_type.property_modifier + '_OUTPUT_DIRECTORY',
+        cmake_target_output_directory)
+
+    # Output name
+    default_product_prefix = ''
+    default_product_name = target_name
+    default_product_ext = ''
+    if target_type == 'static_library':
+      static_library_prefix = generator_default_variables['STATIC_LIB_PREFIX']
+      default_product_name = RemovePrefix(default_product_name,
+                                          static_library_prefix)
+      default_product_prefix = static_library_prefix
+      default_product_ext = generator_default_variables['STATIC_LIB_SUFFIX']
+
+    elif target_type in ('loadable_module', 'shared_library'):
+      shared_library_prefix = generator_default_variables['SHARED_LIB_PREFIX']
+      default_product_name = RemovePrefix(default_product_name,
+                                          shared_library_prefix)
+      default_product_prefix = shared_library_prefix
+      default_product_ext = generator_default_variables['SHARED_LIB_SUFFIX']
+
+    elif target_type != 'executable':
+      print ('ERROR: What output file should be generated?',
+              'type', target_type, 'target', target_name)
+
+    product_prefix = spec.get('product_prefix', default_product_prefix)
+    product_name = spec.get('product_name', default_product_name)
+    product_ext = spec.get('product_extension')
+    if product_ext:
+      product_ext = '.' + product_ext
+    else:
+      product_ext = default_product_ext
+
+    SetTargetProperty(output, cmake_target_name, 'PREFIX', product_prefix)
+    SetTargetProperty(output, cmake_target_name,
+                        cmake_target_type.property_modifier + '_OUTPUT_NAME',
+                        product_name)
+    SetTargetProperty(output, cmake_target_name, 'SUFFIX', product_ext)
+
+    # Make the output of this target referenceable as a source.
+    cmake_target_output_basename = product_prefix + product_name + product_ext
+    cmake_target_output = os.path.join(cmake_target_output_directory,
+                                       cmake_target_output_basename)
+    SetFileProperty(output, cmake_target_output, 'GENERATED', ['TRUE'], '')
+
+  # Let CMake know if the 'all' target should depend on this target.
+  exclude_from_all = ('TRUE' if qualified_target not in all_qualified_targets
+                             else 'FALSE')
+  SetTargetProperty(output, cmake_target_name,
+                      'EXCLUDE_FROM_ALL', exclude_from_all)
+  for extra_target_name in extra_deps:
+    SetTargetProperty(output, extra_target_name,
+                        'EXCLUDE_FROM_ALL', exclude_from_all)
+
+  # Includes
+  includes = config.get('include_dirs')
+  if includes:
+    # This (target include directories) is what requires CMake 2.8.8
+    includes_name = cmake_target_name + '__include_dirs'
+    SetVariableList(output, includes_name,
+        [NormjoinPathForceCMakeSource(path_from_cmakelists_to_gyp, include)
+         for include in includes])
+    output.write('set_property(TARGET ')
+    output.write(cmake_target_name)
+    output.write(' APPEND PROPERTY INCLUDE_DIRECTORIES ')
+    WriteVariable(output, includes_name, '')
+    output.write(')\n')
+
+  # Defines
+  defines = config.get('defines')
+  if defines is not None:
+    SetTargetProperty(output,
+                        cmake_target_name,
+                        'COMPILE_DEFINITIONS',
+                        defines,
+                        ';')
+
+  # Compile Flags - http://www.cmake.org/Bug/view.php?id=6493
+  # CMake currently does not have target C and CXX flags.
+  # So, instead of doing...
+
+  # cflags_c = config.get('cflags_c')
+  # if cflags_c is not None:
+  #   SetTargetProperty(output, cmake_target_name,
+  #                       'C_COMPILE_FLAGS', cflags_c, ' ')
+
+  # cflags_cc = config.get('cflags_cc')
+  # if cflags_cc is not None:
+  #   SetTargetProperty(output, cmake_target_name,
+  #                       '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):
+    flags = []
+    flags.extend(cflags)
+    flags.extend(cflags_c)
+    SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ')
+
+  elif cxx_sources and not (s_sources or c_sources):
+    flags = []
+    flags.extend(cflags)
+    flags.extend(cflags_cxx)
+    SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ')
+
+  else:
+    if s_sources and cflags:
+      SetFilesProperty(output, s_sources, '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, ' ')
+
+    if cxx_sources and (cflags or cflags_cxx):
+      flags = []
+      flags.extend(cflags)
+      flags.extend(cflags_cxx)
+      SetFilesProperty(output, cxx_sources, '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:
+    SetTargetProperty(output, cmake_target_name, 'LINKER_LANGUAGE', ['C'])
+
+  # Linker flags
+  ldflags = config.get('ldflags')
+  if ldflags is not None:
+    SetTargetProperty(output, cmake_target_name, 'LINK_FLAGS', ldflags, ' ')
+
+  # Note on Dependencies and Libraries:
+  # CMake wants to handle link order, resolving the link line up front.
+  # Gyp does not retain or enforce specifying enough information to do so.
+  # So do as other gyp generators and use --start-group and --end-group.
+  # Give CMake as little information as possible so that it doesn't mess it up.
+
+  # Dependencies
+  rawDeps = spec.get('dependencies', [])
+
+  static_deps = []
+  shared_deps = []
+  other_deps = []
+  for rawDep in rawDeps:
+    dep_cmake_name = namer.CreateCMakeTargetName(rawDep)
+    dep_spec = target_dicts.get(rawDep, {})
+    dep_target_type = dep_spec.get('type', None)
+
+    if dep_target_type == 'static_library':
+      static_deps.append(dep_cmake_name)
+    elif dep_target_type ==  'shared_library':
+      shared_deps.append(dep_cmake_name)
+    else:
+      other_deps.append(dep_cmake_name)
+
+  # ensure all external dependencies are complete before internal dependencies
+  # extra_deps currently only depend on their own deps, so otherwise run early
+  if static_deps or shared_deps or other_deps:
+    for extra_dep in extra_deps:
+      output.write('add_dependencies(')
+      output.write(extra_dep)
+      output.write('\n')
+      for deps in (static_deps, shared_deps, other_deps):
+        for dep in gyp.common.uniquer(deps):
+          output.write('  ')
+          output.write(dep)
+          output.write('\n')
+      output.write(')\n')
+
+  linkable = target_type in ('executable', 'loadable_module', 'shared_library')
+  other_deps.extend(extra_deps)
+  if other_deps or (not linkable and (static_deps or shared_deps)):
+    output.write('add_dependencies(')
+    output.write(cmake_target_name)
+    output.write('\n')
+    for dep in gyp.common.uniquer(other_deps):
+      output.write('  ')
+      output.write(dep)
+      output.write('\n')
+    if not linkable:
+      for deps in (static_deps, shared_deps):
+        for lib_dep in gyp.common.uniquer(deps):
+          output.write('  ')
+          output.write(lib_dep)
+          output.write('\n')
+    output.write(')\n')
+
+  # Libraries
+  if linkable:
+    external_libs = [lib for lib in spec.get('libraries', []) if len(lib) > 0]
+    if external_libs or static_deps or shared_deps:
+      output.write('target_link_libraries(')
+      output.write(cmake_target_name)
+      output.write('\n')
+      if static_deps:
+        write_group = circular_libs and len(static_deps) > 1
+        if write_group:
+          output.write('-Wl,--start-group\n')
+        for dep in gyp.common.uniquer(static_deps):
+          output.write('  ')
+          output.write(dep)
+          output.write('\n')
+        if write_group:
+          output.write('-Wl,--end-group\n')
+      if shared_deps:
+        for dep in gyp.common.uniquer(shared_deps):
+          output.write('  ')
+          output.write(dep)
+          output.write('\n')
+      if external_libs:
+        for lib in gyp.common.uniquer(external_libs):
+          output.write('  ')
+          output.write(lib)
+          output.write('\n')
+
+      output.write(')\n')
+
+  UnsetVariable(output, 'TOOLSET')
+  UnsetVariable(output, 'TARGET')
+
+
+def GenerateOutputForConfig(target_list, target_dicts, data,
+                            params, config_to_use):
+  options = params['options']
+  generator_flags = params['generator_flags']
+
+  # generator_dir: relative path from pwd to where make puts build files.
+  # Makes migrating from make to cmake easier, cmake doesn't put anything here.
+  # Each Gyp configuration creates a different CMakeLists.txt file
+  # to avoid incompatibilities between Gyp and CMake configurations.
+  generator_dir = os.path.relpath(options.generator_output or '.')
+
+  # output_dir: relative path from generator_dir to the build directory.
+  output_dir = generator_flags.get('output_dir', 'out')
+
+  # build_dir: relative path from source root to our output files.
+  # e.g. "out/Debug"
+  build_dir = os.path.normpath(os.path.join(generator_dir,
+                                            output_dir,
+                                            config_to_use))
+
+  toplevel_build = os.path.join(options.toplevel_dir, build_dir)
+
+  output_file = os.path.join(toplevel_build, 'CMakeLists.txt')
+  gyp.common.EnsureDirExists(output_file)
+
+  output = open(output_file, 'w')
+  output.write('cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)\n')
+  output.write('cmake_policy(VERSION 2.8.8)\n')
+
+  _, project_target, _ = gyp.common.ParseQualifiedTarget(target_list[-1])
+  output.write('project(')
+  output.write(project_target)
+  output.write(')\n')
+
+  SetVariable(output, 'configuration', config_to_use)
+
+  # 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')
+
+  SetVariable(output, 'builddir', '${CMAKE_BINARY_DIR}')
+  SetVariable(output, 'obj', '${builddir}/obj')
+  output.write('\n')
+
+  # TODO: Undocumented/unsupported (the CMake Java generator depends on it).
+  # CMake by default names the object resulting from foo.c to be foo.c.o.
+  # Gyp traditionally names the object resulting from foo.c foo.o.
+  # This should be irrelevant, but some targets extract .o files from .a
+  # and depend on the name of the extracted .o files.
+  output.write('set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)\n')
+  output.write('set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)\n')
+  output.write('\n')
+
+  namer = CMakeNamer(target_list)
+
+  # The list of targets upon which the 'all' target should depend.
+  # CMake has it's own implicit 'all' target, one is not created explicitly.
+  all_qualified_targets = set()
+  for build_file in params['build_files']:
+    for qualified_target in gyp.common.AllTargets(target_list,
+                                                  target_dicts,
+                                                  os.path.normpath(build_file)):
+      all_qualified_targets.add(qualified_target)
+
+  for qualified_target in target_list:
+    WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
+                options, generator_flags, all_qualified_targets, output)
+
+  output.close()
+
+
+def PerformBuild(data, configurations, params):
+  options = params['options']
+  generator_flags = params['generator_flags']
+
+  # generator_dir: relative path from pwd to where make puts build files.
+  # Makes migrating from make to cmake easier, cmake doesn't put anything here.
+  generator_dir = os.path.relpath(options.generator_output or '.')
+
+  # output_dir: relative path from generator_dir to the build directory.
+  output_dir = generator_flags.get('output_dir', 'out')
+
+  for config_name in configurations:
+    # build_dir: relative path from source root to our output files.
+    # e.g. "out/Debug"
+    build_dir = os.path.normpath(os.path.join(generator_dir,
+                                              output_dir,
+                                              config_name))
+    arguments = ['cmake', '-G', 'Ninja']
+    print 'Generating [%s]: %s' % (config_name, arguments)
+    subprocess.check_call(arguments, cwd=build_dir)
+
+    arguments = ['ninja', '-C', build_dir]
+    print 'Building [%s]: %s' % (config_name, arguments)
+    subprocess.check_call(arguments)
+
+
+def CallGenerateOutputForConfig(arglist):
+  # Ignore the interrupt signal so that the parent process catches it and
+  # kills all multiprocessing children.
+  signal.signal(signal.SIGINT, signal.SIG_IGN)
+
+  target_list, target_dicts, data, params, config_name = arglist
+  GenerateOutputForConfig(target_list, target_dicts, data, params, config_name)
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  user_config = params.get('generator_flags', {}).get('config', None)
+  if user_config:
+    GenerateOutputForConfig(target_list, target_dicts, data,
+                            params, user_config)
+  else:
+    config_names = target_dicts[target_list[0]]['configurations'].keys()
+    if params['parallel']:
+      try:
+        pool = multiprocessing.Pool(len(config_names))
+        arglists = []
+        for config_name in config_names:
+          arglists.append((target_list, target_dicts, data,
+                           params, config_name))
+          pool.map(CallGenerateOutputForConfig, arglists)
+      except KeyboardInterrupt, e:
+        pool.terminate()
+        raise e
+    else:
+      for config_name in config_names:
+        GenerateOutputForConfig(target_list, target_dicts, data,
+                                params, config_name)
diff --git a/gyp/pylib/gyp/generator/dump_dependency_json.py b/gyp/pylib/gyp/generator/dump_dependency_json.py
new file mode 100644 (file)
index 0000000..927ba6e
--- /dev/null
@@ -0,0 +1,81 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import os
+import gyp
+import gyp.common
+import gyp.msvs_emulation
+import json
+import sys
+
+generator_supports_multiple_toolsets = True
+
+generator_wants_static_library_dependencies_adjusted = False
+
+generator_default_variables = {
+}
+for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR',
+                'LIB_DIR', 'SHARED_LIB_DIR']:
+  # Some gyp steps fail if these are empty(!).
+  generator_default_variables[dirname] = 'dir'
+for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
+               'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
+               'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
+               'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
+               'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
+               'CONFIGURATION_NAME']:
+  generator_default_variables[unused] = ''
+
+
+def CalculateVariables(default_variables, params):
+  generator_flags = params.get('generator_flags', {})
+  for key, val in generator_flags.items():
+    default_variables.setdefault(key, val)
+  default_variables.setdefault('OS', gyp.common.GetFlavor(params))
+
+  flavor = gyp.common.GetFlavor(params)
+  if flavor =='win':
+    # Copy additional generator configuration data from VS, which is shared
+    # by the Windows Ninja generator.
+    import gyp.generator.msvs as msvs_generator
+    generator_additional_non_configuration_keys = getattr(msvs_generator,
+        'generator_additional_non_configuration_keys', [])
+    generator_additional_path_sections = getattr(msvs_generator,
+        'generator_additional_path_sections', [])
+
+    gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
+
+
+def CalculateGeneratorInputInfo(params):
+  """Calculate the generator specific info that gets fed to input (called by
+  gyp)."""
+  generator_flags = params.get('generator_flags', {})
+  if generator_flags.get('adjust_static_libraries', False):
+    global generator_wants_static_library_dependencies_adjusted
+    generator_wants_static_library_dependencies_adjusted = True
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  # Map of target -> list of targets it depends on.
+  edges = {}
+
+  # Queue of targets to visit.
+  targets_to_visit = target_list[:]
+
+  while len(targets_to_visit) > 0:
+    target = targets_to_visit.pop()
+    if target in edges:
+      continue
+    edges[target] = []
+
+    for dep in target_dicts[target].get('dependencies', []):
+      edges[target].append(dep)
+      targets_to_visit.append(dep)
+
+  filename = 'dump.json'
+  f = open(filename, 'w')
+  json.dump(edges, f)
+  f.close()
+  print 'Wrote json to %s.' % filename
diff --git a/gyp/pylib/gyp/generator/eclipse.py b/gyp/pylib/gyp/generator/eclipse.py
new file mode 100644 (file)
index 0000000..718eb5d
--- /dev/null
@@ -0,0 +1,334 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""GYP backend that generates Eclipse CDT settings files.
+
+This backend DOES NOT generate Eclipse CDT projects. Instead, it generates XML
+files that can be imported into an Eclipse CDT project. The XML file contains a
+list of include paths and symbols (i.e. defines).
+
+Because a full .cproject definition is not created by this generator, it's not
+possible to properly define the include dirs and symbols for each file
+individually.  Instead, one set of includes/symbols is generated for the entire
+project.  This works fairly well (and is a vast improvement in general), but may
+still result in a few indexer issues here and there.
+
+This generator has no automated tests, so expect it to be broken.
+"""
+
+from xml.sax.saxutils import escape
+import os.path
+import subprocess
+import gyp
+import gyp.common
+import gyp.msvs_emulation
+import shlex
+
+generator_wants_static_library_dependencies_adjusted = False
+
+generator_default_variables = {
+}
+
+for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']:
+  # Some gyp steps fail if these are empty(!).
+  generator_default_variables[dirname] = 'dir'
+
+for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
+               'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
+               'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
+               'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
+               'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
+               'CONFIGURATION_NAME']:
+  generator_default_variables[unused] = ''
+
+# Include dirs will occasionally use the SHARED_INTERMEDIATE_DIR variable as
+# part of the path when dealing with generated headers.  This value will be
+# replaced dynamically for each configuration.
+generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \
+    '$SHARED_INTERMEDIATE_DIR'
+
+
+def CalculateVariables(default_variables, params):
+  generator_flags = params.get('generator_flags', {})
+  for key, val in generator_flags.items():
+    default_variables.setdefault(key, val)
+  flavor = gyp.common.GetFlavor(params)
+  default_variables.setdefault('OS', flavor)
+  if flavor == 'win':
+    # Copy additional generator configuration data from VS, which is shared
+    # by the Eclipse generator.
+    import gyp.generator.msvs as msvs_generator
+    generator_additional_non_configuration_keys = getattr(msvs_generator,
+        'generator_additional_non_configuration_keys', [])
+    generator_additional_path_sections = getattr(msvs_generator,
+        'generator_additional_path_sections', [])
+
+    gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
+
+
+def CalculateGeneratorInputInfo(params):
+  """Calculate the generator specific info that gets fed to input (called by
+  gyp)."""
+  generator_flags = params.get('generator_flags', {})
+  if generator_flags.get('adjust_static_libraries', False):
+    global generator_wants_static_library_dependencies_adjusted
+    generator_wants_static_library_dependencies_adjusted = True
+
+
+def GetAllIncludeDirectories(target_list, target_dicts,
+                             shared_intermediate_dirs, config_name, params,
+                             compiler_path):
+  """Calculate the set of include directories to be used.
+
+  Returns:
+    A list including all the include_dir's specified for every target followed
+    by any include directories that were added as cflag compiler options.
+  """
+
+  gyp_includes_set = set()
+  compiler_includes_list = []
+
+  # Find compiler's default include dirs.
+  if compiler_path:
+    command = shlex.split(compiler_path)
+    command.extend(['-E', '-xc++', '-v', '-'])
+    proc = subprocess.Popen(args=command, stdin=subprocess.PIPE,
+                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    output = proc.communicate()[1]
+    # Extract the list of include dirs from the output, which has this format:
+    #   ...
+    #   #include "..." search starts here:
+    #   #include <...> search starts here:
+    #    /usr/include/c++/4.6
+    #    /usr/local/include
+    #   End of search list.
+    #   ...
+    in_include_list = False
+    for line in output.splitlines():
+      if line.startswith('#include'):
+        in_include_list = True
+        continue
+      if line.startswith('End of search list.'):
+        break
+      if in_include_list:
+        include_dir = line.strip()
+        if include_dir not in compiler_includes_list:
+          compiler_includes_list.append(include_dir)
+
+  flavor = gyp.common.GetFlavor(params)
+  if flavor == 'win':
+    generator_flags = params.get('generator_flags', {})
+  for target_name in target_list:
+    target = target_dicts[target_name]
+    if config_name in target['configurations']:
+      config = target['configurations'][config_name]
+
+      # Look for any include dirs that were explicitly added via cflags. This
+      # may be done in gyp files to force certain includes to come at the end.
+      # TODO(jgreenwald): Change the gyp files to not abuse cflags for this, and
+      # remove this.
+      if flavor == 'win':
+        msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags)
+        cflags = msvs_settings.GetCflags(config_name)
+      else:
+        cflags = config['cflags']
+      for cflag in cflags:
+        if cflag.startswith('-I'):
+          include_dir = cflag[2:]
+          if include_dir not in compiler_includes_list:
+            compiler_includes_list.append(include_dir)
+
+      # Find standard gyp include dirs.
+      if config.has_key('include_dirs'):
+        include_dirs = config['include_dirs']
+        for shared_intermediate_dir in shared_intermediate_dirs:
+          for include_dir in include_dirs:
+            include_dir = include_dir.replace('$SHARED_INTERMEDIATE_DIR',
+                                              shared_intermediate_dir)
+            if not os.path.isabs(include_dir):
+              base_dir = os.path.dirname(target_name)
+
+              include_dir = base_dir + '/' + include_dir
+              include_dir = os.path.abspath(include_dir)
+
+            gyp_includes_set.add(include_dir)
+
+  # Generate a list that has all the include dirs.
+  all_includes_list = list(gyp_includes_set)
+  all_includes_list.sort()
+  for compiler_include in compiler_includes_list:
+    if not compiler_include in gyp_includes_set:
+      all_includes_list.append(compiler_include)
+
+  # All done.
+  return all_includes_list
+
+
+def GetCompilerPath(target_list, data, options):
+  """Determine a command that can be used to invoke the compiler.
+
+  Returns:
+    If this is a gyp project that has explicit make settings, try to determine
+    the compiler from that.  Otherwise, see if a compiler was specified via the
+    CC_target environment variable.
+  """
+  # First, see if the compiler is configured in make's settings.
+  build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
+  make_global_settings_dict = data[build_file].get('make_global_settings', {})
+  for key, value in make_global_settings_dict:
+    if key in ['CC', 'CXX']:
+      return os.path.join(options.toplevel_dir, value)
+
+  # Check to see if the compiler was specified as an environment variable.
+  for key in ['CC_target', 'CC', 'CXX']:
+    compiler = os.environ.get(key)
+    if compiler:
+      return compiler
+
+  return 'gcc'
+
+
+def GetAllDefines(target_list, target_dicts, data, config_name, params,
+                  compiler_path):
+  """Calculate the defines for a project.
+
+  Returns:
+    A dict that includes explict defines declared in gyp files along with all of
+    the default defines that the compiler uses.
+  """
+
+  # Get defines declared in the gyp files.
+  all_defines = {}
+  flavor = gyp.common.GetFlavor(params)
+  if flavor == 'win':
+    generator_flags = params.get('generator_flags', {})
+  for target_name in target_list:
+    target = target_dicts[target_name]
+
+    if flavor == 'win':
+      msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags)
+      extra_defines = msvs_settings.GetComputedDefines(config_name)
+    else:
+      extra_defines = []
+    if config_name in target['configurations']:
+      config = target['configurations'][config_name]
+      target_defines = config['defines']
+    else:
+      target_defines = []
+    for define in target_defines + extra_defines:
+      split_define = define.split('=', 1)
+      if len(split_define) == 1:
+        split_define.append('1')
+      if split_define[0].strip() in all_defines:
+        # Already defined
+        continue
+      all_defines[split_define[0].strip()] = split_define[1].strip()
+  # Get default compiler defines (if possible).
+  if flavor == 'win':
+    return all_defines  # Default defines already processed in the loop above.
+  if compiler_path:
+    command = shlex.split(compiler_path)
+    command.extend(['-E', '-dM', '-'])
+    cpp_proc = subprocess.Popen(args=command, cwd='.',
+                                stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+    cpp_output = cpp_proc.communicate()[0]
+    cpp_lines = cpp_output.split('\n')
+    for cpp_line in cpp_lines:
+      if not cpp_line.strip():
+        continue
+      cpp_line_parts = cpp_line.split(' ', 2)
+      key = cpp_line_parts[1]
+      if len(cpp_line_parts) >= 3:
+        val = cpp_line_parts[2]
+      else:
+        val = '1'
+      all_defines[key] = val
+
+  return all_defines
+
+
+def WriteIncludePaths(out, eclipse_langs, include_dirs):
+  """Write the includes section of a CDT settings export file."""
+
+  out.write('  <section name="org.eclipse.cdt.internal.ui.wizards.' \
+            'settingswizards.IncludePaths">\n')
+  out.write('    <language name="holder for library settings"></language>\n')
+  for lang in eclipse_langs:
+    out.write('    <language name="%s">\n' % lang)
+    for include_dir in include_dirs:
+      out.write('      <includepath workspace_path="false">%s</includepath>\n' %
+                include_dir)
+    out.write('    </language>\n')
+  out.write('  </section>\n')
+
+
+def WriteMacros(out, eclipse_langs, defines):
+  """Write the macros section of a CDT settings export file."""
+
+  out.write('  <section name="org.eclipse.cdt.internal.ui.wizards.' \
+            'settingswizards.Macros">\n')
+  out.write('    <language name="holder for library settings"></language>\n')
+  for lang in eclipse_langs:
+    out.write('    <language name="%s">\n' % lang)
+    for key in sorted(defines.iterkeys()):
+      out.write('      <macro><name>%s</name><value>%s</value></macro>\n' %
+                (escape(key), escape(defines[key])))
+    out.write('    </language>\n')
+  out.write('  </section>\n')
+
+
+def GenerateOutputForConfig(target_list, target_dicts, data, params,
+                            config_name):
+  options = params['options']
+  generator_flags = params.get('generator_flags', {})
+
+  # build_dir: relative path from source root to our output files.
+  # e.g. "out/Debug"
+  build_dir = os.path.join(generator_flags.get('output_dir', 'out'),
+                           config_name)
+
+  toplevel_build = os.path.join(options.toplevel_dir, build_dir)
+  # Ninja uses out/Debug/gen while make uses out/Debug/obj/gen as the
+  # SHARED_INTERMEDIATE_DIR. Include both possible locations.
+  shared_intermediate_dirs = [os.path.join(toplevel_build, 'obj', 'gen'),
+                              os.path.join(toplevel_build, 'gen')]
+
+  out_name = os.path.join(toplevel_build, 'eclipse-cdt-settings.xml')
+  gyp.common.EnsureDirExists(out_name)
+  out = open(out_name, 'w')
+
+  out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+  out.write('<cdtprojectproperties>\n')
+
+  eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File',
+                   'GNU C++', 'GNU C', 'Assembly']
+  compiler_path = GetCompilerPath(target_list, data, options)
+  include_dirs = GetAllIncludeDirectories(target_list, target_dicts,
+                                          shared_intermediate_dirs, config_name,
+                                          params, compiler_path)
+  WriteIncludePaths(out, eclipse_langs, include_dirs)
+  defines = GetAllDefines(target_list, target_dicts, data, config_name, params,
+                          compiler_path)
+  WriteMacros(out, eclipse_langs, defines)
+
+  out.write('</cdtprojectproperties>\n')
+  out.close()
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  """Generate an XML settings file that can be imported into a CDT project."""
+
+  if params['options'].generator_output:
+    raise NotImplementedError, "--generator_output not implemented for eclipse"
+
+  user_config = params.get('generator_flags', {}).get('config', None)
+  if user_config:
+    GenerateOutputForConfig(target_list, target_dicts, data, params,
+                            user_config)
+  else:
+    config_names = target_dicts[target_list[0]]['configurations'].keys()
+    for config_name in config_names:
+      GenerateOutputForConfig(target_list, target_dicts, data, params,
+                              config_name)
+
diff --git a/gyp/pylib/gyp/generator/gypd.py b/gyp/pylib/gyp/generator/gypd.py
new file mode 100644 (file)
index 0000000..22ef57f
--- /dev/null
@@ -0,0 +1,87 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""gypd output module
+
+This module produces gyp input as its output.  Output files are given the
+.gypd extension to avoid overwriting the .gyp files that they are generated
+from.  Internal references to .gyp files (such as those found in
+"dependencies" sections) are not adjusted to point to .gypd files instead;
+unlike other paths, which are relative to the .gyp or .gypd file, such paths
+are relative to the directory from which gyp was run to create the .gypd file.
+
+This generator module is intended to be a sample and a debugging aid, hence
+the "d" for "debug" in .gypd.  It is useful to inspect the results of the
+various merges, expansions, and conditional evaluations performed by gyp
+and to see a representation of what would be fed to a generator module.
+
+It's not advisable to rename .gypd files produced by this module to .gyp,
+because they will have all merges, expansions, and evaluations already
+performed and the relevant constructs not present in the output; paths to
+dependencies may be wrong; and various sections that do not belong in .gyp
+files such as such as "included_files" and "*_excluded" will be present.
+Output will also be stripped of comments.  This is not intended to be a
+general-purpose gyp pretty-printer; for that, you probably just want to
+run "pprint.pprint(eval(open('source.gyp').read()))", which will still strip
+comments but won't do all of the other things done to this module's output.
+
+The specific formatting of the output generated by this module is subject
+to change.
+"""
+
+
+import gyp.common
+import errno
+import os
+import pprint
+
+
+# These variables should just be spit back out as variable references.
+_generator_identity_variables = [
+  'EXECUTABLE_PREFIX',
+  'EXECUTABLE_SUFFIX',
+  'INTERMEDIATE_DIR',
+  'PRODUCT_DIR',
+  'RULE_INPUT_ROOT',
+  'RULE_INPUT_DIRNAME',
+  'RULE_INPUT_EXT',
+  'RULE_INPUT_NAME',
+  'RULE_INPUT_PATH',
+  'SHARED_INTERMEDIATE_DIR',
+]
+
+# gypd doesn't define a default value for OS like many other generator
+# modules.  Specify "-D OS=whatever" on the command line to provide a value.
+generator_default_variables = {
+}
+
+# gypd supports multiple toolsets
+generator_supports_multiple_toolsets = True
+
+# TODO(mark): This always uses <, which isn't right.  The input module should
+# notify the generator to tell it which phase it is operating in, and this
+# module should use < for the early phase and then switch to > for the late
+# phase.  Bonus points for carrying @ back into the output too.
+for v in _generator_identity_variables:
+  generator_default_variables[v] = '<(%s)' % v
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  output_files = {}
+  for qualified_target in target_list:
+    [input_file, target] = \
+        gyp.common.ParseQualifiedTarget(qualified_target)[0:2]
+
+    if input_file[-4:] != '.gyp':
+      continue
+    input_file_stem = input_file[:-4]
+    output_file = input_file_stem + params['options'].suffix + '.gypd'
+
+    if not output_file in output_files:
+      output_files[output_file] = input_file
+
+  for output_file, input_file in output_files.iteritems():
+    output = open(output_file, 'w')
+    pprint.pprint(data[input_file], output)
+    output.close()
diff --git a/gyp/pylib/gyp/generator/gypsh.py b/gyp/pylib/gyp/generator/gypsh.py
new file mode 100644 (file)
index 0000000..bd405f4
--- /dev/null
@@ -0,0 +1,56 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""gypsh output module
+
+gypsh is a GYP shell.  It's not really a generator per se.  All it does is
+fire up an interactive Python session with a few local variables set to the
+variables passed to the generator.  Like gypd, it's intended as a debugging
+aid, to facilitate the exploration of .gyp structures after being processed
+by the input module.
+
+The expected usage is "gyp -f gypsh -D OS=desired_os".
+"""
+
+
+import code
+import sys
+
+
+# All of this stuff about generator variables was lovingly ripped from gypd.py.
+# That module has a much better description of what's going on and why.
+_generator_identity_variables = [
+  'EXECUTABLE_PREFIX',
+  'EXECUTABLE_SUFFIX',
+  'INTERMEDIATE_DIR',
+  'PRODUCT_DIR',
+  'RULE_INPUT_ROOT',
+  'RULE_INPUT_DIRNAME',
+  'RULE_INPUT_EXT',
+  'RULE_INPUT_NAME',
+  'RULE_INPUT_PATH',
+  'SHARED_INTERMEDIATE_DIR',
+]
+
+generator_default_variables = {
+}
+
+for v in _generator_identity_variables:
+  generator_default_variables[v] = '<(%s)' % v
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  locals = {
+        'target_list':  target_list,
+        'target_dicts': target_dicts,
+        'data':         data,
+      }
+
+  # Use a banner that looks like the stock Python one and like what
+  # code.interact uses by default, but tack on something to indicate what
+  # locals are available, and identify gypsh.
+  banner='Python %s on %s\nlocals.keys() = %s\ngypsh' % \
+         (sys.version, sys.platform, repr(sorted(locals.keys())))
+
+  code.interact(banner, local=locals)
diff --git a/gyp/pylib/gyp/generator/make.py b/gyp/pylib/gyp/generator/make.py
new file mode 100644 (file)
index 0000000..8c31d10
--- /dev/null
@@ -0,0 +1,2218 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Notes:
+#
+# This is all roughly based on the Makefile system used by the Linux
+# kernel, but is a non-recursive make -- we put the entire dependency
+# graph in front of make and let it figure it out.
+#
+# The code below generates a separate .mk file for each target, but
+# all are sourced by the top-level Makefile.  This means that all
+# variables in .mk-files clobber one another.  Be careful to use :=
+# where appropriate for immediate evaluation, and similarly to watch
+# that you're not relying on a variable value to last beween different
+# .mk files.
+#
+# TODOs:
+#
+# Global settings and utility functions are currently stuffed in the
+# toplevel Makefile.  It may make sense to generate some .mk files on
+# the side to keep the the files readable.
+
+import os
+import re
+import sys
+import subprocess
+import gyp
+import gyp.common
+import gyp.xcode_emulation
+from gyp.common import GetEnvironFallback
+from gyp.common import GypError
+
+generator_default_variables = {
+  'EXECUTABLE_PREFIX': '',
+  'EXECUTABLE_SUFFIX': '',
+  'STATIC_LIB_PREFIX': 'lib',
+  'SHARED_LIB_PREFIX': 'lib',
+  'STATIC_LIB_SUFFIX': '.a',
+  'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/$(TARGET)/geni',
+  'SHARED_INTERMEDIATE_DIR': '$(obj)/gen',
+  'PRODUCT_DIR': '$(builddir)',
+  'RULE_INPUT_ROOT': '%(INPUT_ROOT)s',  # This gets expanded by Python.
+  'RULE_INPUT_DIRNAME': '%(INPUT_DIRNAME)s',  # This gets expanded by Python.
+  'RULE_INPUT_PATH': '$(abspath $<)',
+  'RULE_INPUT_EXT': '$(suffix $<)',
+  'RULE_INPUT_NAME': '$(notdir $<)',
+  'CONFIGURATION_NAME': '$(BUILDTYPE)',
+}
+
+# Make supports multiple toolsets
+generator_supports_multiple_toolsets = True
+
+# Request sorted dependencies in the order from dependents to dependencies.
+generator_wants_sorted_dependencies = False
+
+# Placates pylint.
+generator_additional_non_configuration_keys = []
+generator_additional_path_sections = []
+generator_extra_sources_for_rules = []
+generator_filelist_paths = None
+
+
+def CalculateVariables(default_variables, params):
+  """Calculate additional variables for use in the build (called by gyp)."""
+  flavor = gyp.common.GetFlavor(params)
+  if flavor == 'mac':
+    default_variables.setdefault('OS', 'mac')
+    default_variables.setdefault('SHARED_LIB_SUFFIX', '.dylib')
+    default_variables.setdefault('SHARED_LIB_DIR',
+                                 generator_default_variables['PRODUCT_DIR'])
+    default_variables.setdefault('LIB_DIR',
+                                 generator_default_variables['PRODUCT_DIR'])
+
+    # Copy additional generator configuration data from Xcode, which is shared
+    # by the Mac Make generator.
+    import gyp.generator.xcode as xcode_generator
+    global generator_additional_non_configuration_keys
+    generator_additional_non_configuration_keys = getattr(xcode_generator,
+        'generator_additional_non_configuration_keys', [])
+    global generator_additional_path_sections
+    generator_additional_path_sections = getattr(xcode_generator,
+        'generator_additional_path_sections', [])
+    global generator_extra_sources_for_rules
+    generator_extra_sources_for_rules = getattr(xcode_generator,
+        'generator_extra_sources_for_rules', [])
+    COMPILABLE_EXTENSIONS.update({'.m': 'objc', '.mm' : 'objcxx'})
+  else:
+    operating_system = flavor
+    if flavor == 'android':
+      operating_system = 'linux'  # Keep this legacy behavior for now.
+    default_variables.setdefault('OS', operating_system)
+    default_variables.setdefault('SHARED_LIB_SUFFIX', '.so')
+    default_variables.setdefault('SHARED_LIB_DIR','$(builddir)/lib.$(TOOLSET)')
+    default_variables.setdefault('LIB_DIR', '$(obj).$(TOOLSET)')
+
+
+def CalculateGeneratorInputInfo(params):
+  """Calculate the generator specific info that gets fed to input (called by
+  gyp)."""
+  generator_flags = params.get('generator_flags', {})
+  android_ndk_version = generator_flags.get('android_ndk_version', None)
+  # Android NDK requires a strict link order.
+  if android_ndk_version:
+    global generator_wants_sorted_dependencies
+    generator_wants_sorted_dependencies = True
+
+  output_dir = params['options'].generator_output or \
+               params['options'].toplevel_dir
+  builddir_name = generator_flags.get('output_dir', 'out')
+  qualified_out_dir = os.path.normpath(os.path.join(
+    output_dir, builddir_name, 'gypfiles'))
+
+  global generator_filelist_paths
+  generator_filelist_paths = {
+    'toplevel': params['options'].toplevel_dir,
+    'qualified_out_dir': qualified_out_dir,
+  }
+
+
+# The .d checking code below uses these functions:
+# wildcard, sort, foreach, shell, wordlist
+# wildcard can handle spaces, the rest can't.
+# Since I could find no way to make foreach work with spaces in filenames
+# correctly, the .d files have spaces replaced with another character. The .d
+# file for
+#     Chromium\ Framework.framework/foo
+# is for example
+#     out/Release/.deps/out/Release/Chromium?Framework.framework/foo
+# This is the replacement character.
+SPACE_REPLACEMENT = '?'
+
+
+LINK_COMMANDS_LINUX = """\
+quiet_cmd_alink = AR($(TOOLSET)) $@
+cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
+
+quiet_cmd_alink_thin = AR($(TOOLSET)) $@
+cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
+
+# Due to circular dependencies between libraries :(, we wrap the
+# special "figure out circular dependencies" flags around the entire
+# input list during linking.
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
+
+# We support two kinds of shared objects (.so):
+# 1) shared_library, which is just bundling together many dependent libraries
+# into a link line.
+# 2) loadable_module, which is generating a module intended for dlopen().
+#
+# They differ only slightly:
+# In the former case, we want to package all dependent code into the .so.
+# In the latter case, we want to package just the API exposed by the
+# outermost module.
+# This means shared_library uses --whole-archive, while loadable_module doesn't.
+# (Note that --whole-archive is incompatible with the --start-group used in
+# normal linking.)
+
+# Other shared-object link notes:
+# - Set SONAME to the library filename so our binaries don't reference
+# the local, absolute paths used on the link command-line.
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
+
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
+"""
+
+LINK_COMMANDS_MAC = """\
+quiet_cmd_alink = LIBTOOL-STATIC $@
+cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^)
+
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
+
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
+
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
+"""
+
+LINK_COMMANDS_ANDROID = """\
+quiet_cmd_alink = AR($(TOOLSET)) $@
+cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
+
+quiet_cmd_alink_thin = AR($(TOOLSET)) $@
+cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
+
+# Due to circular dependencies between libraries :(, we wrap the
+# special "figure out circular dependencies" flags around the entire
+# input list during linking.
+quiet_cmd_link = LINK($(TOOLSET)) $@
+quiet_cmd_link_host = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
+cmd_link_host = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
+
+# Other shared-object link notes:
+# - Set SONAME to the library filename so our binaries don't reference
+# the local, absolute paths used on the link command-line.
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
+
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
+quiet_cmd_solink_module_host = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module_host = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
+"""
+
+
+LINK_COMMANDS_AIX = """\
+quiet_cmd_alink = AR($(TOOLSET)) $@
+cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
+
+quiet_cmd_alink_thin = AR($(TOOLSET)) $@
+cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
+
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
+
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
+
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
+"""
+
+
+# Header of toplevel Makefile.
+# This should go into the build tree, but it's easier to keep it here for now.
+SHARED_HEADER = ("""\
+# We borrow heavily from the kernel build setup, though we are simpler since
+# we don't have Kconfig tweaking settings on us.
+
+# The implicit make rules have it looking for RCS files, among other things.
+# We instead explicitly write all the rules we care about.
+# It's even quicker (saves ~200ms) to pass -r on the command line.
+MAKEFLAGS=-r
+
+# The source directory tree.
+srcdir := %(srcdir)s
+abs_srcdir := $(abspath $(srcdir))
+
+# The name of the builddir.
+builddir_name ?= %(builddir)s
+
+# The V=1 flag on command line makes us verbosely print command lines.
+ifdef V
+  quiet=
+else
+  quiet=quiet_
+endif
+
+# Specify BUILDTYPE=Release on the command line for a release build.
+BUILDTYPE ?= %(default_configuration)s
+
+# Directory all our build output goes into.
+# Note that this must be two directories beneath src/ for unit tests to pass,
+# as they reach into the src/ directory for data with relative paths.
+builddir ?= $(builddir_name)/$(BUILDTYPE)
+abs_builddir := $(abspath $(builddir))
+depsdir := $(builddir)/.deps
+
+# Object output directory.
+obj := $(builddir)/obj
+abs_obj := $(abspath $(obj))
+
+# We build up a list of every single one of the targets so we can slurp in the
+# generated dependency rule Makefiles in one pass.
+all_deps :=
+
+%(make_global_settings)s
+
+CC.target ?= %(CC.target)s
+CFLAGS.target ?= $(CFLAGS)
+CXX.target ?= %(CXX.target)s
+CXXFLAGS.target ?= $(CXXFLAGS)
+LINK.target ?= %(LINK.target)s
+LDFLAGS.target ?= $(LDFLAGS)
+AR.target ?= $(AR)
+
+# C++ apps need to be linked with g++.
+#
+# Note: flock is used to seralize linking. Linking is a memory-intensive
+# process so running parallel links can often lead to thrashing.  To disable
+# the serialization, override LINK via an envrionment variable as follows:
+#
+#   export LINK=g++
+#
+# This will allow make to invoke N linker processes as specified in -jN.
+LINK ?= %(flock)s $(builddir)/linker.lock $(CXX.target)
+
+# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
+# to replicate this environment fallback in make as well.
+CC.host ?= %(CC.host)s
+CFLAGS.host ?=
+CXX.host ?= %(CXX.host)s
+CXXFLAGS.host ?=
+LINK.host ?= %(LINK.host)s
+LDFLAGS.host ?=
+AR.host ?= %(AR.host)s
+
+# Define a dir function that can handle spaces.
+# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
+# "leading spaces cannot appear in the text of the first argument as written.
+# These characters can be put into the argument value by variable substitution."
+empty :=
+space := $(empty) $(empty)
+
+# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
+replace_spaces = $(subst $(space),""" + SPACE_REPLACEMENT + """,$1)
+unreplace_spaces = $(subst """ + SPACE_REPLACEMENT + """,$(space),$1)
+dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
+
+# Flags to make gcc output dependency info.  Note that you need to be
+# careful here to use the flags that ccache and distcc can understand.
+# We write to a dep file on the side first and then rename at the end
+# so we can't end up with a broken dep file.
+depfile = $(depsdir)/$(call replace_spaces,$@).d
+DEPFLAGS = -MMD -MF $(depfile).raw
+
+# We have to fixup the deps output in a few ways.
+# (1) the file output should mention the proper .o file.
+# ccache or distcc lose the path to the target, so we convert a rule of
+# the form:
+#   foobar.o: DEP1 DEP2
+# into
+#   path/to/foobar.o: DEP1 DEP2
+# (2) we want missing files not to cause us to fail to build.
+# We want to rewrite
+#   foobar.o: DEP1 DEP2 \\
+#               DEP3
+# to
+#   DEP1:
+#   DEP2:
+#   DEP3:
+# so if the files are missing, they're just considered phony rules.
+# We have to do some pretty insane escaping to get those backslashes
+# and dollar signs past make, the shell, and sed at the same time.
+# Doesn't work with spaces, but that's fine: .d files have spaces in
+# their names replaced with other characters."""
+r"""
+define fixup_dep
+# The depfile may not exist if the input file didn't have any #includes.
+touch $(depfile).raw
+# Fixup path as in (1).
+sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
+# Add extra rules as in (2).
+# We remove slashes and replace spaces with new lines;
+# remove blank lines;
+# delete the first line and append a colon to the remaining lines.
+sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
+  grep -v '^$$'                             |\
+  sed -e 1d -e 's|$$|:|'                     \
+    >> $(depfile)
+rm $(depfile).raw
+endef
+"""
+"""
+# Command definitions:
+# - cmd_foo is the actual command to run;
+# - quiet_cmd_foo is the brief-output summary of the command.
+
+quiet_cmd_cc = CC($(TOOLSET)) $@
+cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_cxx = CXX($(TOOLSET)) $@
+cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+%(extra_commands)s
+quiet_cmd_touch = TOUCH $@
+cmd_touch = touch $@
+
+quiet_cmd_copy = COPY $@
+# send stderr to /dev/null to ignore messages when linking directories.
+cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
+
+%(link_commands)s
+"""
+
+r"""
+# Define an escape_quotes function to escape single quotes.
+# This allows us to handle quotes properly as long as we always use
+# use single quotes and escape_quotes.
+escape_quotes = $(subst ','\'',$(1))
+# This comment is here just to include a ' to unconfuse syntax highlighting.
+# Define an escape_vars function to escape '$' variable syntax.
+# This allows us to read/write command lines with shell variables (e.g.
+# $LD_LIBRARY_PATH), without triggering make substitution.
+escape_vars = $(subst $$,$$$$,$(1))
+# Helper that expands to a shell command to echo a string exactly as it is in
+# make. This uses printf instead of echo because printf's behaviour with respect
+# to escape sequences is more portable than echo's across different shells
+# (e.g., dash, bash).
+exact_echo = printf '%%s\n' '$(call escape_quotes,$(1))'
+"""
+"""
+# Helper to compare the command we're about to run against the command
+# we logged the last time we ran the command.  Produces an empty
+# string (false) when the commands match.
+# Tricky point: Make has no string-equality test function.
+# The kernel uses the following, but it seems like it would have false
+# positives, where one string reordered its arguments.
+#   arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \\
+#                       $(filter-out $(cmd_$@), $(cmd_$(1))))
+# We instead substitute each for the empty string into the other, and
+# say they're equal if both substitutions produce the empty string.
+# .d files contain """ + SPACE_REPLACEMENT + \
+                   """ instead of spaces, take that into account.
+command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\\
+                       $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
+
+# Helper that is non-empty when a prerequisite changes.
+# Normally make does this implicitly, but we force rules to always run
+# so we can check their command lines.
+#   $? -- new prerequisites
+#   $| -- order-only dependencies
+prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
+
+# Helper that executes all postbuilds until one fails.
+define do_postbuilds
+  @E=0;\\
+  for p in $(POSTBUILDS); do\\
+    eval $$p;\\
+    E=$$?;\\
+    if [ $$E -ne 0 ]; then\\
+      break;\\
+    fi;\\
+  done;\\
+  if [ $$E -ne 0 ]; then\\
+    rm -rf "$@";\\
+    exit $$E;\\
+  fi
+endef
+
+# do_cmd: run a command via the above cmd_foo names, if necessary.
+# Should always run for a given target to handle command-line changes.
+# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
+# Third argument, if non-zero, makes it do POSTBUILDS processing.
+# Note: We intentionally do NOT call dirx for depfile, since it contains """ + \
+                                                     SPACE_REPLACEMENT + """ for
+# spaces already and dirx strips the """ + SPACE_REPLACEMENT + \
+                                     """ characters.
+define do_cmd
+$(if $(or $(command_changed),$(prereq_changed)),
+  @$(call exact_echo,  $($(quiet)cmd_$(1)))
+  @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
+  $(if $(findstring flock,$(word %(flock_index)d,$(cmd_$1))),
+    @$(cmd_$(1))
+    @echo "  $(quiet_cmd_$(1)): Finished",
+    @$(cmd_$(1))
+  )
+  @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
+  @$(if $(2),$(fixup_dep))
+  $(if $(and $(3), $(POSTBUILDS)),
+    $(call do_postbuilds)
+  )
+)
+endef
+
+# Declare the "%(default_target)s" target first so it is the default,
+# even though we don't have the deps yet.
+.PHONY: %(default_target)s
+%(default_target)s:
+
+# make looks for ways to re-generate included makefiles, but in our case, we
+# don't have a direct way. Explicitly telling make that it has nothing to do
+# for them makes it go faster.
+%%.d: ;
+
+# Use FORCE_DO_CMD to force a target to run.  Should be coupled with
+# do_cmd.
+.PHONY: FORCE_DO_CMD
+FORCE_DO_CMD:
+
+""")
+
+SHARED_HEADER_MAC_COMMANDS = """
+quiet_cmd_objc = CXX($(TOOLSET)) $@
+cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
+
+quiet_cmd_objcxx = CXX($(TOOLSET)) $@
+cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
+
+# Commands for precompiled header files.
+quiet_cmd_pch_c = CXX($(TOOLSET)) $@
+cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
+cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+quiet_cmd_pch_m = CXX($(TOOLSET)) $@
+cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
+quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
+cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
+
+# gyp-mac-tool is written next to the root Makefile by gyp.
+# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
+# already.
+quiet_cmd_mac_tool = MACTOOL $(4) $<
+cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@"
+
+quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
+cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
+
+quiet_cmd_infoplist = INFOPLIST $@
+cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
+"""
+
+
+def WriteRootHeaderSuffixRules(writer):
+  extensions = sorted(COMPILABLE_EXTENSIONS.keys(), key=str.lower)
+
+  writer.write('# Suffix rules, putting all outputs into $(obj).\n')
+  for ext in extensions:
+    writer.write('$(obj).$(TOOLSET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD\n' % ext)
+    writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext])
+
+  writer.write('\n# Try building from generated source, too.\n')
+  for ext in extensions:
+    writer.write(
+        '$(obj).$(TOOLSET)/%%.o: $(obj).$(TOOLSET)/%%%s FORCE_DO_CMD\n' % ext)
+    writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext])
+  writer.write('\n')
+  for ext in extensions:
+    writer.write('$(obj).$(TOOLSET)/%%.o: $(obj)/%%%s FORCE_DO_CMD\n' % ext)
+    writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext])
+  writer.write('\n')
+
+
+SHARED_HEADER_SUFFIX_RULES_COMMENT1 = ("""\
+# Suffix rules, putting all outputs into $(obj).
+""")
+
+
+SHARED_HEADER_SUFFIX_RULES_COMMENT2 = ("""\
+# Try building from generated source, too.
+""")
+
+
+SHARED_FOOTER = """\
+# "all" is a concatenation of the "all" targets from all the included
+# sub-makefiles. This is just here to clarify.
+all:
+
+# Add in dependency-tracking rules.  $(all_deps) is the list of every single
+# target in our tree. Only consider the ones with .d (dependency) info:
+d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
+ifneq ($(d_files),)
+  include $(d_files)
+endif
+"""
+
+header = """\
+# This file is generated by gyp; do not edit.
+
+"""
+
+# Maps every compilable file extension to the do_cmd that compiles it.
+COMPILABLE_EXTENSIONS = {
+  '.c': 'cc',
+  '.cc': 'cxx',
+  '.cpp': 'cxx',
+  '.cxx': 'cxx',
+  '.s': 'cc',
+  '.S': 'cc',
+}
+
+def Compilable(filename):
+  """Return true if the file is compilable (should be in OBJS)."""
+  for res in (filename.endswith(e) for e in COMPILABLE_EXTENSIONS):
+    if res:
+      return True
+  return False
+
+
+def Linkable(filename):
+  """Return true if the file is linkable (should be on the link line)."""
+  return filename.endswith('.o')
+
+
+def Target(filename):
+  """Translate a compilable filename to its .o target."""
+  return os.path.splitext(filename)[0] + '.o'
+
+
+def EscapeShellArgument(s):
+  """Quotes an argument so that it will be interpreted literally by a POSIX
+     shell. Taken from
+     http://stackoverflow.com/questions/35817/whats-the-best-way-to-escape-ossystem-calls-in-python
+     """
+  return "'" + s.replace("'", "'\\''") + "'"
+
+
+def EscapeMakeVariableExpansion(s):
+  """Make has its own variable expansion syntax using $. We must escape it for
+     string to be interpreted literally."""
+  return s.replace('$', '$$')
+
+
+def EscapeCppDefine(s):
+  """Escapes a CPP define so that it will reach the compiler unaltered."""
+  s = EscapeShellArgument(s)
+  s = EscapeMakeVariableExpansion(s)
+  # '#' characters must be escaped even embedded in a string, else Make will
+  # treat it as the start of a comment.
+  return s.replace('#', r'\#')
+
+
+def QuoteIfNecessary(string):
+  """TODO: Should this ideally be replaced with one or more of the above
+     functions?"""
+  if '"' in string:
+    string = '"' + string.replace('"', '\\"') + '"'
+  return string
+
+
+def StringToMakefileVariable(string):
+  """Convert a string to a value that is acceptable as a make variable name."""
+  return re.sub('[^a-zA-Z0-9_]', '_', string)
+
+
+srcdir_prefix = ''
+def Sourceify(path):
+  """Convert a path to its source directory form."""
+  if '$(' in path:
+    return path
+  if os.path.isabs(path):
+    return path
+  return srcdir_prefix + path
+
+
+def QuoteSpaces(s, quote=r'\ '):
+  return s.replace(' ', quote)
+
+
+# TODO: Avoid code duplication with _ValidateSourcesForMSVSProject in msvs.py.
+def _ValidateSourcesForOSX(spec, all_sources):
+  """Makes sure if duplicate basenames are not specified in the source list.
+
+  Arguments:
+    spec: The target dictionary containing the properties of the target.
+  """
+  if spec.get('type', None) != 'static_library':
+    return
+
+  basenames = {}
+  for source in all_sources:
+    name, ext = os.path.splitext(source)
+    is_compiled_file = ext in [
+        '.c', '.cc', '.cpp', '.cxx', '.m', '.mm', '.s', '.S']
+    if not is_compiled_file:
+      continue
+    basename = os.path.basename(name)  # Don't include extension.
+    basenames.setdefault(basename, []).append(source)
+
+  error = ''
+  for basename, files in basenames.iteritems():
+    if len(files) > 1:
+      error += '  %s: %s\n' % (basename, ' '.join(files))
+
+  if error:
+    print('static library %s has several files with the same basename:\n' %
+          spec['target_name'] + error + 'libtool on OS X will generate' +
+          ' warnings for them.')
+    raise GypError('Duplicate basenames in sources section, see list above')
+
+
+# Map from qualified target to path to output.
+target_outputs = {}
+# Map from qualified target to any linkable output.  A subset
+# of target_outputs.  E.g. when mybinary depends on liba, we want to
+# include liba in the linker line; when otherbinary depends on
+# mybinary, we just want to build mybinary first.
+target_link_deps = {}
+
+
+class MakefileWriter:
+  """MakefileWriter packages up the writing of one target-specific foobar.mk.
+
+  Its only real entry point is Write(), and is mostly used for namespacing.
+  """
+
+  def __init__(self, generator_flags, flavor):
+    self.generator_flags = generator_flags
+    self.flavor = flavor
+
+    self.suffix_rules_srcdir = {}
+    self.suffix_rules_objdir1 = {}
+    self.suffix_rules_objdir2 = {}
+
+    # Generate suffix rules for all compilable extensions.
+    for ext in COMPILABLE_EXTENSIONS.keys():
+      # Suffix rules for source folder.
+      self.suffix_rules_srcdir.update({ext: ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD
+       @$(call do_cmd,%s,1)
+""" % (ext, COMPILABLE_EXTENSIONS[ext]))})
+
+      # Suffix rules for generated source files.
+      self.suffix_rules_objdir1.update({ext: ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj).$(TOOLSET)/%%%s FORCE_DO_CMD
+       @$(call do_cmd,%s,1)
+""" % (ext, COMPILABLE_EXTENSIONS[ext]))})
+      self.suffix_rules_objdir2.update({ext: ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
+       @$(call do_cmd,%s,1)
+""" % (ext, COMPILABLE_EXTENSIONS[ext]))})
+
+
+  def Write(self, qualified_target, base_path, output_filename, spec, configs,
+            part_of_all):
+    """The main entry point: writes a .mk file for a single target.
+
+    Arguments:
+      qualified_target: target we're generating
+      base_path: path relative to source root we're building in, used to resolve
+                 target-relative paths
+      output_filename: output .mk file name to write
+      spec, configs: gyp info
+      part_of_all: flag indicating this target is part of 'all'
+    """
+    gyp.common.EnsureDirExists(output_filename)
+
+    self.fp = open(output_filename, 'w')
+
+    self.fp.write(header)
+
+    self.qualified_target = qualified_target
+    self.path = base_path
+    self.target = spec['target_name']
+    self.type = spec['type']
+    self.toolset = spec['toolset']
+
+    self.is_mac_bundle = gyp.xcode_emulation.IsMacBundle(self.flavor, spec)
+    if self.flavor == 'mac':
+      self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec)
+    else:
+      self.xcode_settings = None
+
+    deps, link_deps = self.ComputeDeps(spec)
+
+    # Some of the generation below can add extra output, sources, or
+    # link dependencies.  All of the out params of the functions that
+    # follow use names like extra_foo.
+    extra_outputs = []
+    extra_sources = []
+    extra_link_deps = []
+    extra_mac_bundle_resources = []
+    mac_bundle_deps = []
+
+    if self.is_mac_bundle:
+      self.output = self.ComputeMacBundleOutput(spec)
+      self.output_binary = self.ComputeMacBundleBinaryOutput(spec)
+    else:
+      self.output = self.output_binary = self.ComputeOutput(spec)
+
+    self.is_standalone_static_library = bool(
+        spec.get('standalone_static_library', 0))
+    self._INSTALLABLE_TARGETS = ('executable', 'loadable_module',
+                                 'shared_library')
+    if (self.is_standalone_static_library or
+        self.type in self._INSTALLABLE_TARGETS):
+      self.alias = os.path.basename(self.output)
+      install_path = self._InstallableTargetInstallPath()
+    else:
+      self.alias = self.output
+      install_path = self.output
+
+    self.WriteLn("TOOLSET := " + self.toolset)
+    self.WriteLn("TARGET := " + self.target)
+
+    # Actions must come first, since they can generate more OBJs for use below.
+    if 'actions' in spec:
+      self.WriteActions(spec['actions'], extra_sources, extra_outputs,
+                        extra_mac_bundle_resources, part_of_all)
+
+    # Rules must be early like actions.
+    if 'rules' in spec:
+      self.WriteRules(spec['rules'], extra_sources, extra_outputs,
+                      extra_mac_bundle_resources, part_of_all)
+
+    if 'copies' in spec:
+      self.WriteCopies(spec['copies'], extra_outputs, part_of_all)
+
+    # Bundle resources.
+    if self.is_mac_bundle:
+      all_mac_bundle_resources = (
+          spec.get('mac_bundle_resources', []) + extra_mac_bundle_resources)
+      self.WriteMacBundleResources(all_mac_bundle_resources, mac_bundle_deps)
+      self.WriteMacInfoPlist(mac_bundle_deps)
+
+    # Sources.
+    all_sources = spec.get('sources', []) + extra_sources
+    if all_sources:
+      if self.flavor == 'mac':
+        # libtool on OS X generates warnings for duplicate basenames in the same
+        # target.
+        _ValidateSourcesForOSX(spec, all_sources)
+      self.WriteSources(
+          configs, deps, all_sources, extra_outputs,
+          extra_link_deps, part_of_all,
+          gyp.xcode_emulation.MacPrefixHeader(
+              self.xcode_settings, lambda p: Sourceify(self.Absolutify(p)),
+              self.Pchify))
+      sources = filter(Compilable, all_sources)
+      if sources:
+        self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT1)
+        extensions = set([os.path.splitext(s)[1] for s in sources])
+        for ext in extensions:
+          if ext in self.suffix_rules_srcdir:
+            self.WriteLn(self.suffix_rules_srcdir[ext])
+        self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT2)
+        for ext in extensions:
+          if ext in self.suffix_rules_objdir1:
+            self.WriteLn(self.suffix_rules_objdir1[ext])
+        for ext in extensions:
+          if ext in self.suffix_rules_objdir2:
+            self.WriteLn(self.suffix_rules_objdir2[ext])
+        self.WriteLn('# End of this set of suffix rules')
+
+        # Add dependency from bundle to bundle binary.
+        if self.is_mac_bundle:
+          mac_bundle_deps.append(self.output_binary)
+
+    self.WriteTarget(spec, configs, deps, extra_link_deps + link_deps,
+                     mac_bundle_deps, extra_outputs, part_of_all)
+
+    # Update global list of target outputs, used in dependency tracking.
+    target_outputs[qualified_target] = install_path
+
+    # Update global list of link dependencies.
+    if self.type in ('static_library', 'shared_library'):
+      target_link_deps[qualified_target] = self.output_binary
+
+    # Currently any versions have the same effect, but in future the behavior
+    # could be different.
+    if self.generator_flags.get('android_ndk_version', None):
+      self.WriteAndroidNdkModuleRule(self.target, all_sources, link_deps)
+
+    self.fp.close()
+
+
+  def WriteSubMake(self, output_filename, makefile_path, targets, build_dir):
+    """Write a "sub-project" Makefile.
+
+    This is a small, wrapper Makefile that calls the top-level Makefile to build
+    the targets from a single gyp file (i.e. a sub-project).
+
+    Arguments:
+      output_filename: sub-project Makefile name to write
+      makefile_path: path to the top-level Makefile
+      targets: list of "all" targets for this sub-project
+      build_dir: build output directory, relative to the sub-project
+    """
+    gyp.common.EnsureDirExists(output_filename)
+    self.fp = open(output_filename, 'w')
+    self.fp.write(header)
+    # For consistency with other builders, put sub-project build output in the
+    # sub-project dir (see test/subdirectory/gyptest-subdir-all.py).
+    self.WriteLn('export builddir_name ?= %s' %
+                 os.path.join(os.path.dirname(output_filename), build_dir))
+    self.WriteLn('.PHONY: all')
+    self.WriteLn('all:')
+    if makefile_path:
+      makefile_path = ' -C ' + makefile_path
+    self.WriteLn('\t$(MAKE)%s %s' % (makefile_path, ' '.join(targets)))
+    self.fp.close()
+
+
+  def WriteActions(self, actions, extra_sources, extra_outputs,
+                   extra_mac_bundle_resources, part_of_all):
+    """Write Makefile code for any 'actions' from the gyp input.
+
+    extra_sources: a list that will be filled in with newly generated source
+                   files, if any
+    extra_outputs: a list that will be filled in with any outputs of these
+                   actions (used to make other pieces dependent on these
+                   actions)
+    part_of_all: flag indicating this target is part of 'all'
+    """
+    env = self.GetSortedXcodeEnv()
+    for action in actions:
+      name = StringToMakefileVariable('%s_%s' % (self.qualified_target,
+                                                 action['action_name']))
+      self.WriteLn('### Rules for action "%s":' % action['action_name'])
+      inputs = action['inputs']
+      outputs = action['outputs']
+
+      # Build up a list of outputs.
+      # Collect the output dirs we'll need.
+      dirs = set()
+      for out in outputs:
+        dir = os.path.split(out)[0]
+        if dir:
+          dirs.add(dir)
+      if int(action.get('process_outputs_as_sources', False)):
+        extra_sources += outputs
+      if int(action.get('process_outputs_as_mac_bundle_resources', False)):
+        extra_mac_bundle_resources += outputs
+
+      # Write the actual command.
+      action_commands = action['action']
+      if self.flavor == 'mac':
+        action_commands = [gyp.xcode_emulation.ExpandEnvVars(command, env)
+                          for command in action_commands]
+      command = gyp.common.EncodePOSIXShellList(action_commands)
+      if 'message' in action:
+        self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, action['message']))
+      else:
+        self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, name))
+      if len(dirs) > 0:
+        command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
+
+      cd_action = 'cd %s; ' % Sourceify(self.path or '.')
+
+      # command and cd_action get written to a toplevel variable called
+      # cmd_foo. Toplevel variables can't handle things that change per
+      # makefile like $(TARGET), so hardcode the target.
+      command = command.replace('$(TARGET)', self.target)
+      cd_action = cd_action.replace('$(TARGET)', self.target)
+
+      # Set LD_LIBRARY_PATH in case the action runs an executable from this
+      # build which links to shared libs from this build.
+      # actions run on the host, so they should in theory only use host
+      # libraries, but until everything is made cross-compile safe, also use
+      # target libraries.
+      # TODO(piman): when everything is cross-compile safe, remove lib.target
+      self.WriteLn('cmd_%s = LD_LIBRARY_PATH=$(builddir)/lib.host:'
+                   '$(builddir)/lib.target:$$LD_LIBRARY_PATH; '
+                   'export LD_LIBRARY_PATH; '
+                   '%s%s'
+                   % (name, cd_action, command))
+      self.WriteLn()
+      outputs = map(self.Absolutify, outputs)
+      # The makefile rules are all relative to the top dir, but the gyp actions
+      # are defined relative to their containing dir.  This replaces the obj
+      # variable for the action rule with an absolute version so that the output
+      # goes in the right place.
+      # Only write the 'obj' and 'builddir' rules for the "primary" output (:1);
+      # it's superfluous for the "extra outputs", and this avoids accidentally
+      # writing duplicate dummy rules for those outputs.
+      # Same for environment.
+      self.WriteLn("%s: obj := $(abs_obj)" % QuoteSpaces(outputs[0]))
+      self.WriteLn("%s: builddir := $(abs_builddir)" % QuoteSpaces(outputs[0]))
+      self.WriteSortedXcodeEnv(outputs[0], self.GetSortedXcodeEnv())
+
+      for input in inputs:
+        assert ' ' not in input, (
+            "Spaces in action input filenames not supported (%s)"  % input)
+      for output in outputs:
+        assert ' ' not in output, (
+            "Spaces in action output filenames not supported (%s)"  % output)
+
+      # See the comment in WriteCopies about expanding env vars.
+      outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs]
+      inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs]
+
+      self.WriteDoCmd(outputs, map(Sourceify, map(self.Absolutify, inputs)),
+                      part_of_all=part_of_all, command=name)
+
+      # Stuff the outputs in a variable so we can refer to them later.
+      outputs_variable = 'action_%s_outputs' % name
+      self.WriteLn('%s := %s' % (outputs_variable, ' '.join(outputs)))
+      extra_outputs.append('$(%s)' % outputs_variable)
+      self.WriteLn()
+
+    self.WriteLn()
+
+
+  def WriteRules(self, rules, extra_sources, extra_outputs,
+                 extra_mac_bundle_resources, part_of_all):
+    """Write Makefile code for any 'rules' from the gyp input.
+
+    extra_sources: a list that will be filled in with newly generated source
+                   files, if any
+    extra_outputs: a list that will be filled in with any outputs of these
+                   rules (used to make other pieces dependent on these rules)
+    part_of_all: flag indicating this target is part of 'all'
+    """
+    env = self.GetSortedXcodeEnv()
+    for rule in rules:
+      name = StringToMakefileVariable('%s_%s' % (self.qualified_target,
+                                                 rule['rule_name']))
+      count = 0
+      self.WriteLn('### Generated for rule %s:' % name)
+
+      all_outputs = []
+
+      for rule_source in rule.get('rule_sources', []):
+        dirs = set()
+        (rule_source_dirname, rule_source_basename) = os.path.split(rule_source)
+        (rule_source_root, rule_source_ext) = \
+            os.path.splitext(rule_source_basename)
+
+        outputs = [self.ExpandInputRoot(out, rule_source_root,
+                                        rule_source_dirname)
+                   for out in rule['outputs']]
+
+        for out in outputs:
+          dir = os.path.dirname(out)
+          if dir:
+            dirs.add(dir)
+        if int(rule.get('process_outputs_as_sources', False)):
+          extra_sources += outputs
+        if int(rule.get('process_outputs_as_mac_bundle_resources', False)):
+          extra_mac_bundle_resources += outputs
+        inputs = map(Sourceify, map(self.Absolutify, [rule_source] +
+                                    rule.get('inputs', [])))
+        actions = ['$(call do_cmd,%s_%d)' % (name, count)]
+
+        if name == 'resources_grit':
+          # HACK: This is ugly.  Grit intentionally doesn't touch the
+          # timestamp of its output file when the file doesn't change,
+          # which is fine in hash-based dependency systems like scons
+          # and forge, but not kosher in the make world.  After some
+          # discussion, hacking around it here seems like the least
+          # amount of pain.
+          actions += ['@touch --no-create $@']
+
+        # See the comment in WriteCopies about expanding env vars.
+        outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs]
+        inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs]
+
+        outputs = map(self.Absolutify, outputs)
+        all_outputs += outputs
+        # Only write the 'obj' and 'builddir' rules for the "primary" output
+        # (:1); it's superfluous for the "extra outputs", and this avoids
+        # accidentally writing duplicate dummy rules for those outputs.
+        self.WriteLn('%s: obj := $(abs_obj)' % outputs[0])
+        self.WriteLn('%s: builddir := $(abs_builddir)' % outputs[0])
+        self.WriteMakeRule(outputs, inputs + ['FORCE_DO_CMD'], actions)
+        # Spaces in rule filenames are not supported, but rule variables have
+        # spaces in them (e.g. RULE_INPUT_PATH expands to '$(abspath $<)').
+        # The spaces within the variables are valid, so remove the variables
+        # before checking.
+        variables_with_spaces = re.compile(r'\$\([^ ]* \$<\)')
+        for output in outputs:
+          output = re.sub(variables_with_spaces, '', output)
+          assert ' ' not in output, (
+              "Spaces in rule filenames not yet supported (%s)"  % output)
+        self.WriteLn('all_deps += %s' % ' '.join(outputs))
+
+        action = [self.ExpandInputRoot(ac, rule_source_root,
+                                       rule_source_dirname)
+                  for ac in rule['action']]
+        mkdirs = ''
+        if len(dirs) > 0:
+          mkdirs = 'mkdir -p %s; ' % ' '.join(dirs)
+        cd_action = 'cd %s; ' % Sourceify(self.path or '.')
+
+        # action, cd_action, and mkdirs get written to a toplevel variable
+        # called cmd_foo. Toplevel variables can't handle things that change
+        # per makefile like $(TARGET), so hardcode the target.
+        if self.flavor == 'mac':
+          action = [gyp.xcode_emulation.ExpandEnvVars(command, env)
+                    for command in action]
+        action = gyp.common.EncodePOSIXShellList(action)
+        action = action.replace('$(TARGET)', self.target)
+        cd_action = cd_action.replace('$(TARGET)', self.target)
+        mkdirs = mkdirs.replace('$(TARGET)', self.target)
+
+        # Set LD_LIBRARY_PATH in case the rule runs an executable from this
+        # build which links to shared libs from this build.
+        # rules run on the host, so they should in theory only use host
+        # libraries, but until everything is made cross-compile safe, also use
+        # target libraries.
+        # TODO(piman): when everything is cross-compile safe, remove lib.target
+        self.WriteLn(
+            "cmd_%(name)s_%(count)d = LD_LIBRARY_PATH="
+              "$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; "
+              "export LD_LIBRARY_PATH; "
+              "%(cd_action)s%(mkdirs)s%(action)s" % {
+          'action': action,
+          'cd_action': cd_action,
+          'count': count,
+          'mkdirs': mkdirs,
+          'name': name,
+        })
+        self.WriteLn(
+            'quiet_cmd_%(name)s_%(count)d = RULE %(name)s_%(count)d $@' % {
+          'count': count,
+          'name': name,
+        })
+        self.WriteLn()
+        count += 1
+
+      outputs_variable = 'rule_%s_outputs' % name
+      self.WriteList(all_outputs, outputs_variable)
+      extra_outputs.append('$(%s)' % outputs_variable)
+
+      self.WriteLn('### Finished generating for rule: %s' % name)
+      self.WriteLn()
+    self.WriteLn('### Finished generating for all rules')
+    self.WriteLn('')
+
+
+  def WriteCopies(self, copies, extra_outputs, part_of_all):
+    """Write Makefile code for any 'copies' from the gyp input.
+
+    extra_outputs: a list that will be filled in with any outputs of this action
+                   (used to make other pieces dependent on this action)
+    part_of_all: flag indicating this target is part of 'all'
+    """
+    self.WriteLn('### Generated for copy rule.')
+
+    variable = StringToMakefileVariable(self.qualified_target + '_copies')
+    outputs = []
+    for copy in copies:
+      for path in copy['files']:
+        # Absolutify() may call normpath, and will strip trailing slashes.
+        path = Sourceify(self.Absolutify(path))
+        filename = os.path.split(path)[1]
+        output = Sourceify(self.Absolutify(os.path.join(copy['destination'],
+                                                        filename)))
+
+        # If the output path has variables in it, which happens in practice for
+        # 'copies', writing the environment as target-local doesn't work,
+        # because the variables are already needed for the target name.
+        # Copying the environment variables into global make variables doesn't
+        # work either, because then the .d files will potentially contain spaces
+        # after variable expansion, and .d file handling cannot handle spaces.
+        # As a workaround, manually expand variables at gyp time. Since 'copies'
+        # can't run scripts, there's no need to write the env then.
+        # WriteDoCmd() will escape spaces for .d files.
+        env = self.GetSortedXcodeEnv()
+        output = gyp.xcode_emulation.ExpandEnvVars(output, env)
+        path = gyp.xcode_emulation.ExpandEnvVars(path, env)
+        self.WriteDoCmd([output], [path], 'copy', part_of_all)
+        outputs.append(output)
+    self.WriteLn('%s = %s' % (variable, ' '.join(map(QuoteSpaces, outputs))))
+    extra_outputs.append('$(%s)' % variable)
+    self.WriteLn()
+
+
+  def WriteMacBundleResources(self, resources, bundle_deps):
+    """Writes Makefile code for 'mac_bundle_resources'."""
+    self.WriteLn('### Generated for mac_bundle_resources')
+
+    for output, res in gyp.xcode_emulation.GetMacBundleResources(
+        generator_default_variables['PRODUCT_DIR'], self.xcode_settings,
+        map(Sourceify, map(self.Absolutify, resources))):
+      self.WriteDoCmd([output], [res], 'mac_tool,,,copy-bundle-resource',
+                      part_of_all=True)
+      bundle_deps.append(output)
+
+
+  def WriteMacInfoPlist(self, bundle_deps):
+    """Write Makefile code for bundle Info.plist files."""
+    info_plist, out, defines, extra_env = gyp.xcode_emulation.GetMacInfoPlist(
+        generator_default_variables['PRODUCT_DIR'], self.xcode_settings,
+        lambda p: Sourceify(self.Absolutify(p)))
+    if not info_plist:
+      return
+    if defines:
+      # Create an intermediate file to store preprocessed results.
+      intermediate_plist = ('$(obj).$(TOOLSET)/$(TARGET)/' +
+          os.path.basename(info_plist))
+      self.WriteList(defines, intermediate_plist + ': INFOPLIST_DEFINES', '-D',
+          quoter=EscapeCppDefine)
+      self.WriteMakeRule([intermediate_plist], [info_plist],
+          ['$(call do_cmd,infoplist)',
+           # "Convert" the plist so that any weird whitespace changes from the
+           # preprocessor do not affect the XML parser in mac_tool.
+           '@plutil -convert xml1 $@ $@'])
+      info_plist = intermediate_plist
+    # plists can contain envvars and substitute them into the file.
+    self.WriteSortedXcodeEnv(
+        out, self.GetSortedXcodeEnv(additional_settings=extra_env))
+    self.WriteDoCmd([out], [info_plist], 'mac_tool,,,copy-info-plist',
+                    part_of_all=True)
+    bundle_deps.append(out)
+
+
+  def WriteSources(self, configs, deps, sources,
+                   extra_outputs, extra_link_deps,
+                   part_of_all, precompiled_header):
+    """Write Makefile code for any 'sources' from the gyp input.
+    These are source files necessary to build the current target.
+
+    configs, deps, sources: input from gyp.
+    extra_outputs: a list of extra outputs this action should be dependent on;
+                   used to serialize action/rules before compilation
+    extra_link_deps: a list that will be filled in with any outputs of
+                     compilation (to be used in link lines)
+    part_of_all: flag indicating this target is part of 'all'
+    """
+
+    # Write configuration-specific variables for CFLAGS, etc.
+    for configname in sorted(configs.keys()):
+      config = configs[configname]
+      self.WriteList(config.get('defines'), 'DEFS_%s' % configname, prefix='-D',
+          quoter=EscapeCppDefine)
+
+      if self.flavor == 'mac':
+        cflags = self.xcode_settings.GetCflags(configname)
+        cflags_c = self.xcode_settings.GetCflagsC(configname)
+        cflags_cc = self.xcode_settings.GetCflagsCC(configname)
+        cflags_objc = self.xcode_settings.GetCflagsObjC(configname)
+        cflags_objcc = self.xcode_settings.GetCflagsObjCC(configname)
+      else:
+        cflags = config.get('cflags')
+        cflags_c = config.get('cflags_c')
+        cflags_cc = config.get('cflags_cc')
+
+      self.WriteLn("# Flags passed to all source files.");
+      self.WriteList(cflags, 'CFLAGS_%s' % configname)
+      self.WriteLn("# Flags passed to only C files.");
+      self.WriteList(cflags_c, 'CFLAGS_C_%s' % configname)
+      self.WriteLn("# Flags passed to only C++ files.");
+      self.WriteList(cflags_cc, 'CFLAGS_CC_%s' % configname)
+      if self.flavor == 'mac':
+        self.WriteLn("# Flags passed to only ObjC files.");
+        self.WriteList(cflags_objc, 'CFLAGS_OBJC_%s' % configname)
+        self.WriteLn("# Flags passed to only ObjC++ files.");
+        self.WriteList(cflags_objcc, 'CFLAGS_OBJCC_%s' % configname)
+      includes = config.get('include_dirs')
+      if includes:
+        includes = map(Sourceify, map(self.Absolutify, includes))
+      self.WriteList(includes, 'INCS_%s' % configname, prefix='-I')
+
+    compilable = filter(Compilable, sources)
+    objs = map(self.Objectify, map(self.Absolutify, map(Target, compilable)))
+    self.WriteList(objs, 'OBJS')
+
+    for obj in objs:
+      assert ' ' not in obj, (
+          "Spaces in object filenames not supported (%s)"  % obj)
+    self.WriteLn('# Add to the list of files we specially track '
+                 'dependencies for.')
+    self.WriteLn('all_deps += $(OBJS)')
+    self.WriteLn()
+
+    # Make sure our dependencies are built first.
+    if deps:
+      self.WriteMakeRule(['$(OBJS)'], deps,
+                         comment = 'Make sure our dependencies are built '
+                                   'before any of us.',
+                         order_only = True)
+
+    # Make sure the actions and rules run first.
+    # If they generate any extra headers etc., the per-.o file dep tracking
+    # will catch the proper rebuilds, so order only is still ok here.
+    if extra_outputs:
+      self.WriteMakeRule(['$(OBJS)'], extra_outputs,
+                         comment = 'Make sure our actions/rules run '
+                                   'before any of us.',
+                         order_only = True)
+
+    pchdeps = precompiled_header.GetObjDependencies(compilable, objs )
+    if pchdeps:
+      self.WriteLn('# Dependencies from obj files to their precompiled headers')
+      for source, obj, gch in pchdeps:
+        self.WriteLn('%s: %s' % (obj, gch))
+      self.WriteLn('# End precompiled header dependencies')
+
+    if objs:
+      extra_link_deps.append('$(OBJS)')
+      self.WriteLn("""\
+# CFLAGS et al overrides must be target-local.
+# See "Target-specific Variable Values" in the GNU Make manual.""")
+      self.WriteLn("$(OBJS): TOOLSET := $(TOOLSET)")
+      self.WriteLn("$(OBJS): GYP_CFLAGS := "
+                   "$(DEFS_$(BUILDTYPE)) "
+                   "$(INCS_$(BUILDTYPE)) "
+                   "%s " % precompiled_header.GetInclude('c') +
+                   "$(CFLAGS_$(BUILDTYPE)) "
+                   "$(CFLAGS_C_$(BUILDTYPE))")
+      self.WriteLn("$(OBJS): GYP_CXXFLAGS := "
+                   "$(DEFS_$(BUILDTYPE)) "
+                   "$(INCS_$(BUILDTYPE)) "
+                   "%s " % precompiled_header.GetInclude('cc') +
+                   "$(CFLAGS_$(BUILDTYPE)) "
+                   "$(CFLAGS_CC_$(BUILDTYPE))")
+      if self.flavor == 'mac':
+        self.WriteLn("$(OBJS): GYP_OBJCFLAGS := "
+                     "$(DEFS_$(BUILDTYPE)) "
+                     "$(INCS_$(BUILDTYPE)) "
+                     "%s " % precompiled_header.GetInclude('m') +
+                     "$(CFLAGS_$(BUILDTYPE)) "
+                     "$(CFLAGS_C_$(BUILDTYPE)) "
+                     "$(CFLAGS_OBJC_$(BUILDTYPE))")
+        self.WriteLn("$(OBJS): GYP_OBJCXXFLAGS := "
+                     "$(DEFS_$(BUILDTYPE)) "
+                     "$(INCS_$(BUILDTYPE)) "
+                     "%s " % precompiled_header.GetInclude('mm') +
+                     "$(CFLAGS_$(BUILDTYPE)) "
+                     "$(CFLAGS_CC_$(BUILDTYPE)) "
+                     "$(CFLAGS_OBJCC_$(BUILDTYPE))")
+
+    self.WritePchTargets(precompiled_header.GetPchBuildCommands())
+
+    # If there are any object files in our input file list, link them into our
+    # output.
+    extra_link_deps += filter(Linkable, sources)
+
+    self.WriteLn()
+
+  def WritePchTargets(self, pch_commands):
+    """Writes make rules to compile prefix headers."""
+    if not pch_commands:
+      return
+
+    for gch, lang_flag, lang, input in pch_commands:
+      extra_flags = {
+        'c': '$(CFLAGS_C_$(BUILDTYPE))',
+        'cc': '$(CFLAGS_CC_$(BUILDTYPE))',
+        'm': '$(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))',
+        'mm': '$(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))',
+      }[lang]
+      var_name = {
+        'c': 'GYP_PCH_CFLAGS',
+        'cc': 'GYP_PCH_CXXFLAGS',
+        'm': 'GYP_PCH_OBJCFLAGS',
+        'mm': 'GYP_PCH_OBJCXXFLAGS',
+      }[lang]
+      self.WriteLn("%s: %s := %s " % (gch, var_name, lang_flag) +
+                   "$(DEFS_$(BUILDTYPE)) "
+                   "$(INCS_$(BUILDTYPE)) "
+                   "$(CFLAGS_$(BUILDTYPE)) " +
+                   extra_flags)
+
+      self.WriteLn('%s: %s FORCE_DO_CMD' % (gch, input))
+      self.WriteLn('\t@$(call do_cmd,pch_%s,1)' % lang)
+      self.WriteLn('')
+      assert ' ' not in gch, (
+          "Spaces in gch filenames not supported (%s)"  % gch)
+      self.WriteLn('all_deps += %s' % gch)
+      self.WriteLn('')
+
+
+  def ComputeOutputBasename(self, spec):
+    """Return the 'output basename' of a gyp spec.
+
+    E.g., the loadable module 'foobar' in directory 'baz' will produce
+      'libfoobar.so'
+    """
+    assert not self.is_mac_bundle
+
+    if self.flavor == 'mac' and self.type in (
+        'static_library', 'executable', 'shared_library', 'loadable_module'):
+      return self.xcode_settings.GetExecutablePath()
+
+    target = spec['target_name']
+    target_prefix = ''
+    target_ext = ''
+    if self.type == 'static_library':
+      if target[:3] == 'lib':
+        target = target[3:]
+      target_prefix = 'lib'
+      target_ext = '.a'
+    elif self.type in ('loadable_module', 'shared_library'):
+      if target[:3] == 'lib':
+        target = target[3:]
+      target_prefix = 'lib'
+      target_ext = '.so'
+    elif self.type == 'none':
+      target = '%s.stamp' % target
+    elif self.type != 'executable':
+      print ("ERROR: What output file should be generated?",
+             "type", self.type, "target", target)
+
+    target_prefix = spec.get('product_prefix', target_prefix)
+    target = spec.get('product_name', target)
+    product_ext = spec.get('product_extension')
+    if product_ext:
+      target_ext = '.' + product_ext
+
+    return target_prefix + target + target_ext
+
+
+  def _InstallImmediately(self):
+    return self.toolset == 'target' and self.flavor == 'mac' and self.type in (
+          'static_library', 'executable', 'shared_library', 'loadable_module')
+
+
+  def ComputeOutput(self, spec):
+    """Return the 'output' (full output path) of a gyp spec.
+
+    E.g., the loadable module 'foobar' in directory 'baz' will produce
+      '$(obj)/baz/libfoobar.so'
+    """
+    assert not self.is_mac_bundle
+
+    path = os.path.join('$(obj).' + self.toolset, self.path)
+    if self.type == 'executable' or self._InstallImmediately():
+      path = '$(builddir)'
+    path = spec.get('product_dir', path)
+    return os.path.join(path, self.ComputeOutputBasename(spec))
+
+
+  def ComputeMacBundleOutput(self, spec):
+    """Return the 'output' (full output path) to a bundle output directory."""
+    assert self.is_mac_bundle
+    path = generator_default_variables['PRODUCT_DIR']
+    return os.path.join(path, self.xcode_settings.GetWrapperName())
+
+
+  def ComputeMacBundleBinaryOutput(self, spec):
+    """Return the 'output' (full output path) to the binary in a bundle."""
+    path = generator_default_variables['PRODUCT_DIR']
+    return os.path.join(path, self.xcode_settings.GetExecutablePath())
+
+
+  def ComputeDeps(self, spec):
+    """Compute the dependencies of a gyp spec.
+
+    Returns a tuple (deps, link_deps), where each is a list of
+    filenames that will need to be put in front of make for either
+    building (deps) or linking (link_deps).
+    """
+    deps = []
+    link_deps = []
+    if 'dependencies' in spec:
+      deps.extend([target_outputs[dep] for dep in spec['dependencies']
+                   if target_outputs[dep]])
+      for dep in spec['dependencies']:
+        if dep in target_link_deps:
+          link_deps.append(target_link_deps[dep])
+      deps.extend(link_deps)
+      # TODO: It seems we need to transitively link in libraries (e.g. -lfoo)?
+      # This hack makes it work:
+      # link_deps.extend(spec.get('libraries', []))
+    return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps))
+
+
+  def WriteDependencyOnExtraOutputs(self, target, extra_outputs):
+    self.WriteMakeRule([self.output_binary], extra_outputs,
+                       comment = 'Build our special outputs first.',
+                       order_only = True)
+
+
+  def WriteTarget(self, spec, configs, deps, link_deps, bundle_deps,
+                  extra_outputs, part_of_all):
+    """Write Makefile code to produce the final target of the gyp spec.
+
+    spec, configs: input from gyp.
+    deps, link_deps: dependency lists; see ComputeDeps()
+    extra_outputs: any extra outputs that our target should depend on
+    part_of_all: flag indicating this target is part of 'all'
+    """
+
+    self.WriteLn('### Rules for final target.')
+
+    if extra_outputs:
+      self.WriteDependencyOnExtraOutputs(self.output_binary, extra_outputs)
+      self.WriteMakeRule(extra_outputs, deps,
+                         comment=('Preserve order dependency of '
+                                  'special output on deps.'),
+                         order_only = True)
+
+    target_postbuilds = {}
+    if self.type != 'none':
+      for configname in sorted(configs.keys()):
+        config = configs[configname]
+        if self.flavor == 'mac':
+          ldflags = self.xcode_settings.GetLdflags(configname,
+              generator_default_variables['PRODUCT_DIR'],
+              lambda p: Sourceify(self.Absolutify(p)))
+
+          # TARGET_POSTBUILDS_$(BUILDTYPE) is added to postbuilds later on.
+          gyp_to_build = gyp.common.InvertRelativePath(self.path)
+          target_postbuild = self.xcode_settings.AddImplicitPostbuilds(
+              configname,
+              QuoteSpaces(os.path.normpath(os.path.join(gyp_to_build,
+                                                        self.output))),
+              QuoteSpaces(os.path.normpath(os.path.join(gyp_to_build,
+                                                        self.output_binary))))
+          if target_postbuild:
+            target_postbuilds[configname] = target_postbuild
+        else:
+          ldflags = config.get('ldflags', [])
+          # Compute an rpath for this output if needed.
+          if any(dep.endswith('.so') or '.so.' in dep for dep in deps):
+            # We want to get the literal string "$ORIGIN" into the link command,
+            # so we need lots of escaping.
+            ldflags.append(r'-Wl,-rpath=\$$ORIGIN/lib.%s/' % self.toolset)
+            ldflags.append(r'-Wl,-rpath-link=\$(builddir)/lib.%s/' %
+                           self.toolset)
+        library_dirs = config.get('library_dirs', [])
+        ldflags += [('-L%s' % library_dir) for library_dir in library_dirs]
+        self.WriteList(ldflags, 'LDFLAGS_%s' % configname)
+        if self.flavor == 'mac':
+          self.WriteList(self.xcode_settings.GetLibtoolflags(configname),
+                         'LIBTOOLFLAGS_%s' % configname)
+      libraries = spec.get('libraries')
+      if libraries:
+        # Remove duplicate entries
+        libraries = gyp.common.uniquer(libraries)
+        if self.flavor == 'mac':
+          libraries = self.xcode_settings.AdjustLibraries(libraries)
+      self.WriteList(libraries, 'LIBS')
+      self.WriteLn('%s: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))' %
+          QuoteSpaces(self.output_binary))
+      self.WriteLn('%s: LIBS := $(LIBS)' % QuoteSpaces(self.output_binary))
+
+      if self.flavor == 'mac':
+        self.WriteLn('%s: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE))' %
+            QuoteSpaces(self.output_binary))
+
+    # Postbuild actions. Like actions, but implicitly depend on the target's
+    # output.
+    postbuilds = []
+    if self.flavor == 'mac':
+      if target_postbuilds:
+        postbuilds.append('$(TARGET_POSTBUILDS_$(BUILDTYPE))')
+      postbuilds.extend(
+          gyp.xcode_emulation.GetSpecPostbuildCommands(spec))
+
+    if postbuilds:
+      # Envvars may be referenced by TARGET_POSTBUILDS_$(BUILDTYPE),
+      # so we must output its definition first, since we declare variables
+      # using ":=".
+      self.WriteSortedXcodeEnv(self.output, self.GetSortedXcodePostbuildEnv())
+
+      for configname in target_postbuilds:
+        self.WriteLn('%s: TARGET_POSTBUILDS_%s := %s' %
+            (QuoteSpaces(self.output),
+             configname,
+             gyp.common.EncodePOSIXShellList(target_postbuilds[configname])))
+
+      # Postbuilds expect to be run in the gyp file's directory, so insert an
+      # implicit postbuild to cd to there.
+      postbuilds.insert(0, gyp.common.EncodePOSIXShellList(['cd', self.path]))
+      for i in xrange(len(postbuilds)):
+        if not postbuilds[i].startswith('$'):
+          postbuilds[i] = EscapeShellArgument(postbuilds[i])
+      self.WriteLn('%s: builddir := $(abs_builddir)' % QuoteSpaces(self.output))
+      self.WriteLn('%s: POSTBUILDS := %s' % (
+          QuoteSpaces(self.output), ' '.join(postbuilds)))
+
+    # A bundle directory depends on its dependencies such as bundle resources
+    # and bundle binary. When all dependencies have been built, the bundle
+    # needs to be packaged.
+    if self.is_mac_bundle:
+      # If the framework doesn't contain a binary, then nothing depends
+      # on the actions -- make the framework depend on them directly too.
+      self.WriteDependencyOnExtraOutputs(self.output, extra_outputs)
+
+      # Bundle dependencies. Note that the code below adds actions to this
+      # target, so if you move these two lines, move the lines below as well.
+      self.WriteList(map(QuoteSpaces, bundle_deps), 'BUNDLE_DEPS')
+      self.WriteLn('%s: $(BUNDLE_DEPS)' % QuoteSpaces(self.output))
+
+      # After the framework is built, package it. Needs to happen before
+      # postbuilds, since postbuilds depend on this.
+      if self.type in ('shared_library', 'loadable_module'):
+        self.WriteLn('\t@$(call do_cmd,mac_package_framework,,,%s)' %
+            self.xcode_settings.GetFrameworkVersion())
+
+      # Bundle postbuilds can depend on the whole bundle, so run them after
+      # the bundle is packaged, not already after the bundle binary is done.
+      if postbuilds:
+        self.WriteLn('\t@$(call do_postbuilds)')
+      postbuilds = []  # Don't write postbuilds for target's output.
+
+      # Needed by test/mac/gyptest-rebuild.py.
+      self.WriteLn('\t@true  # No-op, used by tests')
+
+      # Since this target depends on binary and resources which are in
+      # nested subfolders, the framework directory will be older than
+      # its dependencies usually. To prevent this rule from executing
+      # on every build (expensive, especially with postbuilds), expliclity
+      # update the time on the framework directory.
+      self.WriteLn('\t@touch -c %s' % QuoteSpaces(self.output))
+
+    if postbuilds:
+      assert not self.is_mac_bundle, ('Postbuilds for bundles should be done '
+          'on the bundle, not the binary (target \'%s\')' % self.target)
+      assert 'product_dir' not in spec, ('Postbuilds do not work with '
+          'custom product_dir')
+
+    if self.type == 'executable':
+      self.WriteLn('%s: LD_INPUTS := %s' % (
+          QuoteSpaces(self.output_binary),
+          ' '.join(map(QuoteSpaces, link_deps))))
+      if self.toolset == 'host' and self.flavor == 'android':
+        self.WriteDoCmd([self.output_binary], link_deps, 'link_host',
+                        part_of_all, postbuilds=postbuilds)
+      else:
+        self.WriteDoCmd([self.output_binary], link_deps, 'link', part_of_all,
+                        postbuilds=postbuilds)
+
+    elif self.type == 'static_library':
+      for link_dep in link_deps:
+        assert ' ' not in link_dep, (
+            "Spaces in alink input filenames not supported (%s)"  % link_dep)
+      if (self.flavor not in ('mac', 'openbsd', 'win') and not
+          self.is_standalone_static_library):
+        self.WriteDoCmd([self.output_binary], link_deps, 'alink_thin',
+                        part_of_all, postbuilds=postbuilds)
+      else:
+        self.WriteDoCmd([self.output_binary], link_deps, 'alink', part_of_all,
+                        postbuilds=postbuilds)
+    elif self.type == 'shared_library':
+      self.WriteLn('%s: LD_INPUTS := %s' % (
+            QuoteSpaces(self.output_binary),
+            ' '.join(map(QuoteSpaces, link_deps))))
+      self.WriteDoCmd([self.output_binary], link_deps, 'solink', part_of_all,
+                      postbuilds=postbuilds)
+    elif self.type == 'loadable_module':
+      for link_dep in link_deps:
+        assert ' ' not in link_dep, (
+            "Spaces in module input filenames not supported (%s)"  % link_dep)
+      if self.toolset == 'host' and self.flavor == 'android':
+        self.WriteDoCmd([self.output_binary], link_deps, 'solink_module_host',
+                        part_of_all, postbuilds=postbuilds)
+      else:
+        self.WriteDoCmd(
+            [self.output_binary], link_deps, 'solink_module', part_of_all,
+            postbuilds=postbuilds)
+    elif self.type == 'none':
+      # Write a stamp line.
+      self.WriteDoCmd([self.output_binary], deps, 'touch', part_of_all,
+                      postbuilds=postbuilds)
+    else:
+      print "WARNING: no output for", self.type, target
+
+    # Add an alias for each target (if there are any outputs).
+    # Installable target aliases are created below.
+    if ((self.output and self.output != self.target) and
+        (self.type not in self._INSTALLABLE_TARGETS)):
+      self.WriteMakeRule([self.target], [self.output],
+                         comment='Add target alias', phony = True)
+      if part_of_all:
+        self.WriteMakeRule(['all'], [self.target],
+                           comment = 'Add target alias to "all" target.',
+                           phony = True)
+
+    # Add special-case rules for our installable targets.
+    # 1) They need to install to the build dir or "product" dir.
+    # 2) They get shortcuts for building (e.g. "make chrome").
+    # 3) They are part of "make all".
+    if (self.type in self._INSTALLABLE_TARGETS or
+        self.is_standalone_static_library):
+      if self.type == 'shared_library':
+        file_desc = 'shared library'
+      elif self.type == 'static_library':
+        file_desc = 'static library'
+      else:
+        file_desc = 'executable'
+      install_path = self._InstallableTargetInstallPath()
+      installable_deps = [self.output]
+      if (self.flavor == 'mac' and not 'product_dir' in spec and
+          self.toolset == 'target'):
+        # On mac, products are created in install_path immediately.
+        assert install_path == self.output, '%s != %s' % (
+            install_path, self.output)
+
+      # Point the target alias to the final binary output.
+      self.WriteMakeRule([self.target], [install_path],
+                         comment='Add target alias', phony = True)
+      if install_path != self.output:
+        assert not self.is_mac_bundle  # See comment a few lines above.
+        self.WriteDoCmd([install_path], [self.output], 'copy',
+                        comment = 'Copy this to the %s output path.' %
+                        file_desc, part_of_all=part_of_all)
+        installable_deps.append(install_path)
+      if self.output != self.alias and self.alias != self.target:
+        self.WriteMakeRule([self.alias], installable_deps,
+                           comment = 'Short alias for building this %s.' %
+                           file_desc, phony = True)
+      if part_of_all:
+        self.WriteMakeRule(['all'], [install_path],
+                           comment = 'Add %s to "all" target.' % file_desc,
+                           phony = True)
+
+
+  def WriteList(self, value_list, variable=None, prefix='',
+                quoter=QuoteIfNecessary):
+    """Write a variable definition that is a list of values.
+
+    E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
+         foo = blaha blahb
+    but in a pretty-printed style.
+    """
+    values = ''
+    if value_list:
+      value_list = [quoter(prefix + l) for l in value_list]
+      values = ' \\\n\t' + ' \\\n\t'.join(value_list)
+    self.fp.write('%s :=%s\n\n' % (variable, values))
+
+
+  def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None,
+                 postbuilds=False):
+    """Write a Makefile rule that uses do_cmd.
+
+    This makes the outputs dependent on the command line that was run,
+    as well as support the V= make command line flag.
+    """
+    suffix = ''
+    if postbuilds:
+      assert ',' not in command
+      suffix = ',,1'  # Tell do_cmd to honor $POSTBUILDS
+    self.WriteMakeRule(outputs, inputs,
+                       actions = ['$(call do_cmd,%s%s)' % (command, suffix)],
+                       comment = comment,
+                       force = True)
+    # Add our outputs to the list of targets we read depfiles from.
+    # all_deps is only used for deps file reading, and for deps files we replace
+    # spaces with ? because escaping doesn't work with make's $(sort) and
+    # other functions.
+    outputs = [QuoteSpaces(o, SPACE_REPLACEMENT) for o in outputs]
+    self.WriteLn('all_deps += %s' % ' '.join(outputs))
+
+
+  def WriteMakeRule(self, outputs, inputs, actions=None, comment=None,
+                    order_only=False, force=False, phony=False):
+    """Write a Makefile rule, with some extra tricks.
+
+    outputs: a list of outputs for the rule (note: this is not directly
+             supported by make; see comments below)
+    inputs: a list of inputs for the rule
+    actions: a list of shell commands to run for the rule
+    comment: a comment to put in the Makefile above the rule (also useful
+             for making this Python script's code self-documenting)
+    order_only: if true, makes the dependency order-only
+    force: if true, include FORCE_DO_CMD as an order-only dep
+    phony: if true, the rule does not actually generate the named output, the
+           output is just a name to run the rule
+    """
+    outputs = map(QuoteSpaces, outputs)
+    inputs = map(QuoteSpaces, inputs)
+
+    if comment:
+      self.WriteLn('# ' + comment)
+    if phony:
+      self.WriteLn('.PHONY: ' + ' '.join(outputs))
+    # TODO(evanm): just make order_only a list of deps instead of these hacks.
+    if order_only:
+      order_insert = '| '
+      pick_output = ' '.join(outputs)
+    else:
+      order_insert = ''
+      pick_output = outputs[0]
+    if force:
+      force_append = ' FORCE_DO_CMD'
+    else:
+      force_append = ''
+    if actions:
+      self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0])
+    self.WriteLn('%s: %s%s%s' % (pick_output, order_insert, ' '.join(inputs),
+                                 force_append))
+    if actions:
+      for action in actions:
+        self.WriteLn('\t%s' % action)
+    if not order_only and len(outputs) > 1:
+      # If we have more than one output, a rule like
+      #   foo bar: baz
+      # that for *each* output we must run the action, potentially
+      # in parallel.  That is not what we're trying to write -- what
+      # we want is that we run the action once and it generates all
+      # the files.
+      # http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html
+      # discusses this problem and has this solution:
+      # 1) Write the naive rule that would produce parallel runs of
+      # the action.
+      # 2) Make the outputs seralized on each other, so we won't start
+      # a parallel run until the first run finishes, at which point
+      # we'll have generated all the outputs and we're done.
+      self.WriteLn('%s: %s' % (' '.join(outputs[1:]), outputs[0]))
+      # Add a dummy command to the "extra outputs" rule, otherwise make seems to
+      # think these outputs haven't (couldn't have?) changed, and thus doesn't
+      # flag them as changed (i.e. include in '$?') when evaluating dependent
+      # rules, which in turn causes do_cmd() to skip running dependent commands.
+      self.WriteLn('%s: ;' % (' '.join(outputs[1:])))
+    self.WriteLn()
+
+
+  def WriteAndroidNdkModuleRule(self, module_name, all_sources, link_deps):
+    """Write a set of LOCAL_XXX definitions for Android NDK.
+
+    These variable definitions will be used by Android NDK but do nothing for
+    non-Android applications.
+
+    Arguments:
+      module_name: Android NDK module name, which must be unique among all
+          module names.
+      all_sources: A list of source files (will be filtered by Compilable).
+      link_deps: A list of link dependencies, which must be sorted in
+          the order from dependencies to dependents.
+    """
+    if self.type not in ('executable', 'shared_library', 'static_library'):
+      return
+
+    self.WriteLn('# Variable definitions for Android applications')
+    self.WriteLn('include $(CLEAR_VARS)')
+    self.WriteLn('LOCAL_MODULE := ' + module_name)
+    self.WriteLn('LOCAL_CFLAGS := $(CFLAGS_$(BUILDTYPE)) '
+                 '$(DEFS_$(BUILDTYPE)) '
+                 # LOCAL_CFLAGS is applied to both of C and C++.  There is
+                 # no way to specify $(CFLAGS_C_$(BUILDTYPE)) only for C
+                 # sources.
+                 '$(CFLAGS_C_$(BUILDTYPE)) '
+                 # $(INCS_$(BUILDTYPE)) includes the prefix '-I' while
+                 # LOCAL_C_INCLUDES does not expect it.  So put it in
+                 # LOCAL_CFLAGS.
+                 '$(INCS_$(BUILDTYPE))')
+    # LOCAL_CXXFLAGS is obsolete and LOCAL_CPPFLAGS is preferred.
+    self.WriteLn('LOCAL_CPPFLAGS := $(CFLAGS_CC_$(BUILDTYPE))')
+    self.WriteLn('LOCAL_C_INCLUDES :=')
+    self.WriteLn('LOCAL_LDLIBS := $(LDFLAGS_$(BUILDTYPE)) $(LIBS)')
+
+    # Detect the C++ extension.
+    cpp_ext = {'.cc': 0, '.cpp': 0, '.cxx': 0}
+    default_cpp_ext = '.cpp'
+    for filename in all_sources:
+      ext = os.path.splitext(filename)[1]
+      if ext in cpp_ext:
+        cpp_ext[ext] += 1
+        if cpp_ext[ext] > cpp_ext[default_cpp_ext]:
+          default_cpp_ext = ext
+    self.WriteLn('LOCAL_CPP_EXTENSION := ' + default_cpp_ext)
+
+    self.WriteList(map(self.Absolutify, filter(Compilable, all_sources)),
+                   'LOCAL_SRC_FILES')
+
+    # Filter out those which do not match prefix and suffix and produce
+    # the resulting list without prefix and suffix.
+    def DepsToModules(deps, prefix, suffix):
+      modules = []
+      for filepath in deps:
+        filename = os.path.basename(filepath)
+        if filename.startswith(prefix) and filename.endswith(suffix):
+          modules.append(filename[len(prefix):-len(suffix)])
+      return modules
+
+    # Retrieve the default value of 'SHARED_LIB_SUFFIX'
+    params = {'flavor': 'linux'}
+    default_variables = {}
+    CalculateVariables(default_variables, params)
+
+    self.WriteList(
+        DepsToModules(link_deps,
+                      generator_default_variables['SHARED_LIB_PREFIX'],
+                      default_variables['SHARED_LIB_SUFFIX']),
+        'LOCAL_SHARED_LIBRARIES')
+    self.WriteList(
+        DepsToModules(link_deps,
+                      generator_default_variables['STATIC_LIB_PREFIX'],
+                      generator_default_variables['STATIC_LIB_SUFFIX']),
+        'LOCAL_STATIC_LIBRARIES')
+
+    if self.type == 'executable':
+      self.WriteLn('include $(BUILD_EXECUTABLE)')
+    elif self.type == 'shared_library':
+      self.WriteLn('include $(BUILD_SHARED_LIBRARY)')
+    elif self.type == 'static_library':
+      self.WriteLn('include $(BUILD_STATIC_LIBRARY)')
+    self.WriteLn()
+
+
+  def WriteLn(self, text=''):
+    self.fp.write(text + '\n')
+
+
+  def GetSortedXcodeEnv(self, additional_settings=None):
+    return gyp.xcode_emulation.GetSortedXcodeEnv(
+        self.xcode_settings, "$(abs_builddir)",
+        os.path.join("$(abs_srcdir)", self.path), "$(BUILDTYPE)",
+        additional_settings)
+
+
+  def GetSortedXcodePostbuildEnv(self):
+    # CHROMIUM_STRIP_SAVE_FILE is a chromium-specific hack.
+    # TODO(thakis): It would be nice to have some general mechanism instead.
+    strip_save_file = self.xcode_settings.GetPerTargetSetting(
+        'CHROMIUM_STRIP_SAVE_FILE', '')
+    # Even if strip_save_file is empty, explicitly write it. Else a postbuild
+    # might pick up an export from an earlier target.
+    return self.GetSortedXcodeEnv(
+        additional_settings={'CHROMIUM_STRIP_SAVE_FILE': strip_save_file})
+
+
+  def WriteSortedXcodeEnv(self, target, env):
+    for k, v in env:
+      # For
+      #  foo := a\ b
+      # the escaped space does the right thing. For
+      #  export foo := a\ b
+      # it does not -- the backslash is written to the env as literal character.
+      # So don't escape spaces in |env[k]|.
+      self.WriteLn('%s: export %s := %s' % (QuoteSpaces(target), k, v))
+
+
+  def Objectify(self, path):
+    """Convert a path to its output directory form."""
+    if '$(' in path:
+      path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/' % self.toolset)
+    if not '$(obj)' in path:
+      path = '$(obj).%s/$(TARGET)/%s' % (self.toolset, path)
+    return path
+
+
+  def Pchify(self, path, lang):
+    """Convert a prefix header path to its output directory form."""
+    path = self.Absolutify(path)
+    if '$(' in path:
+      path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/pch-%s' %
+                          (self.toolset, lang))
+      return path
+    return '$(obj).%s/$(TARGET)/pch-%s/%s' % (self.toolset, lang, path)
+
+
+  def Absolutify(self, path):
+    """Convert a subdirectory-relative path into a base-relative path.
+    Skips over paths that contain variables."""
+    if '$(' in path:
+      # Don't call normpath in this case, as it might collapse the
+      # path too aggressively if it features '..'. However it's still
+      # important to strip trailing slashes.
+      return path.rstrip('/')
+    return os.path.normpath(os.path.join(self.path, path))
+
+
+  def ExpandInputRoot(self, template, expansion, dirname):
+    if '%(INPUT_ROOT)s' not in template and '%(INPUT_DIRNAME)s' not in template:
+      return template
+    path = template % {
+        'INPUT_ROOT': expansion,
+        'INPUT_DIRNAME': dirname,
+        }
+    return path
+
+
+  def _InstallableTargetInstallPath(self):
+    """Returns the location of the final output for an installable target."""
+    # Xcode puts shared_library results into PRODUCT_DIR, and some gyp files
+    # rely on this. Emulate this behavior for mac.
+    if (self.type == 'shared_library' and
+        (self.flavor != 'mac' or self.toolset != 'target')):
+      # Install all shared libs into a common directory (per toolset) for
+      # convenient access with LD_LIBRARY_PATH.
+      return '$(builddir)/lib.%s/%s' % (self.toolset, self.alias)
+    return '$(builddir)/' + self.alias
+
+
+def WriteAutoRegenerationRule(params, root_makefile, makefile_name,
+                              build_files):
+  """Write the target to regenerate the Makefile."""
+  options = params['options']
+  build_files_args = [gyp.common.RelativePath(filename, options.toplevel_dir)
+                      for filename in params['build_files_arg']]
+
+  gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'],
+                                            options.toplevel_dir)
+  if not gyp_binary.startswith(os.sep):
+    gyp_binary = os.path.join('.', gyp_binary)
+
+  root_makefile.write(
+      "quiet_cmd_regen_makefile = ACTION Regenerating $@\n"
+      "cmd_regen_makefile = cd $(srcdir); %(cmd)s\n"
+      "%(makefile_name)s: %(deps)s\n"
+      "\t$(call do_cmd,regen_makefile)\n\n" % {
+          'makefile_name': makefile_name,
+          'deps': ' '.join(map(Sourceify, build_files)),
+          'cmd': gyp.common.EncodePOSIXShellList(
+                     [gyp_binary, '-fmake'] +
+                     gyp.RegenerateFlags(options) +
+                     build_files_args)})
+
+
+def PerformBuild(data, configurations, params):
+  options = params['options']
+  for config in configurations:
+    arguments = ['make']
+    if options.toplevel_dir and options.toplevel_dir != '.':
+      arguments += '-C', options.toplevel_dir
+    arguments.append('BUILDTYPE=' + config)
+    print 'Building [%s]: %s' % (config, arguments)
+    subprocess.check_call(arguments)
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  options = params['options']
+  flavor = gyp.common.GetFlavor(params)
+  generator_flags = params.get('generator_flags', {})
+  builddir_name = generator_flags.get('output_dir', 'out')
+  android_ndk_version = generator_flags.get('android_ndk_version', None)
+  default_target = generator_flags.get('default_target', 'all')
+
+  def CalculateMakefilePath(build_file, base_name):
+    """Determine where to write a Makefile for a given gyp file."""
+    # Paths in gyp files are relative to the .gyp file, but we want
+    # paths relative to the source root for the master makefile.  Grab
+    # the path of the .gyp file as the base to relativize against.
+    # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp".
+    base_path = gyp.common.RelativePath(os.path.dirname(build_file),
+                                        options.depth)
+    # We write the file in the base_path directory.
+    output_file = os.path.join(options.depth, base_path, base_name)
+    if options.generator_output:
+      output_file = os.path.join(
+          options.depth, options.generator_output, base_path, base_name)
+    base_path = gyp.common.RelativePath(os.path.dirname(build_file),
+                                        options.toplevel_dir)
+    return base_path, output_file
+
+  # TODO:  search for the first non-'Default' target.  This can go
+  # away when we add verification that all targets have the
+  # necessary configurations.
+  default_configuration = None
+  toolsets = set([target_dicts[target]['toolset'] for target in target_list])
+  for target in target_list:
+    spec = target_dicts[target]
+    if spec['default_configuration'] != 'Default':
+      default_configuration = spec['default_configuration']
+      break
+  if not default_configuration:
+    default_configuration = 'Default'
+
+  srcdir = '.'
+  makefile_name = 'Makefile' + options.suffix
+  makefile_path = os.path.join(options.toplevel_dir, makefile_name)
+  if options.generator_output:
+    global srcdir_prefix
+    makefile_path = os.path.join(
+        options.toplevel_dir, options.generator_output, makefile_name)
+    srcdir = gyp.common.RelativePath(srcdir, options.generator_output)
+    srcdir_prefix = '$(srcdir)/'
+
+  flock_command= 'flock'
+  header_params = {
+      'default_target': default_target,
+      'builddir': builddir_name,
+      'default_configuration': default_configuration,
+      'flock': flock_command,
+      'flock_index': 1,
+      'link_commands': LINK_COMMANDS_LINUX,
+      'extra_commands': '',
+      'srcdir': srcdir,
+    }
+  if flavor == 'mac':
+    flock_command = './gyp-mac-tool flock'
+    header_params.update({
+        'flock': flock_command,
+        'flock_index': 2,
+        'link_commands': LINK_COMMANDS_MAC,
+        'extra_commands': SHARED_HEADER_MAC_COMMANDS,
+    })
+  elif flavor == 'android':
+    header_params.update({
+        'link_commands': LINK_COMMANDS_ANDROID,
+    })
+  elif flavor == 'solaris':
+    header_params.update({
+        'flock': './gyp-flock-tool flock',
+        'flock_index': 2,
+    })
+  elif flavor == 'freebsd':
+    # Note: OpenBSD has sysutils/flock. lockf seems to be FreeBSD specific.
+    header_params.update({
+        'flock': 'lockf',
+    })
+  elif flavor == 'aix':
+    header_params.update({
+        'link_commands': LINK_COMMANDS_AIX,
+        'flock': './gyp-flock-tool flock',
+        'flock_index': 2,
+    })
+
+  header_params.update({
+    'CC.target':   GetEnvironFallback(('CC_target', 'CC'), '$(CC)'),
+    'AR.target':   GetEnvironFallback(('AR_target', 'AR'), '$(AR)'),
+    'CXX.target':  GetEnvironFallback(('CXX_target', 'CXX'), '$(CXX)'),
+    'LINK.target': GetEnvironFallback(('LINK_target', 'LINK'), '$(LINK)'),
+    'CC.host':     GetEnvironFallback(('CC_host',), 'gcc'),
+    'AR.host':     GetEnvironFallback(('AR_host',), 'ar'),
+    'CXX.host':    GetEnvironFallback(('CXX_host',), 'g++'),
+    'LINK.host':   GetEnvironFallback(('LINK_host',), '$(CXX.host)'),
+  })
+
+  build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
+  make_global_settings_array = data[build_file].get('make_global_settings', [])
+  wrappers = {}
+  wrappers['LINK'] = '%s $(builddir)/linker.lock' % flock_command
+  for key, value in make_global_settings_array:
+    if key.endswith('_wrapper'):
+      wrappers[key[:-len('_wrapper')]] = '$(abspath %s)' % value
+  make_global_settings = ''
+  for key, value in make_global_settings_array:
+    if re.match('.*_wrapper', key):
+      continue
+    if value[0] != '$':
+      value = '$(abspath %s)' % value
+    wrapper = wrappers.get(key)
+    if wrapper:
+      value = '%s %s' % (wrapper, value)
+      del wrappers[key]
+    if key in ('CC', 'CC.host', 'CXX', 'CXX.host'):
+      make_global_settings += (
+          'ifneq (,$(filter $(origin %s), undefined default))\n' % key)
+      # Let gyp-time envvars win over global settings.
+      env_key = key.replace('.', '_')  # CC.host -> CC_host
+      if env_key in os.environ:
+        value = os.environ[env_key]
+      make_global_settings += '  %s = %s\n' % (key, value)
+      make_global_settings += 'endif\n'
+    else:
+      make_global_settings += '%s ?= %s\n' % (key, value)
+  # TODO(ukai): define cmd when only wrapper is specified in
+  # make_global_settings.
+
+  header_params['make_global_settings'] = make_global_settings
+
+  gyp.common.EnsureDirExists(makefile_path)
+  root_makefile = open(makefile_path, 'w')
+  root_makefile.write(SHARED_HEADER % header_params)
+  # Currently any versions have the same effect, but in future the behavior
+  # could be different.
+  if android_ndk_version:
+    root_makefile.write(
+        '# Define LOCAL_PATH for build of Android applications.\n'
+        'LOCAL_PATH := $(call my-dir)\n'
+        '\n')
+  for toolset in toolsets:
+    root_makefile.write('TOOLSET := %s\n' % toolset)
+    WriteRootHeaderSuffixRules(root_makefile)
+
+  # Put build-time support tools next to the root Makefile.
+  dest_path = os.path.dirname(makefile_path)
+  gyp.common.CopyTool(flavor, dest_path)
+
+  # Find the list of targets that derive from the gyp file(s) being built.
+  needed_targets = set()
+  for build_file in params['build_files']:
+    for target in gyp.common.AllTargets(target_list, target_dicts, build_file):
+      needed_targets.add(target)
+
+  build_files = set()
+  include_list = set()
+  for qualified_target in target_list:
+    build_file, target, toolset = gyp.common.ParseQualifiedTarget(
+        qualified_target)
+
+    this_make_global_settings = data[build_file].get('make_global_settings', [])
+    assert make_global_settings_array == this_make_global_settings, (
+        "make_global_settings needs to be the same for all targets. %s vs. %s" %
+        (this_make_global_settings, make_global_settings))
+
+    build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir))
+    included_files = data[build_file]['included_files']
+    for included_file in included_files:
+      # The included_files entries are relative to the dir of the build file
+      # that included them, so we have to undo that and then make them relative
+      # to the root dir.
+      relative_include_file = gyp.common.RelativePath(
+          gyp.common.UnrelativePath(included_file, build_file),
+          options.toplevel_dir)
+      abs_include_file = os.path.abspath(relative_include_file)
+      # If the include file is from the ~/.gyp dir, we should use absolute path
+      # so that relocating the src dir doesn't break the path.
+      if (params['home_dot_gyp'] and
+          abs_include_file.startswith(params['home_dot_gyp'])):
+        build_files.add(abs_include_file)
+      else:
+        build_files.add(relative_include_file)
+
+    base_path, output_file = CalculateMakefilePath(build_file,
+        target + '.' + toolset + options.suffix + '.mk')
+
+    spec = target_dicts[qualified_target]
+    configs = spec['configurations']
+
+    if flavor == 'mac':
+      gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec)
+
+    writer = MakefileWriter(generator_flags, flavor)
+    writer.Write(qualified_target, base_path, output_file, spec, configs,
+                 part_of_all=qualified_target in needed_targets)
+
+    # Our root_makefile lives at the source root.  Compute the relative path
+    # from there to the output_file for including.
+    mkfile_rel_path = gyp.common.RelativePath(output_file,
+                                              os.path.dirname(makefile_path))
+    include_list.add(mkfile_rel_path)
+
+  # Write out per-gyp (sub-project) Makefiles.
+  depth_rel_path = gyp.common.RelativePath(options.depth, os.getcwd())
+  for build_file in build_files:
+    # The paths in build_files were relativized above, so undo that before
+    # testing against the non-relativized items in target_list and before
+    # calculating the Makefile path.
+    build_file = os.path.join(depth_rel_path, build_file)
+    gyp_targets = [target_dicts[target]['target_name'] for target in target_list
+                   if target.startswith(build_file) and
+                   target in needed_targets]
+    # Only generate Makefiles for gyp files with targets.
+    if not gyp_targets:
+      continue
+    base_path, output_file = CalculateMakefilePath(build_file,
+        os.path.splitext(os.path.basename(build_file))[0] + '.Makefile')
+    makefile_rel_path = gyp.common.RelativePath(os.path.dirname(makefile_path),
+                                                os.path.dirname(output_file))
+    writer.WriteSubMake(output_file, makefile_rel_path, gyp_targets,
+                        builddir_name)
+
+
+  # Write out the sorted list of includes.
+  root_makefile.write('\n')
+  for include_file in sorted(include_list):
+    # We wrap each .mk include in an if statement so users can tell make to
+    # not load a file by setting NO_LOAD.  The below make code says, only
+    # load the .mk file if the .mk filename doesn't start with a token in
+    # NO_LOAD.
+    root_makefile.write(
+        "ifeq ($(strip $(foreach prefix,$(NO_LOAD),\\\n"
+        "    $(findstring $(join ^,$(prefix)),\\\n"
+        "                 $(join ^," + include_file + ")))),)\n")
+    root_makefile.write("  include " + include_file + "\n")
+    root_makefile.write("endif\n")
+  root_makefile.write('\n')
+
+  if (not generator_flags.get('standalone')
+      and generator_flags.get('auto_regeneration', True)):
+    WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
+
+  root_makefile.write(SHARED_FOOTER)
+
+  root_makefile.close()
diff --git a/gyp/pylib/gyp/generator/msvs.py b/gyp/pylib/gyp/generator/msvs.py
new file mode 100644 (file)
index 0000000..80e3104
--- /dev/null
@@ -0,0 +1,3364 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import copy
+import ntpath
+import os
+import posixpath
+import re
+import subprocess
+import sys
+
+import gyp.common
+import gyp.easy_xml as easy_xml
+import gyp.generator.ninja as ninja_generator
+import gyp.MSVSNew as MSVSNew
+import gyp.MSVSProject as MSVSProject
+import gyp.MSVSSettings as MSVSSettings
+import gyp.MSVSToolFile as MSVSToolFile
+import gyp.MSVSUserFile as MSVSUserFile
+import gyp.MSVSUtil as MSVSUtil
+import gyp.MSVSVersion as MSVSVersion
+from gyp.common import GypError
+from gyp.common import OrderedSet
+
+# TODO: Remove once bots are on 2.7, http://crbug.com/241769
+def _import_OrderedDict():
+  import collections
+  try:
+    return collections.OrderedDict
+  except AttributeError:
+    import gyp.ordered_dict
+    return gyp.ordered_dict.OrderedDict
+OrderedDict = _import_OrderedDict()
+
+
+# Regular expression for validating Visual Studio GUIDs.  If the GUID
+# contains lowercase hex letters, MSVS will be fine. However,
+# IncrediBuild BuildConsole will parse the solution file, but then
+# silently skip building the target causing hard to track down errors.
+# Note that this only happens with the BuildConsole, and does not occur
+# if IncrediBuild is executed from inside Visual Studio.  This regex
+# validates that the string looks like a GUID with all uppercase hex
+# letters.
+VALID_MSVS_GUID_CHARS = re.compile('^[A-F0-9\-]+$')
+
+
+generator_default_variables = {
+    'EXECUTABLE_PREFIX': '',
+    'EXECUTABLE_SUFFIX': '.exe',
+    'STATIC_LIB_PREFIX': '',
+    'SHARED_LIB_PREFIX': '',
+    'STATIC_LIB_SUFFIX': '.lib',
+    'SHARED_LIB_SUFFIX': '.dll',
+    'INTERMEDIATE_DIR': '$(IntDir)',
+    'SHARED_INTERMEDIATE_DIR': '$(OutDir)obj/global_intermediate',
+    'OS': 'win',
+    'PRODUCT_DIR': '$(OutDir)',
+    'LIB_DIR': '$(OutDir)lib',
+    'RULE_INPUT_ROOT': '$(InputName)',
+    'RULE_INPUT_DIRNAME': '$(InputDir)',
+    'RULE_INPUT_EXT': '$(InputExt)',
+    'RULE_INPUT_NAME': '$(InputFileName)',
+    'RULE_INPUT_PATH': '$(InputPath)',
+    'CONFIGURATION_NAME': '$(ConfigurationName)',
+}
+
+
+# The msvs specific sections that hold paths
+generator_additional_path_sections = [
+    'msvs_cygwin_dirs',
+    'msvs_props',
+]
+
+
+generator_additional_non_configuration_keys = [
+    'msvs_cygwin_dirs',
+    'msvs_cygwin_shell',
+    'msvs_large_pdb',
+    'msvs_shard',
+    'msvs_external_builder',
+    'msvs_external_builder_out_dir',
+    'msvs_external_builder_build_cmd',
+    'msvs_external_builder_clean_cmd',
+    'msvs_external_builder_clcompile_cmd',
+]
+
+
+# List of precompiled header related keys.
+precomp_keys = [
+    'msvs_precompiled_header',
+    'msvs_precompiled_source',
+]
+
+
+cached_username = None
+
+
+cached_domain = None
+
+
+# TODO(gspencer): Switch the os.environ calls to be
+# win32api.GetDomainName() and win32api.GetUserName() once the
+# python version in depot_tools has been updated to work on Vista
+# 64-bit.
+def _GetDomainAndUserName():
+  if sys.platform not in ('win32', 'cygwin'):
+    return ('DOMAIN', 'USERNAME')
+  global cached_username
+  global cached_domain
+  if not cached_domain or not cached_username:
+    domain = os.environ.get('USERDOMAIN')
+    username = os.environ.get('USERNAME')
+    if not domain or not username:
+      call = subprocess.Popen(['net', 'config', 'Workstation'],
+                              stdout=subprocess.PIPE)
+      config = call.communicate()[0]
+      username_re = re.compile('^User name\s+(\S+)', re.MULTILINE)
+      username_match = username_re.search(config)
+      if username_match:
+        username = username_match.group(1)
+      domain_re = re.compile('^Logon domain\s+(\S+)', re.MULTILINE)
+      domain_match = domain_re.search(config)
+      if domain_match:
+        domain = domain_match.group(1)
+    cached_domain = domain
+    cached_username = username
+  return (cached_domain, cached_username)
+
+fixpath_prefix = None
+
+
+def _NormalizedSource(source):
+  """Normalize the path.
+
+  But not if that gets rid of a variable, as this may expand to something
+  larger than one directory.
+
+  Arguments:
+      source: The path to be normalize.d
+
+  Returns:
+      The normalized path.
+  """
+  normalized = os.path.normpath(source)
+  if source.count('$') == normalized.count('$'):
+    source = normalized
+  return source
+
+
+def _FixPath(path):
+  """Convert paths to a form that will make sense in a vcproj file.
+
+  Arguments:
+    path: The path to convert, may contain / etc.
+  Returns:
+    The path with all slashes made into backslashes.
+  """
+  if fixpath_prefix and path and not os.path.isabs(path) and not path[0] == '$':
+    path = os.path.join(fixpath_prefix, path)
+  path = path.replace('/', '\\')
+  path = _NormalizedSource(path)
+  if path and path[-1] == '\\':
+    path = path[:-1]
+  return path
+
+
+def _FixPaths(paths):
+  """Fix each of the paths of the list."""
+  return [_FixPath(i) for i in paths]
+
+
+def _ConvertSourcesToFilterHierarchy(sources, prefix=None, excluded=None,
+                                     list_excluded=True, msvs_version=None):
+  """Converts a list split source file paths into a vcproj folder hierarchy.
+
+  Arguments:
+    sources: A list of source file paths split.
+    prefix: A list of source file path layers meant to apply to each of sources.
+    excluded: A set of excluded files.
+    msvs_version: A MSVSVersion object.
+
+  Returns:
+    A hierarchy of filenames and MSVSProject.Filter objects that matches the
+    layout of the source tree.
+    For example:
+    _ConvertSourcesToFilterHierarchy([['a', 'bob1.c'], ['b', 'bob2.c']],
+                                     prefix=['joe'])
+    -->
+    [MSVSProject.Filter('a', contents=['joe\\a\\bob1.c']),
+     MSVSProject.Filter('b', contents=['joe\\b\\bob2.c'])]
+  """
+  if not prefix: prefix = []
+  result = []
+  excluded_result = []
+  folders = OrderedDict()
+  # Gather files into the final result, excluded, or folders.
+  for s in sources:
+    if len(s) == 1:
+      filename = _NormalizedSource('\\'.join(prefix + s))
+      if filename in excluded:
+        excluded_result.append(filename)
+      else:
+        result.append(filename)
+    elif msvs_version and not msvs_version.UsesVcxproj():
+      # For MSVS 2008 and earlier, we need to process all files before walking
+      # the sub folders.
+      if not folders.get(s[0]):
+        folders[s[0]] = []
+      folders[s[0]].append(s[1:])
+    else:
+      contents = _ConvertSourcesToFilterHierarchy([s[1:]], prefix + [s[0]],
+                                                  excluded=excluded,
+                                                  list_excluded=list_excluded,
+                                                  msvs_version=msvs_version)
+      contents = MSVSProject.Filter(s[0], contents=contents)
+      result.append(contents)
+  # Add a folder for excluded files.
+  if excluded_result and list_excluded:
+    excluded_folder = MSVSProject.Filter('_excluded_files',
+                                         contents=excluded_result)
+    result.append(excluded_folder)
+
+  if msvs_version and msvs_version.UsesVcxproj():
+    return result
+
+  # Populate all the folders.
+  for f in folders:
+    contents = _ConvertSourcesToFilterHierarchy(folders[f], prefix=prefix + [f],
+                                                excluded=excluded,
+                                                list_excluded=list_excluded,
+                                                msvs_version=msvs_version)
+    contents = MSVSProject.Filter(f, contents=contents)
+    result.append(contents)
+  return result
+
+
+def _ToolAppend(tools, tool_name, setting, value, only_if_unset=False):
+  if not value: return
+  _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset)
+
+
+def _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset=False):
+  # TODO(bradnelson): ugly hack, fix this more generally!!!
+  if 'Directories' in setting or 'Dependencies' in setting:
+    if type(value) == str:
+      value = value.replace('/', '\\')
+    else:
+      value = [i.replace('/', '\\') for i in value]
+  if not tools.get(tool_name):
+    tools[tool_name] = dict()
+  tool = tools[tool_name]
+  if tool.get(setting):
+    if only_if_unset: return
+    if type(tool[setting]) == list and type(value) == list:
+      tool[setting] += value
+    else:
+      raise TypeError(
+          'Appending "%s" to a non-list setting "%s" for tool "%s" is '
+          'not allowed, previous value: %s' % (
+              value, setting, tool_name, str(tool[setting])))
+  else:
+    tool[setting] = value
+
+
+def _ConfigPlatform(config_data):
+  return config_data.get('msvs_configuration_platform', 'Win32')
+
+
+def _ConfigBaseName(config_name, platform_name):
+  if config_name.endswith('_' + platform_name):
+    return config_name[0:-len(platform_name) - 1]
+  else:
+    return config_name
+
+
+def _ConfigFullName(config_name, config_data):
+  platform_name = _ConfigPlatform(config_data)
+  return '%s|%s' % (_ConfigBaseName(config_name, platform_name), platform_name)
+
+
+def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path,
+                                quote_cmd, do_setup_env):
+
+  if [x for x in cmd if '$(InputDir)' in x]:
+    input_dir_preamble = (
+      'set INPUTDIR=$(InputDir)\n'
+      'if NOT DEFINED INPUTDIR set INPUTDIR=.\\\n'
+      'set INPUTDIR=%INPUTDIR:~0,-1%\n'
+      )
+  else:
+    input_dir_preamble = ''
+
+  if cygwin_shell:
+    # Find path to cygwin.
+    cygwin_dir = _FixPath(spec.get('msvs_cygwin_dirs', ['.'])[0])
+    # Prepare command.
+    direct_cmd = cmd
+    direct_cmd = [i.replace('$(IntDir)',
+                            '`cygpath -m "${INTDIR}"`') for i in direct_cmd]
+    direct_cmd = [i.replace('$(OutDir)',
+                            '`cygpath -m "${OUTDIR}"`') for i in direct_cmd]
+    direct_cmd = [i.replace('$(InputDir)',
+                            '`cygpath -m "${INPUTDIR}"`') for i in direct_cmd]
+    if has_input_path:
+      direct_cmd = [i.replace('$(InputPath)',
+                              '`cygpath -m "${INPUTPATH}"`')
+                    for i in direct_cmd]
+    direct_cmd = ['\\"%s\\"' % i.replace('"', '\\\\\\"') for i in direct_cmd]
+    # direct_cmd = gyp.common.EncodePOSIXShellList(direct_cmd)
+    direct_cmd = ' '.join(direct_cmd)
+    # TODO(quote):  regularize quoting path names throughout the module
+    cmd = ''
+    if do_setup_env:
+      cmd += 'call "$(ProjectDir)%(cygwin_dir)s\\setup_env.bat" && '
+    cmd += 'set CYGWIN=nontsec&& '
+    if direct_cmd.find('NUMBER_OF_PROCESSORS') >= 0:
+      cmd += 'set /a NUMBER_OF_PROCESSORS_PLUS_1=%%NUMBER_OF_PROCESSORS%%+1&& '
+    if direct_cmd.find('INTDIR') >= 0:
+      cmd += 'set INTDIR=$(IntDir)&& '
+    if direct_cmd.find('OUTDIR') >= 0:
+      cmd += 'set OUTDIR=$(OutDir)&& '
+    if has_input_path and direct_cmd.find('INPUTPATH') >= 0:
+      cmd += 'set INPUTPATH=$(InputPath) && '
+    cmd += 'bash -c "%(cmd)s"'
+    cmd = cmd % {'cygwin_dir': cygwin_dir,
+                 'cmd': direct_cmd}
+    return input_dir_preamble + cmd
+  else:
+    # Convert cat --> type to mimic unix.
+    if cmd[0] == 'cat':
+      command = ['type']
+    else:
+      command = [cmd[0].replace('/', '\\')]
+    # Add call before command to ensure that commands can be tied together one
+    # after the other without aborting in Incredibuild, since IB makes a bat
+    # file out of the raw command string, and some commands (like python) are
+    # actually batch files themselves.
+    command.insert(0, 'call')
+    # Fix the paths
+    # TODO(quote): This is a really ugly heuristic, and will miss path fixing
+    #              for arguments like "--arg=path" or "/opt:path".
+    # If the argument starts with a slash or dash, it's probably a command line
+    # switch
+    arguments = [i if (i[:1] in "/-") else _FixPath(i) for i in cmd[1:]]
+    arguments = [i.replace('$(InputDir)', '%INPUTDIR%') for i in arguments]
+    arguments = [MSVSSettings.FixVCMacroSlashes(i) for i in arguments]
+    if quote_cmd:
+      # Support a mode for using cmd directly.
+      # Convert any paths to native form (first element is used directly).
+      # TODO(quote):  regularize quoting path names throughout the module
+      arguments = ['"%s"' % i for i in arguments]
+    # Collapse into a single command.
+    return input_dir_preamble + ' '.join(command + arguments)
+
+
+def _BuildCommandLineForRule(spec, rule, has_input_path, do_setup_env):
+  # Currently this weird argument munging is used to duplicate the way a
+  # python script would need to be run as part of the chrome tree.
+  # Eventually we should add some sort of rule_default option to set this
+  # per project. For now the behavior chrome needs is the default.
+  mcs = rule.get('msvs_cygwin_shell')
+  if mcs is None:
+    mcs = int(spec.get('msvs_cygwin_shell', 1))
+  elif isinstance(mcs, str):
+    mcs = int(mcs)
+  quote_cmd = int(rule.get('msvs_quote_cmd', 1))
+  return _BuildCommandLineForRuleRaw(spec, rule['action'], mcs, has_input_path,
+                                     quote_cmd, do_setup_env=do_setup_env)
+
+
+def _AddActionStep(actions_dict, inputs, outputs, description, command):
+  """Merge action into an existing list of actions.
+
+  Care must be taken so that actions which have overlapping inputs either don't
+  get assigned to the same input, or get collapsed into one.
+
+  Arguments:
+    actions_dict: dictionary keyed on input name, which maps to a list of
+      dicts describing the actions attached to that input file.
+    inputs: list of inputs
+    outputs: list of outputs
+    description: description of the action
+    command: command line to execute
+  """
+  # Require there to be at least one input (call sites will ensure this).
+  assert inputs
+
+  action = {
+      'inputs': inputs,
+      'outputs': outputs,
+      'description': description,
+      'command': command,
+  }
+
+  # Pick where to stick this action.
+  # While less than optimal in terms of build time, attach them to the first
+  # input for now.
+  chosen_input = inputs[0]
+
+  # Add it there.
+  if chosen_input not in actions_dict:
+    actions_dict[chosen_input] = []
+  actions_dict[chosen_input].append(action)
+
+
+def _AddCustomBuildToolForMSVS(p, spec, primary_input,
+                               inputs, outputs, description, cmd):
+  """Add a custom build tool to execute something.
+
+  Arguments:
+    p: the target project
+    spec: the target project dict
+    primary_input: input file to attach the build tool to
+    inputs: list of inputs
+    outputs: list of outputs
+    description: description of the action
+    cmd: command line to execute
+  """
+  inputs = _FixPaths(inputs)
+  outputs = _FixPaths(outputs)
+  tool = MSVSProject.Tool(
+      'VCCustomBuildTool',
+      {'Description': description,
+       'AdditionalDependencies': ';'.join(inputs),
+       'Outputs': ';'.join(outputs),
+       'CommandLine': cmd,
+      })
+  # Add to the properties of primary input for each config.
+  for config_name, c_data in spec['configurations'].iteritems():
+    p.AddFileConfig(_FixPath(primary_input),
+                    _ConfigFullName(config_name, c_data), tools=[tool])
+
+
+def _AddAccumulatedActionsToMSVS(p, spec, actions_dict):
+  """Add actions accumulated into an actions_dict, merging as needed.
+
+  Arguments:
+    p: the target project
+    spec: the target project dict
+    actions_dict: dictionary keyed on input name, which maps to a list of
+        dicts describing the actions attached to that input file.
+  """
+  for primary_input in actions_dict:
+    inputs = OrderedSet()
+    outputs = OrderedSet()
+    descriptions = []
+    commands = []
+    for action in actions_dict[primary_input]:
+      inputs.update(OrderedSet(action['inputs']))
+      outputs.update(OrderedSet(action['outputs']))
+      descriptions.append(action['description'])
+      commands.append(action['command'])
+    # Add the custom build step for one input file.
+    description = ', and also '.join(descriptions)
+    command = '\r\n'.join(commands)
+    _AddCustomBuildToolForMSVS(p, spec,
+                               primary_input=primary_input,
+                               inputs=inputs,
+                               outputs=outputs,
+                               description=description,
+                               cmd=command)
+
+
+def _RuleExpandPath(path, input_file):
+  """Given the input file to which a rule applied, string substitute a path.
+
+  Arguments:
+    path: a path to string expand
+    input_file: the file to which the rule applied.
+  Returns:
+    The string substituted path.
+  """
+  path = path.replace('$(InputName)',
+                      os.path.splitext(os.path.split(input_file)[1])[0])
+  path = path.replace('$(InputDir)', os.path.dirname(input_file))
+  path = path.replace('$(InputExt)',
+                      os.path.splitext(os.path.split(input_file)[1])[1])
+  path = path.replace('$(InputFileName)', os.path.split(input_file)[1])
+  path = path.replace('$(InputPath)', input_file)
+  return path
+
+
+def _FindRuleTriggerFiles(rule, sources):
+  """Find the list of files which a particular rule applies to.
+
+  Arguments:
+    rule: the rule in question
+    sources: the set of all known source files for this project
+  Returns:
+    The list of sources that trigger a particular rule.
+  """
+  return rule.get('rule_sources', [])
+
+
+def _RuleInputsAndOutputs(rule, trigger_file):
+  """Find the inputs and outputs generated by a rule.
+
+  Arguments:
+    rule: the rule in question.
+    trigger_file: the main trigger for this rule.
+  Returns:
+    The pair of (inputs, outputs) involved in this rule.
+  """
+  raw_inputs = _FixPaths(rule.get('inputs', []))
+  raw_outputs = _FixPaths(rule.get('outputs', []))
+  inputs = OrderedSet()
+  outputs = OrderedSet()
+  inputs.add(trigger_file)
+  for i in raw_inputs:
+    inputs.add(_RuleExpandPath(i, trigger_file))
+  for o in raw_outputs:
+    outputs.add(_RuleExpandPath(o, trigger_file))
+  return (inputs, outputs)
+
+
+def _GenerateNativeRulesForMSVS(p, rules, output_dir, spec, options):
+  """Generate a native rules file.
+
+  Arguments:
+    p: the target project
+    rules: the set of rules to include
+    output_dir: the directory in which the project/gyp resides
+    spec: the project dict
+    options: global generator options
+  """
+  rules_filename = '%s%s.rules' % (spec['target_name'],
+                                   options.suffix)
+  rules_file = MSVSToolFile.Writer(os.path.join(output_dir, rules_filename),
+                                   spec['target_name'])
+  # Add each rule.
+  for r in rules:
+    rule_name = r['rule_name']
+    rule_ext = r['extension']
+    inputs = _FixPaths(r.get('inputs', []))
+    outputs = _FixPaths(r.get('outputs', []))
+    # Skip a rule with no action and no inputs.
+    if 'action' not in r and not r.get('rule_sources', []):
+      continue
+    cmd = _BuildCommandLineForRule(spec, r, has_input_path=True,
+                                   do_setup_env=True)
+    rules_file.AddCustomBuildRule(name=rule_name,
+                                  description=r.get('message', rule_name),
+                                  extensions=[rule_ext],
+                                  additional_dependencies=inputs,
+                                  outputs=outputs,
+                                  cmd=cmd)
+  # Write out rules file.
+  rules_file.WriteIfChanged()
+
+  # Add rules file to project.
+  p.AddToolFile(rules_filename)
+
+
+def _Cygwinify(path):
+  path = path.replace('$(OutDir)', '$(OutDirCygwin)')
+  path = path.replace('$(IntDir)', '$(IntDirCygwin)')
+  return path
+
+
+def _GenerateExternalRules(rules, output_dir, spec,
+                           sources, options, actions_to_add):
+  """Generate an external makefile to do a set of rules.
+
+  Arguments:
+    rules: the list of rules to include
+    output_dir: path containing project and gyp files
+    spec: project specification data
+    sources: set of sources known
+    options: global generator options
+    actions_to_add: The list of actions we will add to.
+  """
+  filename = '%s_rules%s.mk' % (spec['target_name'], options.suffix)
+  mk_file = gyp.common.WriteOnDiff(os.path.join(output_dir, filename))
+  # Find cygwin style versions of some paths.
+  mk_file.write('OutDirCygwin:=$(shell cygpath -u "$(OutDir)")\n')
+  mk_file.write('IntDirCygwin:=$(shell cygpath -u "$(IntDir)")\n')
+  # Gather stuff needed to emit all: target.
+  all_inputs = OrderedSet()
+  all_outputs = OrderedSet()
+  all_output_dirs = OrderedSet()
+  first_outputs = []
+  for rule in rules:
+    trigger_files = _FindRuleTriggerFiles(rule, sources)
+    for tf in trigger_files:
+      inputs, outputs = _RuleInputsAndOutputs(rule, tf)
+      all_inputs.update(OrderedSet(inputs))
+      all_outputs.update(OrderedSet(outputs))
+      # Only use one target from each rule as the dependency for
+      # 'all' so we don't try to build each rule multiple times.
+      first_outputs.append(list(outputs)[0])
+      # Get the unique output directories for this rule.
+      output_dirs = [os.path.split(i)[0] for i in outputs]
+      for od in output_dirs:
+        all_output_dirs.add(od)
+  first_outputs_cyg = [_Cygwinify(i) for i in first_outputs]
+  # Write out all: target, including mkdir for each output directory.
+  mk_file.write('all: %s\n' % ' '.join(first_outputs_cyg))
+  for od in all_output_dirs:
+    if od:
+      mk_file.write('\tmkdir -p `cygpath -u "%s"`\n' % od)
+  mk_file.write('\n')
+  # Define how each output is generated.
+  for rule in rules:
+    trigger_files = _FindRuleTriggerFiles(rule, sources)
+    for tf in trigger_files:
+      # Get all the inputs and outputs for this rule for this trigger file.
+      inputs, outputs = _RuleInputsAndOutputs(rule, tf)
+      inputs = [_Cygwinify(i) for i in inputs]
+      outputs = [_Cygwinify(i) for i in outputs]
+      # Prepare the command line for this rule.
+      cmd = [_RuleExpandPath(c, tf) for c in rule['action']]
+      cmd = ['"%s"' % i for i in cmd]
+      cmd = ' '.join(cmd)
+      # Add it to the makefile.
+      mk_file.write('%s: %s\n' % (' '.join(outputs), ' '.join(inputs)))
+      mk_file.write('\t%s\n\n' % cmd)
+  # Close up the file.
+  mk_file.close()
+
+  # Add makefile to list of sources.
+  sources.add(filename)
+  # Add a build action to call makefile.
+  cmd = ['make',
+         'OutDir=$(OutDir)',
+         'IntDir=$(IntDir)',
+         '-j', '${NUMBER_OF_PROCESSORS_PLUS_1}',
+         '-f', filename]
+  cmd = _BuildCommandLineForRuleRaw(spec, cmd, True, False, True, True)
+  # Insert makefile as 0'th input, so it gets the action attached there,
+  # as this is easier to understand from in the IDE.
+  all_inputs = list(all_inputs)
+  all_inputs.insert(0, filename)
+  _AddActionStep(actions_to_add,
+                 inputs=_FixPaths(all_inputs),
+                 outputs=_FixPaths(all_outputs),
+                 description='Running external rules for %s' %
+                     spec['target_name'],
+                 command=cmd)
+
+
+def _EscapeEnvironmentVariableExpansion(s):
+  """Escapes % characters.
+
+  Escapes any % characters so that Windows-style environment variable
+  expansions will leave them alone.
+  See http://connect.microsoft.com/VisualStudio/feedback/details/106127/cl-d-name-text-containing-percentage-characters-doesnt-compile
+  to understand why we have to do this.
+
+  Args:
+      s: The string to be escaped.
+
+  Returns:
+      The escaped string.
+  """
+  s = s.replace('%', '%%')
+  return s
+
+
+quote_replacer_regex = re.compile(r'(\\*)"')
+
+
+def _EscapeCommandLineArgumentForMSVS(s):
+  """Escapes a Windows command-line argument.
+
+  So that the Win32 CommandLineToArgv function will turn the escaped result back
+  into the original string.
+  See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+  ("Parsing C++ Command-Line Arguments") to understand why we have to do
+  this.
+
+  Args:
+      s: the string to be escaped.
+  Returns:
+      the escaped string.
+  """
+
+  def _Replace(match):
+    # For a literal quote, CommandLineToArgv requires an odd number of
+    # backslashes preceding it, and it produces half as many literal backslashes
+    # (rounded down). So we need to produce 2n+1 backslashes.
+    return 2 * match.group(1) + '\\"'
+
+  # Escape all quotes so that they are interpreted literally.
+  s = quote_replacer_regex.sub(_Replace, s)
+  # Now add unescaped quotes so that any whitespace is interpreted literally.
+  s = '"' + s + '"'
+  return s
+
+
+delimiters_replacer_regex = re.compile(r'(\\*)([,;]+)')
+
+
+def _EscapeVCProjCommandLineArgListItem(s):
+  """Escapes command line arguments for MSVS.
+
+  The VCProj format stores string lists in a single string using commas and
+  semi-colons as separators, which must be quoted if they are to be
+  interpreted literally. However, command-line arguments may already have
+  quotes, and the VCProj parser is ignorant of the backslash escaping
+  convention used by CommandLineToArgv, so the command-line quotes and the
+  VCProj quotes may not be the same quotes. So to store a general
+  command-line argument in a VCProj list, we need to parse the existing
+  quoting according to VCProj's convention and quote any delimiters that are
+  not already quoted by that convention. The quotes that we add will also be
+  seen by CommandLineToArgv, so if backslashes precede them then we also have
+  to escape those backslashes according to the CommandLineToArgv
+  convention.
+
+  Args:
+      s: the string to be escaped.
+  Returns:
+      the escaped string.
+  """
+
+  def _Replace(match):
+    # For a non-literal quote, CommandLineToArgv requires an even number of
+    # backslashes preceding it, and it produces half as many literal
+    # backslashes. So we need to produce 2n backslashes.
+    return 2 * match.group(1) + '"' + match.group(2) + '"'
+
+  segments = s.split('"')
+  # The unquoted segments are at the even-numbered indices.
+  for i in range(0, len(segments), 2):
+    segments[i] = delimiters_replacer_regex.sub(_Replace, segments[i])
+  # Concatenate back into a single string
+  s = '"'.join(segments)
+  if len(segments) % 2 == 0:
+    # String ends while still quoted according to VCProj's convention. This
+    # means the delimiter and the next list item that follow this one in the
+    # .vcproj file will be misinterpreted as part of this item. There is nothing
+    # we can do about this. Adding an extra quote would correct the problem in
+    # the VCProj but cause the same problem on the final command-line. Moving
+    # the item to the end of the list does works, but that's only possible if
+    # there's only one such item. Let's just warn the user.
+    print >> sys.stderr, ('Warning: MSVS may misinterpret the odd number of ' +
+                          'quotes in ' + s)
+  return s
+
+
+def _EscapeCppDefineForMSVS(s):
+  """Escapes a CPP define so that it will reach the compiler unaltered."""
+  s = _EscapeEnvironmentVariableExpansion(s)
+  s = _EscapeCommandLineArgumentForMSVS(s)
+  s = _EscapeVCProjCommandLineArgListItem(s)
+  # cl.exe replaces literal # characters with = in preprocesor definitions for
+  # some reason. Octal-encode to work around that.
+  s = s.replace('#', '\\%03o' % ord('#'))
+  return s
+
+
+quote_replacer_regex2 = re.compile(r'(\\+)"')
+
+
+def _EscapeCommandLineArgumentForMSBuild(s):
+  """Escapes a Windows command-line argument for use by MSBuild."""
+
+  def _Replace(match):
+    return (len(match.group(1)) / 2 * 4) * '\\' + '\\"'
+
+  # Escape all quotes so that they are interpreted literally.
+  s = quote_replacer_regex2.sub(_Replace, s)
+  return s
+
+
+def _EscapeMSBuildSpecialCharacters(s):
+  escape_dictionary = {
+      '%': '%25',
+      '$': '%24',
+      '@': '%40',
+      "'": '%27',
+      ';': '%3B',
+      '?': '%3F',
+      '*': '%2A'
+      }
+  result = ''.join([escape_dictionary.get(c, c) for c in s])
+  return result
+
+
+def _EscapeCppDefineForMSBuild(s):
+  """Escapes a CPP define so that it will reach the compiler unaltered."""
+  s = _EscapeEnvironmentVariableExpansion(s)
+  s = _EscapeCommandLineArgumentForMSBuild(s)
+  s = _EscapeMSBuildSpecialCharacters(s)
+  # cl.exe replaces literal # characters with = in preprocesor definitions for
+  # some reason. Octal-encode to work around that.
+  s = s.replace('#', '\\%03o' % ord('#'))
+  return s
+
+
+def _GenerateRulesForMSVS(p, output_dir, options, spec,
+                          sources, excluded_sources,
+                          actions_to_add):
+  """Generate all the rules for a particular project.
+
+  Arguments:
+    p: the project
+    output_dir: directory to emit rules to
+    options: global options passed to the generator
+    spec: the specification for this project
+    sources: the set of all known source files in this project
+    excluded_sources: the set of sources excluded from normal processing
+    actions_to_add: deferred list of actions to add in
+  """
+  rules = spec.get('rules', [])
+  rules_native = [r for r in rules if not int(r.get('msvs_external_rule', 0))]
+  rules_external = [r for r in rules if int(r.get('msvs_external_rule', 0))]
+
+  # Handle rules that use a native rules file.
+  if rules_native:
+    _GenerateNativeRulesForMSVS(p, rules_native, output_dir, spec, options)
+
+  # Handle external rules (non-native rules).
+  if rules_external:
+    _GenerateExternalRules(rules_external, output_dir, spec,
+                           sources, options, actions_to_add)
+  _AdjustSourcesForRules(spec, rules, sources, excluded_sources)
+
+
+def _AdjustSourcesForRules(spec, rules, sources, excluded_sources):
+  # Add outputs generated by each rule (if applicable).
+  for rule in rules:
+    # Add in the outputs from this rule.
+    trigger_files = _FindRuleTriggerFiles(rule, sources)
+    for trigger_file in trigger_files:
+      # Remove trigger_file from excluded_sources to let the rule be triggered
+      # (e.g. rule trigger ax_enums.idl is added to excluded_sources
+      # because it's also in an action's inputs in the same project)
+      excluded_sources.discard(_FixPath(trigger_file))
+      # Done if not processing outputs as sources.
+      if int(rule.get('process_outputs_as_sources', False)):
+        inputs, outputs = _RuleInputsAndOutputs(rule, trigger_file)
+        inputs = OrderedSet(_FixPaths(inputs))
+        outputs = OrderedSet(_FixPaths(outputs))
+        inputs.remove(_FixPath(trigger_file))
+        sources.update(inputs)
+        if not spec.get('msvs_external_builder'):
+          excluded_sources.update(inputs)
+        sources.update(outputs)
+
+
+def _FilterActionsFromExcluded(excluded_sources, actions_to_add):
+  """Take inputs with actions attached out of the list of exclusions.
+
+  Arguments:
+    excluded_sources: list of source files not to be built.
+    actions_to_add: dict of actions keyed on source file they're attached to.
+  Returns:
+    excluded_sources with files that have actions attached removed.
+  """
+  must_keep = OrderedSet(_FixPaths(actions_to_add.keys()))
+  return [s for s in excluded_sources if s not in must_keep]
+
+
+def _GetDefaultConfiguration(spec):
+  return spec['configurations'][spec['default_configuration']]
+
+
+def _GetGuidOfProject(proj_path, spec):
+  """Get the guid for the project.
+
+  Arguments:
+    proj_path: Path of the vcproj or vcxproj file to generate.
+    spec: The target dictionary containing the properties of the target.
+  Returns:
+    the guid.
+  Raises:
+    ValueError: if the specified GUID is invalid.
+  """
+  # Pluck out the default configuration.
+  default_config = _GetDefaultConfiguration(spec)
+  # Decide the guid of the project.
+  guid = default_config.get('msvs_guid')
+  if guid:
+    if VALID_MSVS_GUID_CHARS.match(guid) is None:
+      raise ValueError('Invalid MSVS guid: "%s".  Must match regex: "%s".' %
+                       (guid, VALID_MSVS_GUID_CHARS.pattern))
+    guid = '{%s}' % guid
+  guid = guid or MSVSNew.MakeGuid(proj_path)
+  return guid
+
+
+def _GetMsbuildToolsetOfProject(proj_path, spec, version):
+  """Get the platform toolset for the project.
+
+  Arguments:
+    proj_path: Path of the vcproj or vcxproj file to generate.
+    spec: The target dictionary containing the properties of the target.
+    version: The MSVSVersion object.
+  Returns:
+    the platform toolset string or None.
+  """
+  # Pluck out the default configuration.
+  default_config = _GetDefaultConfiguration(spec)
+  toolset = default_config.get('msbuild_toolset')
+  if not toolset and version.DefaultToolset():
+    toolset = version.DefaultToolset()
+  return toolset
+
+
+def _GenerateProject(project, options, version, generator_flags):
+  """Generates a vcproj file.
+
+  Arguments:
+    project: the MSVSProject object.
+    options: global generator options.
+    version: the MSVSVersion object.
+    generator_flags: dict of generator-specific flags.
+  Returns:
+    A list of source files that cannot be found on disk.
+  """
+  default_config = _GetDefaultConfiguration(project.spec)
+
+  # Skip emitting anything if told to with msvs_existing_vcproj option.
+  if default_config.get('msvs_existing_vcproj'):
+    return []
+
+  if version.UsesVcxproj():
+    return _GenerateMSBuildProject(project, options, version, generator_flags)
+  else:
+    return _GenerateMSVSProject(project, options, version, generator_flags)
+
+
+# TODO: Avoid code duplication with _ValidateSourcesForOSX in make.py.
+def _ValidateSourcesForMSVSProject(spec, version):
+  """Makes sure if duplicate basenames are not specified in the source list.
+
+  Arguments:
+    spec: The target dictionary containing the properties of the target.
+    version: The VisualStudioVersion object.
+  """
+  # This validation should not be applied to MSVC2010 and later.
+  assert not version.UsesVcxproj()
+
+  # TODO: Check if MSVC allows this for loadable_module targets.
+  if spec.get('type', None) not in ('static_library', 'shared_library'):
+    return
+  sources = spec.get('sources', [])
+  basenames = {}
+  for source in sources:
+    name, ext = os.path.splitext(source)
+    is_compiled_file = ext in [
+        '.c', '.cc', '.cpp', '.cxx', '.m', '.mm', '.s', '.S']
+    if not is_compiled_file:
+      continue
+    basename = os.path.basename(name)  # Don't include extension.
+    basenames.setdefault(basename, []).append(source)
+
+  error = ''
+  for basename, files in basenames.iteritems():
+    if len(files) > 1:
+      error += '  %s: %s\n' % (basename, ' '.join(files))
+
+  if error:
+    print('static library %s has several files with the same basename:\n' %
+          spec['target_name'] + error + 'MSVC08 cannot handle that.')
+    raise GypError('Duplicate basenames in sources section, see list above')
+
+
+def _GenerateMSVSProject(project, options, version, generator_flags):
+  """Generates a .vcproj file.  It may create .rules and .user files too.
+
+  Arguments:
+    project: The project object we will generate the file for.
+    options: Global options passed to the generator.
+    version: The VisualStudioVersion object.
+    generator_flags: dict of generator-specific flags.
+  """
+  spec = project.spec
+  gyp.common.EnsureDirExists(project.path)
+
+  platforms = _GetUniquePlatforms(spec)
+  p = MSVSProject.Writer(project.path, version, spec['target_name'],
+                         project.guid, platforms)
+
+  # Get directory project file is in.
+  project_dir = os.path.split(project.path)[0]
+  gyp_path = _NormalizedSource(project.build_file)
+  relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, project_dir)
+
+  config_type = _GetMSVSConfigurationType(spec, project.build_file)
+  for config_name, config in spec['configurations'].iteritems():
+    _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config)
+
+  # MSVC08 and prior version cannot handle duplicate basenames in the same
+  # target.
+  # TODO: Take excluded sources into consideration if possible.
+  _ValidateSourcesForMSVSProject(spec, version)
+
+  # Prepare list of sources and excluded sources.
+  gyp_file = os.path.split(project.build_file)[1]
+  sources, excluded_sources = _PrepareListOfSources(spec, generator_flags,
+                                                    gyp_file)
+
+  # Add rules.
+  actions_to_add = {}
+  _GenerateRulesForMSVS(p, project_dir, options, spec,
+                        sources, excluded_sources,
+                        actions_to_add)
+  list_excluded = generator_flags.get('msvs_list_excluded_files', True)
+  sources, excluded_sources, excluded_idl = (
+      _AdjustSourcesAndConvertToFilterHierarchy(spec, options, project_dir,
+                                                sources, excluded_sources,
+                                                list_excluded, version))
+
+  # Add in files.
+  missing_sources = _VerifySourcesExist(sources, project_dir)
+  p.AddFiles(sources)
+
+  _AddToolFilesToMSVS(p, spec)
+  _HandlePreCompiledHeaders(p, sources, spec)
+  _AddActions(actions_to_add, spec, relative_path_of_gyp_file)
+  _AddCopies(actions_to_add, spec)
+  _WriteMSVSUserFile(project.path, version, spec)
+
+  # NOTE: this stanza must appear after all actions have been decided.
+  # Don't excluded sources with actions attached, or they won't run.
+  excluded_sources = _FilterActionsFromExcluded(
+      excluded_sources, actions_to_add)
+  _ExcludeFilesFromBeingBuilt(p, spec, excluded_sources, excluded_idl,
+                              list_excluded)
+  _AddAccumulatedActionsToMSVS(p, spec, actions_to_add)
+
+  # Write it out.
+  p.WriteIfChanged()
+
+  return missing_sources
+
+
+def _GetUniquePlatforms(spec):
+  """Returns the list of unique platforms for this spec, e.g ['win32', ...].
+
+  Arguments:
+    spec: The target dictionary containing the properties of the target.
+  Returns:
+    The MSVSUserFile object created.
+  """
+  # Gather list of unique platforms.
+  platforms = OrderedSet()
+  for configuration in spec['configurations']:
+    platforms.add(_ConfigPlatform(spec['configurations'][configuration]))
+  platforms = list(platforms)
+  return platforms
+
+
+def _CreateMSVSUserFile(proj_path, version, spec):
+  """Generates a .user file for the user running this Gyp program.
+
+  Arguments:
+    proj_path: The path of the project file being created.  The .user file
+               shares the same path (with an appropriate suffix).
+    version: The VisualStudioVersion object.
+    spec: The target dictionary containing the properties of the target.
+  Returns:
+    The MSVSUserFile object created.
+  """
+  (domain, username) = _GetDomainAndUserName()
+  vcuser_filename = '.'.join([proj_path, domain, username, 'user'])
+  user_file = MSVSUserFile.Writer(vcuser_filename, version,
+                                  spec['target_name'])
+  return user_file
+
+
+def _GetMSVSConfigurationType(spec, build_file):
+  """Returns the configuration type for this project.
+
+  It's a number defined by Microsoft.  May raise an exception.
+
+  Args:
+      spec: The target dictionary containing the properties of the target.
+      build_file: The path of the gyp file.
+  Returns:
+      An integer, the configuration type.
+  """
+  try:
+    config_type = {
+        'executable': '1',  # .exe
+        'shared_library': '2',  # .dll
+        'loadable_module': '2',  # .dll
+        'static_library': '4',  # .lib
+        'none': '10',  # Utility type
+        }[spec['type']]
+  except KeyError:
+    if spec.get('type'):
+      raise GypError('Target type %s is not a valid target type for '
+                     'target %s in %s.' %
+                     (spec['type'], spec['target_name'], build_file))
+    else:
+      raise GypError('Missing type field for target %s in %s.' %
+                     (spec['target_name'], build_file))
+  return config_type
+
+
+def _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config):
+  """Adds a configuration to the MSVS project.
+
+  Many settings in a vcproj file are specific to a configuration.  This
+  function the main part of the vcproj file that's configuration specific.
+
+  Arguments:
+    p: The target project being generated.
+    spec: The target dictionary containing the properties of the target.
+    config_type: The configuration type, a number as defined by Microsoft.
+    config_name: The name of the configuration.
+    config: The dictionary that defines the special processing to be done
+            for this configuration.
+  """
+  # Get the information for this configuration
+  include_dirs, resource_include_dirs = _GetIncludeDirs(config)
+  libraries = _GetLibraries(spec)
+  library_dirs = _GetLibraryDirs(config)
+  out_file, vc_tool, _ = _GetOutputFilePathAndTool(spec, msbuild=False)
+  defines = _GetDefines(config)
+  defines = [_EscapeCppDefineForMSVS(d) for d in defines]
+  disabled_warnings = _GetDisabledWarnings(config)
+  prebuild = config.get('msvs_prebuild')
+  postbuild = config.get('msvs_postbuild')
+  def_file = _GetModuleDefinition(spec)
+  precompiled_header = config.get('msvs_precompiled_header')
+
+  # Prepare the list of tools as a dictionary.
+  tools = dict()
+  # Add in user specified msvs_settings.
+  msvs_settings = config.get('msvs_settings', {})
+  MSVSSettings.ValidateMSVSSettings(msvs_settings)
+
+  # Prevent default library inheritance from the environment.
+  _ToolAppend(tools, 'VCLinkerTool', 'AdditionalDependencies', ['$(NOINHERIT)'])
+
+  for tool in msvs_settings:
+    settings = config['msvs_settings'][tool]
+    for setting in settings:
+      _ToolAppend(tools, tool, setting, settings[setting])
+  # Add the information to the appropriate tool
+  _ToolAppend(tools, 'VCCLCompilerTool',
+              'AdditionalIncludeDirectories', include_dirs)
+  _ToolAppend(tools, 'VCResourceCompilerTool',
+              'AdditionalIncludeDirectories', resource_include_dirs)
+  # Add in libraries.
+  _ToolAppend(tools, 'VCLinkerTool', 'AdditionalDependencies', libraries)
+  _ToolAppend(tools, 'VCLinkerTool', 'AdditionalLibraryDirectories',
+              library_dirs)
+  if out_file:
+    _ToolAppend(tools, vc_tool, 'OutputFile', out_file, only_if_unset=True)
+  # Add defines.
+  _ToolAppend(tools, 'VCCLCompilerTool', 'PreprocessorDefinitions', defines)
+  _ToolAppend(tools, 'VCResourceCompilerTool', 'PreprocessorDefinitions',
+              defines)
+  # Change program database directory to prevent collisions.
+  _ToolAppend(tools, 'VCCLCompilerTool', 'ProgramDataBaseFileName',
+              '$(IntDir)$(ProjectName)\\vc80.pdb', only_if_unset=True)
+  # Add disabled warnings.
+  _ToolAppend(tools, 'VCCLCompilerTool',
+              'DisableSpecificWarnings', disabled_warnings)
+  # Add Pre-build.
+  _ToolAppend(tools, 'VCPreBuildEventTool', 'CommandLine', prebuild)
+  # Add Post-build.
+  _ToolAppend(tools, 'VCPostBuildEventTool', 'CommandLine', postbuild)
+  # Turn on precompiled headers if appropriate.
+  if precompiled_header:
+    precompiled_header = os.path.split(precompiled_header)[1]
+    _ToolAppend(tools, 'VCCLCompilerTool', 'UsePrecompiledHeader', '2')
+    _ToolAppend(tools, 'VCCLCompilerTool',
+                'PrecompiledHeaderThrough', precompiled_header)
+    _ToolAppend(tools, 'VCCLCompilerTool',
+                'ForcedIncludeFiles', precompiled_header)
+  # Loadable modules don't generate import libraries;
+  # tell dependent projects to not expect one.
+  if spec['type'] == 'loadable_module':
+    _ToolAppend(tools, 'VCLinkerTool', 'IgnoreImportLibrary', 'true')
+  # Set the module definition file if any.
+  if def_file:
+    _ToolAppend(tools, 'VCLinkerTool', 'ModuleDefinitionFile', def_file)
+
+  _AddConfigurationToMSVS(p, spec, tools, config, config_type, config_name)
+
+
+def _GetIncludeDirs(config):
+  """Returns the list of directories to be used for #include directives.
+
+  Arguments:
+    config: The dictionary that defines the special processing to be done
+            for this configuration.
+  Returns:
+    The list of directory paths.
+  """
+  # TODO(bradnelson): include_dirs should really be flexible enough not to
+  #                   require this sort of thing.
+  include_dirs = (
+      config.get('include_dirs', []) +
+      config.get('msvs_system_include_dirs', []))
+  resource_include_dirs = config.get('resource_include_dirs', include_dirs)
+  include_dirs = _FixPaths(include_dirs)
+  resource_include_dirs = _FixPaths(resource_include_dirs)
+  return include_dirs, resource_include_dirs
+
+
+def _GetLibraryDirs(config):
+  """Returns the list of directories to be used for library search paths.
+
+  Arguments:
+    config: The dictionary that defines the special processing to be done
+            for this configuration.
+  Returns:
+    The list of directory paths.
+  """
+
+  library_dirs = config.get('library_dirs', [])
+  library_dirs = _FixPaths(library_dirs)
+  return library_dirs
+
+
+def _GetLibraries(spec):
+  """Returns the list of libraries for this configuration.
+
+  Arguments:
+    spec: The target dictionary containing the properties of the target.
+  Returns:
+    The list of directory paths.
+  """
+  libraries = spec.get('libraries', [])
+  # Strip out -l, as it is not used on windows (but is needed so we can pass
+  # in libraries that are assumed to be in the default library path).
+  # Also remove duplicate entries, leaving only the last duplicate, while
+  # preserving order.
+  found = OrderedSet()
+  unique_libraries_list = []
+  for entry in reversed(libraries):
+    library = re.sub('^\-l', '', entry)
+    if not os.path.splitext(library)[1]:
+      library += '.lib'
+    if library not in found:
+      found.add(library)
+      unique_libraries_list.append(library)
+  unique_libraries_list.reverse()
+  return unique_libraries_list
+
+
+def _GetOutputFilePathAndTool(spec, msbuild):
+  """Returns the path and tool to use for this target.
+
+  Figures out the path of the file this spec will create and the name of
+  the VC tool that will create it.
+
+  Arguments:
+    spec: The target dictionary containing the properties of the target.
+  Returns:
+    A triple of (file path, name of the vc tool, name of the msbuild tool)
+  """
+  # Select a name for the output file.
+  out_file = ''
+  vc_tool = ''
+  msbuild_tool = ''
+  output_file_map = {
+      'executable': ('VCLinkerTool', 'Link', '$(OutDir)', '.exe'),
+      'shared_library': ('VCLinkerTool', 'Link', '$(OutDir)', '.dll'),
+      'loadable_module': ('VCLinkerTool', 'Link', '$(OutDir)', '.dll'),
+      'static_library': ('VCLibrarianTool', 'Lib', '$(OutDir)lib\\', '.lib'),
+  }
+  output_file_props = output_file_map.get(spec['type'])
+  if output_file_props and int(spec.get('msvs_auto_output_file', 1)):
+    vc_tool, msbuild_tool, out_dir, suffix = output_file_props
+    if spec.get('standalone_static_library', 0):
+      out_dir = '$(OutDir)'
+    out_dir = spec.get('product_dir', out_dir)
+    product_extension = spec.get('product_extension')
+    if product_extension:
+      suffix = '.' + product_extension
+    elif msbuild:
+      suffix = '$(TargetExt)'
+    prefix = spec.get('product_prefix', '')
+    product_name = spec.get('product_name', '$(ProjectName)')
+    out_file = ntpath.join(out_dir, prefix + product_name + suffix)
+  return out_file, vc_tool, msbuild_tool
+
+
+def _GetOutputTargetExt(spec):
+  """Returns the extension for this target, including the dot
+
+  If product_extension is specified, set target_extension to this to avoid
+  MSB8012, returns None otherwise. Ignores any target_extension settings in
+  the input files.
+
+  Arguments:
+    spec: The target dictionary containing the properties of the target.
+  Returns:
+    A string with the extension, or None
+  """
+  target_extension = spec.get('product_extension')
+  if target_extension:
+    return '.' + target_extension
+  return None
+
+
+def _GetDefines(config):
+  """Returns the list of preprocessor definitions for this configuation.
+
+  Arguments:
+    config: The dictionary that defines the special processing to be done
+            for this configuration.
+  Returns:
+    The list of preprocessor definitions.
+  """
+  defines = []
+  for d in config.get('defines', []):
+    if type(d) == list:
+      fd = '='.join([str(dpart) for dpart in d])
+    else:
+      fd = str(d)
+    defines.append(fd)
+  return defines
+
+
+def _GetDisabledWarnings(config):
+  return [str(i) for i in config.get('msvs_disabled_warnings', [])]
+
+
+def _GetModuleDefinition(spec):
+  def_file = ''
+  if spec['type'] in ['shared_library', 'loadable_module', 'executable']:
+    def_files = [s for s in spec.get('sources', []) if s.endswith('.def')]
+    if len(def_files) == 1:
+      def_file = _FixPath(def_files[0])
+    elif def_files:
+      raise ValueError(
+          'Multiple module definition files in one target, target %s lists '
+          'multiple .def files: %s' % (
+              spec['target_name'], ' '.join(def_files)))
+  return def_file
+
+
+def _ConvertToolsToExpectedForm(tools):
+  """Convert tools to a form expected by Visual Studio.
+
+  Arguments:
+    tools: A dictionary of settings; the tool name is the key.
+  Returns:
+    A list of Tool objects.
+  """
+  tool_list = []
+  for tool, settings in tools.iteritems():
+    # Collapse settings with lists.
+    settings_fixed = {}
+    for setting, value in settings.iteritems():
+      if type(value) == list:
+        if ((tool == 'VCLinkerTool' and
+             setting == 'AdditionalDependencies') or
+            setting == 'AdditionalOptions'):
+          settings_fixed[setting] = ' '.join(value)
+        else:
+          settings_fixed[setting] = ';'.join(value)
+      else:
+        settings_fixed[setting] = value
+    # Add in this tool.
+    tool_list.append(MSVSProject.Tool(tool, settings_fixed))
+  return tool_list
+
+
+def _AddConfigurationToMSVS(p, spec, tools, config, config_type, config_name):
+  """Add to the project file the configuration specified by config.
+
+  Arguments:
+    p: The target project being generated.
+    spec: the target project dict.
+    tools: A dictionary of settings; the tool name is the key.
+    config: The dictionary that defines the special processing to be done
+            for this configuration.
+    config_type: The configuration type, a number as defined by Microsoft.
+    config_name: The name of the configuration.
+  """
+  attributes = _GetMSVSAttributes(spec, config, config_type)
+  # Add in this configuration.
+  tool_list = _ConvertToolsToExpectedForm(tools)
+  p.AddConfig(_ConfigFullName(config_name, config),
+              attrs=attributes, tools=tool_list)
+
+
+def _GetMSVSAttributes(spec, config, config_type):
+  # Prepare configuration attributes.
+  prepared_attrs = {}
+  source_attrs = config.get('msvs_configuration_attributes', {})
+  for a in source_attrs:
+    prepared_attrs[a] = source_attrs[a]
+  # Add props files.
+  vsprops_dirs = config.get('msvs_props', [])
+  vsprops_dirs = _FixPaths(vsprops_dirs)
+  if vsprops_dirs:
+    prepared_attrs['InheritedPropertySheets'] = ';'.join(vsprops_dirs)
+  # Set configuration type.
+  prepared_attrs['ConfigurationType'] = config_type
+  output_dir = prepared_attrs.get('OutputDirectory',
+                                  '$(SolutionDir)$(ConfigurationName)')
+  prepared_attrs['OutputDirectory'] = _FixPath(output_dir) + '\\'
+  if 'IntermediateDirectory' not in prepared_attrs:
+    intermediate = '$(ConfigurationName)\\obj\\$(ProjectName)'
+    prepared_attrs['IntermediateDirectory'] = _FixPath(intermediate) + '\\'
+  else:
+    intermediate = _FixPath(prepared_attrs['IntermediateDirectory']) + '\\'
+    intermediate = MSVSSettings.FixVCMacroSlashes(intermediate)
+    prepared_attrs['IntermediateDirectory'] = intermediate
+  return prepared_attrs
+
+
+def _AddNormalizedSources(sources_set, sources_array):
+  sources_set.update(_NormalizedSource(s) for s in sources_array)
+
+
+def _PrepareListOfSources(spec, generator_flags, gyp_file):
+  """Prepare list of sources and excluded sources.
+
+  Besides the sources specified directly in the spec, adds the gyp file so
+  that a change to it will cause a re-compile. Also adds appropriate sources
+  for actions and copies. Assumes later stage will un-exclude files which
+  have custom build steps attached.
+
+  Arguments:
+    spec: The target dictionary containing the properties of the target.
+    gyp_file: The name of the gyp file.
+  Returns:
+    A pair of (list of sources, list of excluded sources).
+    The sources will be relative to the gyp file.
+  """
+  sources = OrderedSet()
+  _AddNormalizedSources(sources, spec.get('sources', []))
+  excluded_sources = OrderedSet()
+  # Add in the gyp file.
+  if not generator_flags.get('standalone'):
+    sources.add(gyp_file)
+
+  # Add in 'action' inputs and outputs.
+  for a in spec.get('actions', []):
+    inputs = a['inputs']
+    inputs = [_NormalizedSource(i) for i in inputs]
+    # Add all inputs to sources and excluded sources.
+    inputs = OrderedSet(inputs)
+    sources.update(inputs)
+    if not spec.get('msvs_external_builder'):
+      excluded_sources.update(inputs)
+    if int(a.get('process_outputs_as_sources', False)):
+      _AddNormalizedSources(sources, a.get('outputs', []))
+  # Add in 'copies' inputs and outputs.
+  for cpy in spec.get('copies', []):
+    _AddNormalizedSources(sources, cpy.get('files', []))
+  return (sources, excluded_sources)
+
+
+def _AdjustSourcesAndConvertToFilterHierarchy(
+    spec, options, gyp_dir, sources, excluded_sources, list_excluded, version):
+  """Adjusts the list of sources and excluded sources.
+
+  Also converts the sets to lists.
+
+  Arguments:
+    spec: The target dictionary containing the properties of the target.
+    options: Global generator options.
+    gyp_dir: The path to the gyp file being processed.
+    sources: A set of sources to be included for this project.
+    excluded_sources: A set of sources to be excluded for this project.
+    version: A MSVSVersion object.
+  Returns:
+    A trio of (list of sources, list of excluded sources,
+               path of excluded IDL file)
+  """
+  # Exclude excluded sources coming into the generator.
+  excluded_sources.update(OrderedSet(spec.get('sources_excluded', [])))
+  # Add excluded sources into sources for good measure.
+  sources.update(excluded_sources)
+  # Convert to proper windows form.
+  # NOTE: sources goes from being a set to a list here.
+  # NOTE: excluded_sources goes from being a set to a list here.
+  sources = _FixPaths(sources)
+  # Convert to proper windows form.
+  excluded_sources = _FixPaths(excluded_sources)
+
+  excluded_idl = _IdlFilesHandledNonNatively(spec, sources)
+
+  precompiled_related = _GetPrecompileRelatedFiles(spec)
+  # Find the excluded ones, minus the precompiled header related ones.
+  fully_excluded = [i for i in excluded_sources if i not in precompiled_related]
+
+  # Convert to folders and the right slashes.
+  sources = [i.split('\\') for i in sources]
+  sources = _ConvertSourcesToFilterHierarchy(sources, excluded=fully_excluded,
+                                             list_excluded=list_excluded,
+                                             msvs_version=version)
+
+  # Prune filters with a single child to flatten ugly directory structures
+  # such as ../../src/modules/module1 etc.
+  if version.UsesVcxproj():
+    while all([isinstance(s, MSVSProject.Filter) for s in sources]) \
+        and len(set([s.name for s in sources])) == 1:
+      assert all([len(s.contents) == 1 for s in sources])
+      sources = [s.contents[0] for s in sources]
+  else:
+    while len(sources) == 1 and isinstance(sources[0], MSVSProject.Filter):
+      sources = sources[0].contents
+
+  return sources, excluded_sources, excluded_idl
+
+
+def _IdlFilesHandledNonNatively(spec, sources):
+  # If any non-native rules use 'idl' as an extension exclude idl files.
+  # Gather a list here to use later.
+  using_idl = False
+  for rule in spec.get('rules', []):
+    if rule['extension'] == 'idl' and int(rule.get('msvs_external_rule', 0)):
+      using_idl = True
+      break
+  if using_idl:
+    excluded_idl = [i for i in sources if i.endswith('.idl')]
+  else:
+    excluded_idl = []
+  return excluded_idl
+
+
+def _GetPrecompileRelatedFiles(spec):
+  # Gather a list of precompiled header related sources.
+  precompiled_related = []
+  for _, config in spec['configurations'].iteritems():
+    for k in precomp_keys:
+      f = config.get(k)
+      if f:
+        precompiled_related.append(_FixPath(f))
+  return precompiled_related
+
+
+def _ExcludeFilesFromBeingBuilt(p, spec, excluded_sources, excluded_idl,
+                                list_excluded):
+  exclusions = _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl)
+  for file_name, excluded_configs in exclusions.iteritems():
+    if (not list_excluded and
+            len(excluded_configs) == len(spec['configurations'])):
+      # If we're not listing excluded files, then they won't appear in the
+      # project, so don't try to configure them to be excluded.
+      pass
+    else:
+      for config_name, config in excluded_configs:
+        p.AddFileConfig(file_name, _ConfigFullName(config_name, config),
+                        {'ExcludedFromBuild': 'true'})
+
+
+def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl):
+  exclusions = {}
+  # Exclude excluded sources from being built.
+  for f in excluded_sources:
+    excluded_configs = []
+    for config_name, config in spec['configurations'].iteritems():
+      precomped = [_FixPath(config.get(i, '')) for i in precomp_keys]
+      # Don't do this for ones that are precompiled header related.
+      if f not in precomped:
+        excluded_configs.append((config_name, config))
+    exclusions[f] = excluded_configs
+  # If any non-native rules use 'idl' as an extension exclude idl files.
+  # Exclude them now.
+  for f in excluded_idl:
+    excluded_configs = []
+    for config_name, config in spec['configurations'].iteritems():
+      excluded_configs.append((config_name, config))
+    exclusions[f] = excluded_configs
+  return exclusions
+
+
+def _AddToolFilesToMSVS(p, spec):
+  # Add in tool files (rules).
+  tool_files = OrderedSet()
+  for _, config in spec['configurations'].iteritems():
+    for f in config.get('msvs_tool_files', []):
+      tool_files.add(f)
+  for f in tool_files:
+    p.AddToolFile(f)
+
+
+def _HandlePreCompiledHeaders(p, sources, spec):
+  # Pre-compiled header source stubs need a different compiler flag
+  # (generate precompiled header) and any source file not of the same
+  # kind (i.e. C vs. C++) as the precompiled header source stub needs
+  # to have use of precompiled headers disabled.
+  extensions_excluded_from_precompile = []
+  for config_name, config in spec['configurations'].iteritems():
+    source = config.get('msvs_precompiled_source')
+    if source:
+      source = _FixPath(source)
+      # UsePrecompiledHeader=1 for if using precompiled headers.
+      tool = MSVSProject.Tool('VCCLCompilerTool',
+                              {'UsePrecompiledHeader': '1'})
+      p.AddFileConfig(source, _ConfigFullName(config_name, config),
+                      {}, tools=[tool])
+      basename, extension = os.path.splitext(source)
+      if extension == '.c':
+        extensions_excluded_from_precompile = ['.cc', '.cpp', '.cxx']
+      else:
+        extensions_excluded_from_precompile = ['.c']
+  def DisableForSourceTree(source_tree):
+    for source in source_tree:
+      if isinstance(source, MSVSProject.Filter):
+        DisableForSourceTree(source.contents)
+      else:
+        basename, extension = os.path.splitext(source)
+        if extension in extensions_excluded_from_precompile:
+          for config_name, config in spec['configurations'].iteritems():
+            tool = MSVSProject.Tool('VCCLCompilerTool',
+                                    {'UsePrecompiledHeader': '0',
+                                     'ForcedIncludeFiles': '$(NOINHERIT)'})
+            p.AddFileConfig(_FixPath(source),
+                            _ConfigFullName(config_name, config),
+                            {}, tools=[tool])
+  # Do nothing if there was no precompiled source.
+  if extensions_excluded_from_precompile:
+    DisableForSourceTree(sources)
+
+
+def _AddActions(actions_to_add, spec, relative_path_of_gyp_file):
+  # Add actions.
+  actions = spec.get('actions', [])
+  # Don't setup_env every time. When all the actions are run together in one
+  # batch file in VS, the PATH will grow too long.
+  # Membership in this set means that the cygwin environment has been set up,
+  # and does not need to be set up again.
+  have_setup_env = set()
+  for a in actions:
+    # Attach actions to the gyp file if nothing else is there.
+    inputs = a.get('inputs') or [relative_path_of_gyp_file]
+    attached_to = inputs[0]
+    need_setup_env = attached_to not in have_setup_env
+    cmd = _BuildCommandLineForRule(spec, a, has_input_path=False,
+                                   do_setup_env=need_setup_env)
+    have_setup_env.add(attached_to)
+    # Add the action.
+    _AddActionStep(actions_to_add,
+                   inputs=inputs,
+                   outputs=a.get('outputs', []),
+                   description=a.get('message', a['action_name']),
+                   command=cmd)
+
+
+def _WriteMSVSUserFile(project_path, version, spec):
+  # Add run_as and test targets.
+  if 'run_as' in spec:
+    run_as = spec['run_as']
+    action = run_as.get('action', [])
+    environment = run_as.get('environment', [])
+    working_directory = run_as.get('working_directory', '.')
+  elif int(spec.get('test', 0)):
+    action = ['$(TargetPath)', '--gtest_print_time']
+    environment = []
+    working_directory = '.'
+  else:
+    return  # Nothing to add
+  # Write out the user file.
+  user_file = _CreateMSVSUserFile(project_path, version, spec)
+  for config_name, c_data in spec['configurations'].iteritems():
+    user_file.AddDebugSettings(_ConfigFullName(config_name, c_data),
+                               action, environment, working_directory)
+  user_file.WriteIfChanged()
+
+
+def _AddCopies(actions_to_add, spec):
+  copies = _GetCopies(spec)
+  for inputs, outputs, cmd, description in copies:
+    _AddActionStep(actions_to_add, inputs=inputs, outputs=outputs,
+                   description=description, command=cmd)
+
+
+def _GetCopies(spec):
+  copies = []
+  # Add copies.
+  for cpy in spec.get('copies', []):
+    for src in cpy.get('files', []):
+      dst = os.path.join(cpy['destination'], os.path.basename(src))
+      # _AddCustomBuildToolForMSVS() will call _FixPath() on the inputs and
+      # outputs, so do the same for our generated command line.
+      if src.endswith('/'):
+        src_bare = src[:-1]
+        base_dir = posixpath.split(src_bare)[0]
+        outer_dir = posixpath.split(src_bare)[1]
+        cmd = 'cd "%s" && xcopy /e /f /y "%s" "%s\\%s\\"' % (
+            _FixPath(base_dir), outer_dir, _FixPath(dst), outer_dir)
+        copies.append(([src], ['dummy_copies', dst], cmd,
+                       'Copying %s to %s' % (src, dst)))
+      else:
+        cmd = 'mkdir "%s" 2>nul & set ERRORLEVEL=0 & copy /Y "%s" "%s"' % (
+            _FixPath(cpy['destination']), _FixPath(src), _FixPath(dst))
+        copies.append(([src], [dst], cmd, 'Copying %s to %s' % (src, dst)))
+  return copies
+
+
+def _GetPathDict(root, path):
+  # |path| will eventually be empty (in the recursive calls) if it was initially
+  # relative; otherwise it will eventually end up as '\', 'D:\', etc.
+  if not path or path.endswith(os.sep):
+    return root
+  parent, folder = os.path.split(path)
+  parent_dict = _GetPathDict(root, parent)
+  if folder not in parent_dict:
+    parent_dict[folder] = dict()
+  return parent_dict[folder]
+
+
+def _DictsToFolders(base_path, bucket, flat):
+  # Convert to folders recursively.
+  children = []
+  for folder, contents in bucket.iteritems():
+    if type(contents) == dict:
+      folder_children = _DictsToFolders(os.path.join(base_path, folder),
+                                        contents, flat)
+      if flat:
+        children += folder_children
+      else:
+        folder_children = MSVSNew.MSVSFolder(os.path.join(base_path, folder),
+                                             name='(' + folder + ')',
+                                             entries=folder_children)
+        children.append(folder_children)
+    else:
+      children.append(contents)
+  return children
+
+
+def _CollapseSingles(parent, node):
+  # Recursively explorer the tree of dicts looking for projects which are
+  # the sole item in a folder which has the same name as the project. Bring
+  # such projects up one level.
+  if (type(node) == dict and
+      len(node) == 1 and
+      node.keys()[0] == parent + '.vcproj'):
+    return node[node.keys()[0]]
+  if type(node) != dict:
+    return node
+  for child in node:
+    node[child] = _CollapseSingles(child, node[child])
+  return node
+
+
+def _GatherSolutionFolders(sln_projects, project_objects, flat):
+  root = {}
+  # Convert into a tree of dicts on path.
+  for p in sln_projects:
+    gyp_file, target = gyp.common.ParseQualifiedTarget(p)[0:2]
+    gyp_dir = os.path.dirname(gyp_file)
+    path_dict = _GetPathDict(root, gyp_dir)
+    path_dict[target + '.vcproj'] = project_objects[p]
+  # Walk down from the top until we hit a folder that has more than one entry.
+  # In practice, this strips the top-level "src/" dir from the hierarchy in
+  # the solution.
+  while len(root) == 1 and type(root[root.keys()[0]]) == dict:
+    root = root[root.keys()[0]]
+  # Collapse singles.
+  root = _CollapseSingles('', root)
+  # Merge buckets until everything is a root entry.
+  return _DictsToFolders('', root, flat)
+
+
+def _GetPathOfProject(qualified_target, spec, options, msvs_version):
+  default_config = _GetDefaultConfiguration(spec)
+  proj_filename = default_config.get('msvs_existing_vcproj')
+  if not proj_filename:
+    proj_filename = (spec['target_name'] + options.suffix +
+                     msvs_version.ProjectExtension())
+
+  build_file = gyp.common.BuildFile(qualified_target)
+  proj_path = os.path.join(os.path.dirname(build_file), proj_filename)
+  fix_prefix = None
+  if options.generator_output:
+    project_dir_path = os.path.dirname(os.path.abspath(proj_path))
+    proj_path = os.path.join(options.generator_output, proj_path)
+    fix_prefix = gyp.common.RelativePath(project_dir_path,
+                                         os.path.dirname(proj_path))
+  return proj_path, fix_prefix
+
+
+def _GetPlatformOverridesOfProject(spec):
+  # Prepare a dict indicating which project configurations are used for which
+  # solution configurations for this target.
+  config_platform_overrides = {}
+  for config_name, c in spec['configurations'].iteritems():
+    config_fullname = _ConfigFullName(config_name, c)
+    platform = c.get('msvs_target_platform', _ConfigPlatform(c))
+    fixed_config_fullname = '%s|%s' % (
+        _ConfigBaseName(config_name, _ConfigPlatform(c)), platform)
+    config_platform_overrides[config_fullname] = fixed_config_fullname
+  return config_platform_overrides
+
+
+def _CreateProjectObjects(target_list, target_dicts, options, msvs_version):
+  """Create a MSVSProject object for the targets found in target list.
+
+  Arguments:
+    target_list: the list of targets to generate project objects for.
+    target_dicts: the dictionary of specifications.
+    options: global generator options.
+    msvs_version: the MSVSVersion object.
+  Returns:
+    A set of created projects, keyed by target.
+  """
+  global fixpath_prefix
+  # Generate each project.
+  projects = {}
+  for qualified_target in target_list:
+    spec = target_dicts[qualified_target]
+    if spec['toolset'] != 'target':
+      raise GypError(
+          'Multiple toolsets not supported in msvs build (target %s)' %
+          qualified_target)
+    proj_path, fixpath_prefix = _GetPathOfProject(qualified_target, spec,
+                                                  options, msvs_version)
+    guid = _GetGuidOfProject(proj_path, spec)
+    overrides = _GetPlatformOverridesOfProject(spec)
+    build_file = gyp.common.BuildFile(qualified_target)
+    # Create object for this project.
+    obj = MSVSNew.MSVSProject(
+        proj_path,
+        name=spec['target_name'],
+        guid=guid,
+        spec=spec,
+        build_file=build_file,
+        config_platform_overrides=overrides,
+        fixpath_prefix=fixpath_prefix)
+    # Set project toolset if any (MS build only)
+    if msvs_version.UsesVcxproj():
+      obj.set_msbuild_toolset(
+          _GetMsbuildToolsetOfProject(proj_path, spec, msvs_version))
+    projects[qualified_target] = obj
+  # Set all the dependencies, but not if we are using an external builder like
+  # ninja
+  for project in projects.values():
+    if not project.spec.get('msvs_external_builder'):
+      deps = project.spec.get('dependencies', [])
+      deps = [projects[d] for d in deps]
+      project.set_dependencies(deps)
+  return projects
+
+
+def _InitNinjaFlavor(params, target_list, target_dicts):
+  """Initialize targets for the ninja flavor.
+
+  This sets up the necessary variables in the targets to generate msvs projects
+  that use ninja as an external builder. The variables in the spec are only set
+  if they have not been set. This allows individual specs to override the
+  default values initialized here.
+  Arguments:
+    params: Params provided to the generator.
+    target_list: List of target pairs: 'base/base.gyp:base'.
+    target_dicts: Dict of target properties keyed on target pair.
+  """
+  for qualified_target in target_list:
+    spec = target_dicts[qualified_target]
+    if spec.get('msvs_external_builder'):
+      # The spec explicitly defined an external builder, so don't change it.
+      continue
+
+    path_to_ninja = spec.get('msvs_path_to_ninja', 'ninja.exe')
+
+    spec['msvs_external_builder'] = 'ninja'
+    if not spec.get('msvs_external_builder_out_dir'):
+      gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target)
+      gyp_dir = os.path.dirname(gyp_file)
+      spec['msvs_external_builder_out_dir'] = os.path.join(
+          gyp.common.RelativePath(params['options'].toplevel_dir, gyp_dir),
+          ninja_generator.ComputeOutputDir(params),
+          '$(Configuration)')
+    if not spec.get('msvs_external_builder_build_cmd'):
+      spec['msvs_external_builder_build_cmd'] = [
+        path_to_ninja,
+        '-C',
+        '$(OutDir)',
+        '$(ProjectName)',
+      ]
+    if not spec.get('msvs_external_builder_clean_cmd'):
+      spec['msvs_external_builder_clean_cmd'] = [
+        path_to_ninja,
+        '-C',
+        '$(OutDir)',
+        '-tclean',
+        '$(ProjectName)',
+      ]
+
+
+def CalculateVariables(default_variables, params):
+  """Generated variables that require params to be known."""
+
+  generator_flags = params.get('generator_flags', {})
+
+  # Select project file format version (if unset, default to auto detecting).
+  msvs_version = MSVSVersion.SelectVisualStudioVersion(
+      generator_flags.get('msvs_version', 'auto'))
+  # Stash msvs_version for later (so we don't have to probe the system twice).
+  params['msvs_version'] = msvs_version
+
+  # Set a variable so conditions can be based on msvs_version.
+  default_variables['MSVS_VERSION'] = msvs_version.ShortName()
+
+  # To determine processor word size on Windows, in addition to checking
+  # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
+  # process), it is also necessary to check PROCESSOR_ARCITEW6432 (which
+  # contains the actual word size of the system when running thru WOW64).
+  if (os.environ.get('PROCESSOR_ARCHITECTURE', '').find('64') >= 0 or
+      os.environ.get('PROCESSOR_ARCHITEW6432', '').find('64') >= 0):
+    default_variables['MSVS_OS_BITS'] = 64
+  else:
+    default_variables['MSVS_OS_BITS'] = 32
+
+  if gyp.common.GetFlavor(params) == 'ninja':
+    default_variables['SHARED_INTERMEDIATE_DIR'] = '$(OutDir)gen'
+
+
+def PerformBuild(data, configurations, params):
+  options = params['options']
+  msvs_version = params['msvs_version']
+  devenv = os.path.join(msvs_version.path, 'Common7', 'IDE', 'devenv.com')
+
+  for build_file, build_file_dict in data.iteritems():
+    (build_file_root, build_file_ext) = os.path.splitext(build_file)
+    if build_file_ext != '.gyp':
+      continue
+    sln_path = build_file_root + options.suffix + '.sln'
+    if options.generator_output:
+      sln_path = os.path.join(options.generator_output, sln_path)
+
+  for config in configurations:
+    arguments = [devenv, sln_path, '/Build', config]
+    print 'Building [%s]: %s' % (config, arguments)
+    rtn = subprocess.check_call(arguments)
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  """Generate .sln and .vcproj files.
+
+  This is the entry point for this generator.
+  Arguments:
+    target_list: List of target pairs: 'base/base.gyp:base'.
+    target_dicts: Dict of target properties keyed on target pair.
+    data: Dictionary containing per .gyp data.
+  """
+  global fixpath_prefix
+
+  options = params['options']
+
+  # Get the project file format version back out of where we stashed it in
+  # GeneratorCalculatedVariables.
+  msvs_version = params['msvs_version']
+
+  generator_flags = params.get('generator_flags', {})
+
+  # Optionally shard targets marked with 'msvs_shard': SHARD_COUNT.
+  (target_list, target_dicts) = MSVSUtil.ShardTargets(target_list, target_dicts)
+
+  # Optionally use the large PDB workaround for targets marked with
+  # 'msvs_large_pdb': 1.
+  (target_list, target_dicts) = MSVSUtil.InsertLargePdbShims(
+        target_list, target_dicts, generator_default_variables)
+
+  # Optionally configure each spec to use ninja as the external builder.
+  if params.get('flavor') == 'ninja':
+    _InitNinjaFlavor(params, target_list, target_dicts)
+
+  # Prepare the set of configurations.
+  configs = set()
+  for qualified_target in target_list:
+    spec = target_dicts[qualified_target]
+    for config_name, config in spec['configurations'].iteritems():
+      configs.add(_ConfigFullName(config_name, config))
+  configs = list(configs)
+
+  # Figure out all the projects that will be generated and their guids
+  project_objects = _CreateProjectObjects(target_list, target_dicts, options,
+                                          msvs_version)
+
+  # Generate each project.
+  missing_sources = []
+  for project in project_objects.values():
+    fixpath_prefix = project.fixpath_prefix
+    missing_sources.extend(_GenerateProject(project, options, msvs_version,
+                                            generator_flags))
+  fixpath_prefix = None
+
+  for build_file in data:
+    # Validate build_file extension
+    if not build_file.endswith('.gyp'):
+      continue
+    sln_path = os.path.splitext(build_file)[0] + options.suffix + '.sln'
+    if options.generator_output:
+      sln_path = os.path.join(options.generator_output, sln_path)
+    # Get projects in the solution, and their dependents.
+    sln_projects = gyp.common.BuildFileTargets(target_list, build_file)
+    sln_projects += gyp.common.DeepDependencyTargets(target_dicts, sln_projects)
+    # Create folder hierarchy.
+    root_entries = _GatherSolutionFolders(
+        sln_projects, project_objects, flat=msvs_version.FlatSolution())
+    # Create solution.
+    sln = MSVSNew.MSVSSolution(sln_path,
+                               entries=root_entries,
+                               variants=configs,
+                               websiteProperties=False,
+                               version=msvs_version)
+    sln.Write()
+
+  if missing_sources:
+    error_message = "Missing input files:\n" + \
+                    '\n'.join(set(missing_sources))
+    if generator_flags.get('msvs_error_on_missing_sources', False):
+      raise GypError(error_message)
+    else:
+      print >> sys.stdout, "Warning: " + error_message
+
+
+def _GenerateMSBuildFiltersFile(filters_path, source_files,
+                                extension_to_rule_name):
+  """Generate the filters file.
+
+  This file is used by Visual Studio to organize the presentation of source
+  files into folders.
+
+  Arguments:
+      filters_path: The path of the file to be created.
+      source_files: The hierarchical structure of all the sources.
+      extension_to_rule_name: A dictionary mapping file extensions to rules.
+  """
+  filter_group = []
+  source_group = []
+  _AppendFiltersForMSBuild('', source_files, extension_to_rule_name,
+                           filter_group, source_group)
+  if filter_group:
+    content = ['Project',
+               {'ToolsVersion': '4.0',
+                'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'
+               },
+               ['ItemGroup'] + filter_group,
+               ['ItemGroup'] + source_group
+              ]
+    easy_xml.WriteXmlIfChanged(content, filters_path, pretty=True, win32=True)
+  elif os.path.exists(filters_path):
+    # We don't need this filter anymore.  Delete the old filter file.
+    os.unlink(filters_path)
+
+
+def _AppendFiltersForMSBuild(parent_filter_name, sources,
+                             extension_to_rule_name,
+                             filter_group, source_group):
+  """Creates the list of filters and sources to be added in the filter file.
+
+  Args:
+      parent_filter_name: The name of the filter under which the sources are
+          found.
+      sources: The hierarchy of filters and sources to process.
+      extension_to_rule_name: A dictionary mapping file extensions to rules.
+      filter_group: The list to which filter entries will be appended.
+      source_group: The list to which source entries will be appeneded.
+  """
+  for source in sources:
+    if isinstance(source, MSVSProject.Filter):
+      # We have a sub-filter.  Create the name of that sub-filter.
+      if not parent_filter_name:
+        filter_name = source.name
+      else:
+        filter_name = '%s\\%s' % (parent_filter_name, source.name)
+      # Add the filter to the group.
+      filter_group.append(
+          ['Filter', {'Include': filter_name},
+           ['UniqueIdentifier', MSVSNew.MakeGuid(source.name)]])
+      # Recurse and add its dependents.
+      _AppendFiltersForMSBuild(filter_name, source.contents,
+                               extension_to_rule_name,
+                               filter_group, source_group)
+    else:
+      # It's a source.  Create a source entry.
+      _, element = _MapFileToMsBuildSourceType(source, extension_to_rule_name)
+      source_entry = [element, {'Include': source}]
+      # Specify the filter it is part of, if any.
+      if parent_filter_name:
+        source_entry.append(['Filter', parent_filter_name])
+      source_group.append(source_entry)
+
+
+def _MapFileToMsBuildSourceType(source, extension_to_rule_name):
+  """Returns the group and element type of the source file.
+
+  Arguments:
+      source: The source file name.
+      extension_to_rule_name: A dictionary mapping file extensions to rules.
+
+  Returns:
+      A pair of (group this file should be part of, the label of element)
+  """
+  _, ext = os.path.splitext(source)
+  if ext in extension_to_rule_name:
+    group = 'rule'
+    element = extension_to_rule_name[ext]
+  elif ext in ['.cc', '.cpp', '.c', '.cxx']:
+    group = 'compile'
+    element = 'ClCompile'
+  elif ext in ['.h', '.hxx']:
+    group = 'include'
+    element = 'ClInclude'
+  elif ext == '.rc':
+    group = 'resource'
+    element = 'ResourceCompile'
+  elif ext == '.idl':
+    group = 'midl'
+    element = 'Midl'
+  else:
+    group = 'none'
+    element = 'None'
+  return (group, element)
+
+
+def _GenerateRulesForMSBuild(output_dir, options, spec,
+                             sources, excluded_sources,
+                             props_files_of_rules, targets_files_of_rules,
+                             actions_to_add, extension_to_rule_name):
+  # MSBuild rules are implemented using three files: an XML file, a .targets
+  # file and a .props file.
+  # See http://blogs.msdn.com/b/vcblog/archive/2010/04/21/quick-help-on-vs2010-custom-build-rule.aspx
+  # for more details.
+  rules = spec.get('rules', [])
+  rules_native = [r for r in rules if not int(r.get('msvs_external_rule', 0))]
+  rules_external = [r for r in rules if int(r.get('msvs_external_rule', 0))]
+
+  msbuild_rules = []
+  for rule in rules_native:
+    # Skip a rule with no action and no inputs.
+    if 'action' not in rule and not rule.get('rule_sources', []):
+      continue
+    msbuild_rule = MSBuildRule(rule, spec)
+    msbuild_rules.append(msbuild_rule)
+    extension_to_rule_name[msbuild_rule.extension] = msbuild_rule.rule_name
+  if msbuild_rules:
+    base = spec['target_name'] + options.suffix
+    props_name = base + '.props'
+    targets_name = base + '.targets'
+    xml_name = base + '.xml'
+
+    props_files_of_rules.add(props_name)
+    targets_files_of_rules.add(targets_name)
+
+    props_path = os.path.join(output_dir, props_name)
+    targets_path = os.path.join(output_dir, targets_name)
+    xml_path = os.path.join(output_dir, xml_name)
+
+    _GenerateMSBuildRulePropsFile(props_path, msbuild_rules)
+    _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules)
+    _GenerateMSBuildRuleXmlFile(xml_path, msbuild_rules)
+
+  if rules_external:
+    _GenerateExternalRules(rules_external, output_dir, spec,
+                           sources, options, actions_to_add)
+  _AdjustSourcesForRules(spec, rules, sources, excluded_sources)
+
+
+class MSBuildRule(object):
+  """Used to store information used to generate an MSBuild rule.
+
+  Attributes:
+    rule_name: The rule name, sanitized to use in XML.
+    target_name: The name of the target.
+    after_targets: The name of the AfterTargets element.
+    before_targets: The name of the BeforeTargets element.
+    depends_on: The name of the DependsOn element.
+    compute_output: The name of the ComputeOutput element.
+    dirs_to_make: The name of the DirsToMake element.
+    inputs: The name of the _inputs element.
+    tlog: The name of the _tlog element.
+    extension: The extension this rule applies to.
+    description: The message displayed when this rule is invoked.
+    additional_dependencies: A string listing additional dependencies.
+    outputs: The outputs of this rule.
+    command: The command used to run the rule.
+  """
+
+  def __init__(self, rule, spec):
+    self.display_name = rule['rule_name']
+    # Assure that the rule name is only characters and numbers
+    self.rule_name = re.sub(r'\W', '_', self.display_name)
+    # Create the various element names, following the example set by the
+    # Visual Studio 2008 to 2010 conversion.  I don't know if VS2010
+    # is sensitive to the exact names.
+    self.target_name = '_' + self.rule_name
+    self.after_targets = self.rule_name + 'AfterTargets'
+    self.before_targets = self.rule_name + 'BeforeTargets'
+    self.depends_on = self.rule_name + 'DependsOn'
+    self.compute_output = 'Compute%sOutput' % self.rule_name
+    self.dirs_to_make = self.rule_name + 'DirsToMake'
+    self.inputs = self.rule_name + '_inputs'
+    self.tlog = self.rule_name + '_tlog'
+    self.extension = rule['extension']
+    if not self.extension.startswith('.'):
+      self.extension = '.' + self.extension
+
+    self.description = MSVSSettings.ConvertVCMacrosToMSBuild(
+        rule.get('message', self.rule_name))
+    old_additional_dependencies = _FixPaths(rule.get('inputs', []))
+    self.additional_dependencies = (
+        ';'.join([MSVSSettings.ConvertVCMacrosToMSBuild(i)
+                  for i in old_additional_dependencies]))
+    old_outputs = _FixPaths(rule.get('outputs', []))
+    self.outputs = ';'.join([MSVSSettings.ConvertVCMacrosToMSBuild(i)
+                             for i in old_outputs])
+    old_command = _BuildCommandLineForRule(spec, rule, has_input_path=True,
+                                           do_setup_env=True)
+    self.command = MSVSSettings.ConvertVCMacrosToMSBuild(old_command)
+
+
+def _GenerateMSBuildRulePropsFile(props_path, msbuild_rules):
+  """Generate the .props file."""
+  content = ['Project',
+             {'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}]
+  for rule in msbuild_rules:
+    content.extend([
+        ['PropertyGroup',
+         {'Condition': "'$(%s)' == '' and '$(%s)' == '' and "
+          "'$(ConfigurationType)' != 'Makefile'" % (rule.before_targets,
+                                                    rule.after_targets)
+         },
+         [rule.before_targets, 'Midl'],
+         [rule.after_targets, 'CustomBuild'],
+        ],
+        ['PropertyGroup',
+         [rule.depends_on,
+          {'Condition': "'$(ConfigurationType)' != 'Makefile'"},
+          '_SelectedFiles;$(%s)' % rule.depends_on
+         ],
+        ],
+        ['ItemDefinitionGroup',
+         [rule.rule_name,
+          ['CommandLineTemplate', rule.command],
+          ['Outputs', rule.outputs],
+          ['ExecutionDescription', rule.description],
+          ['AdditionalDependencies', rule.additional_dependencies],
+         ],
+        ]
+    ])
+  easy_xml.WriteXmlIfChanged(content, props_path, pretty=True, win32=True)
+
+
+def _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules):
+  """Generate the .targets file."""
+  content = ['Project',
+             {'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'
+             }
+            ]
+  item_group = [
+      'ItemGroup',
+      ['PropertyPageSchema',
+       {'Include': '$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml'}
+      ]
+    ]
+  for rule in msbuild_rules:
+    item_group.append(
+        ['AvailableItemName',
+         {'Include': rule.rule_name},
+         ['Targets', rule.target_name],
+        ])
+  content.append(item_group)
+
+  for rule in msbuild_rules:
+    content.append(
+        ['UsingTask',
+         {'TaskName': rule.rule_name,
+          'TaskFactory': 'XamlTaskFactory',
+          'AssemblyName': 'Microsoft.Build.Tasks.v4.0'
+         },
+         ['Task', '$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml'],
+        ])
+  for rule in msbuild_rules:
+    rule_name = rule.rule_name
+    target_outputs = '%%(%s.Outputs)' % rule_name
+    target_inputs = ('%%(%s.Identity);%%(%s.AdditionalDependencies);'
+                     '$(MSBuildProjectFile)') % (rule_name, rule_name)
+    rule_inputs = '%%(%s.Identity)' % rule_name
+    extension_condition = ("'%(Extension)'=='.obj' or "
+                           "'%(Extension)'=='.res' or "
+                           "'%(Extension)'=='.rsc' or "
+                           "'%(Extension)'=='.lib'")
+    remove_section = [
+        'ItemGroup',
+        {'Condition': "'@(SelectedFiles)' != ''"},
+        [rule_name,
+         {'Remove': '@(%s)' % rule_name,
+          'Condition': "'%(Identity)' != '@(SelectedFiles)'"
+         }
+        ]
+    ]
+    inputs_section = [
+        'ItemGroup',
+        [rule.inputs, {'Include': '%%(%s.AdditionalDependencies)' % rule_name}]
+    ]
+    logging_section = [
+        'ItemGroup',
+        [rule.tlog,
+         {'Include': '%%(%s.Outputs)' % rule_name,
+          'Condition': ("'%%(%s.Outputs)' != '' and "
+                        "'%%(%s.ExcludedFromBuild)' != 'true'" %
+                        (rule_name, rule_name))
+         },
+         ['Source', "@(%s, '|')" % rule_name],
+         ['Inputs', "@(%s -> '%%(Fullpath)', ';')" % rule.inputs],
+        ],
+    ]
+    message_section = [
+        'Message',
+        {'Importance': 'High',
+         'Text': '%%(%s.ExecutionDescription)' % rule_name
+        }
+    ]
+    write_tlog_section = [
+        'WriteLinesToFile',
+        {'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != "
+         "'true'" % (rule.tlog, rule.tlog),
+         'File': '$(IntDir)$(ProjectName).write.1.tlog',
+         'Lines': "^%%(%s.Source);@(%s->'%%(Fullpath)')" % (rule.tlog,
+                                                            rule.tlog)
+        }
+    ]
+    read_tlog_section = [
+        'WriteLinesToFile',
+        {'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != "
+         "'true'" % (rule.tlog, rule.tlog),
+         'File': '$(IntDir)$(ProjectName).read.1.tlog',
+         'Lines': "^%%(%s.Source);%%(%s.Inputs)" % (rule.tlog, rule.tlog)
+        }
+    ]
+    command_and_input_section = [
+        rule_name,
+        {'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != "
+         "'true'" % (rule_name, rule_name),
+         'CommandLineTemplate': '%%(%s.CommandLineTemplate)' % rule_name,
+         'AdditionalOptions': '%%(%s.AdditionalOptions)' % rule_name,
+         'Inputs': rule_inputs
+        }
+    ]
+    content.extend([
+        ['Target',
+         {'Name': rule.target_name,
+          'BeforeTargets': '$(%s)' % rule.before_targets,
+          'AfterTargets': '$(%s)' % rule.after_targets,
+          'Condition': "'@(%s)' != ''" % rule_name,
+          'DependsOnTargets': '$(%s);%s' % (rule.depends_on,
+                                            rule.compute_output),
+          'Outputs': target_outputs,
+          'Inputs': target_inputs
+         },
+         remove_section,
+         inputs_section,
+         logging_section,
+         message_section,
+         write_tlog_section,
+         read_tlog_section,
+         command_and_input_section,
+        ],
+        ['PropertyGroup',
+         ['ComputeLinkInputsTargets',
+          '$(ComputeLinkInputsTargets);',
+          '%s;' % rule.compute_output
+         ],
+         ['ComputeLibInputsTargets',
+          '$(ComputeLibInputsTargets);',
+          '%s;' % rule.compute_output
+         ],
+        ],
+        ['Target',
+         {'Name': rule.compute_output,
+          'Condition': "'@(%s)' != ''" % rule_name
+         },
+         ['ItemGroup',
+          [rule.dirs_to_make,
+           {'Condition': "'@(%s)' != '' and "
+            "'%%(%s.ExcludedFromBuild)' != 'true'" % (rule_name, rule_name),
+            'Include': '%%(%s.Outputs)' % rule_name
+           }
+          ],
+          ['Link',
+           {'Include': '%%(%s.Identity)' % rule.dirs_to_make,
+            'Condition': extension_condition
+           }
+          ],
+          ['Lib',
+           {'Include': '%%(%s.Identity)' % rule.dirs_to_make,
+            'Condition': extension_condition
+           }
+          ],
+          ['ImpLib',
+           {'Include': '%%(%s.Identity)' % rule.dirs_to_make,
+            'Condition': extension_condition
+           }
+          ],
+         ],
+         ['MakeDir',
+          {'Directories': ("@(%s->'%%(RootDir)%%(Directory)')" %
+                           rule.dirs_to_make)
+          }
+         ]
+        ],
+    ])
+  easy_xml.WriteXmlIfChanged(content, targets_path, pretty=True, win32=True)
+
+
+def _GenerateMSBuildRuleXmlFile(xml_path, msbuild_rules):
+  # Generate the .xml file
+  content = [
+      'ProjectSchemaDefinitions',
+      {'xmlns': ('clr-namespace:Microsoft.Build.Framework.XamlTypes;'
+                 'assembly=Microsoft.Build.Framework'),
+       'xmlns:x': 'http://schemas.microsoft.com/winfx/2006/xaml',
+       'xmlns:sys': 'clr-namespace:System;assembly=mscorlib',
+       'xmlns:transformCallback':
+       'Microsoft.Cpp.Dev10.ConvertPropertyCallback'
+      }
+  ]
+  for rule in msbuild_rules:
+    content.extend([
+        ['Rule',
+         {'Name': rule.rule_name,
+          'PageTemplate': 'tool',
+          'DisplayName': rule.display_name,
+          'Order': '200'
+         },
+         ['Rule.DataSource',
+          ['DataSource',
+           {'Persistence': 'ProjectFile',
+            'ItemType': rule.rule_name
+           }
+          ]
+         ],
+         ['Rule.Categories',
+          ['Category',
+           {'Name': 'General'},
+           ['Category.DisplayName',
+            ['sys:String', 'General'],
+           ],
+          ],
+          ['Category',
+           {'Name': 'Command Line',
+            'Subtype': 'CommandLine'
+           },
+           ['Category.DisplayName',
+            ['sys:String', 'Command Line'],
+           ],
+          ],
+         ],
+         ['StringListProperty',
+          {'Name': 'Inputs',
+           'Category': 'Command Line',
+           'IsRequired': 'true',
+           'Switch': ' '
+          },
+          ['StringListProperty.DataSource',
+           ['DataSource',
+            {'Persistence': 'ProjectFile',
+             'ItemType': rule.rule_name,
+             'SourceType': 'Item'
+            }
+           ]
+          ],
+         ],
+         ['StringProperty',
+          {'Name': 'CommandLineTemplate',
+           'DisplayName': 'Command Line',
+           'Visible': 'False',
+           'IncludeInCommandLine': 'False'
+          }
+         ],
+         ['DynamicEnumProperty',
+          {'Name': rule.before_targets,
+           'Category': 'General',
+           'EnumProvider': 'Targets',
+           'IncludeInCommandLine': 'False'
+          },
+          ['DynamicEnumProperty.DisplayName',
+           ['sys:String', 'Execute Before'],
+          ],
+          ['DynamicEnumProperty.Description',
+           ['sys:String', 'Specifies the targets for the build customization'
+            ' to run before.'
+           ],
+          ],
+          ['DynamicEnumProperty.ProviderSettings',
+           ['NameValuePair',
+            {'Name': 'Exclude',
+             'Value': '^%s|^Compute' % rule.before_targets
+            }
+           ]
+          ],
+          ['DynamicEnumProperty.DataSource',
+           ['DataSource',
+            {'Persistence': 'ProjectFile',
+             'HasConfigurationCondition': 'true'
+            }
+           ]
+          ],
+         ],
+         ['DynamicEnumProperty',
+          {'Name': rule.after_targets,
+           'Category': 'General',
+           'EnumProvider': 'Targets',
+           'IncludeInCommandLine': 'False'
+          },
+          ['DynamicEnumProperty.DisplayName',
+           ['sys:String', 'Execute After'],
+          ],
+          ['DynamicEnumProperty.Description',
+           ['sys:String', ('Specifies the targets for the build customization'
+                           ' to run after.')
+           ],
+          ],
+          ['DynamicEnumProperty.ProviderSettings',
+           ['NameValuePair',
+            {'Name': 'Exclude',
+             'Value': '^%s|^Compute' % rule.after_targets
+            }
+           ]
+          ],
+          ['DynamicEnumProperty.DataSource',
+           ['DataSource',
+            {'Persistence': 'ProjectFile',
+             'ItemType': '',
+             'HasConfigurationCondition': 'true'
+            }
+           ]
+          ],
+         ],
+         ['StringListProperty',
+          {'Name': 'Outputs',
+           'DisplayName': 'Outputs',
+           'Visible': 'False',
+           'IncludeInCommandLine': 'False'
+          }
+         ],
+         ['StringProperty',
+          {'Name': 'ExecutionDescription',
+           'DisplayName': 'Execution Description',
+           'Visible': 'False',
+           'IncludeInCommandLine': 'False'
+          }
+         ],
+         ['StringListProperty',
+          {'Name': 'AdditionalDependencies',
+           'DisplayName': 'Additional Dependencies',
+           'IncludeInCommandLine': 'False',
+           'Visible': 'false'
+          }
+         ],
+         ['StringProperty',
+          {'Subtype': 'AdditionalOptions',
+           'Name': 'AdditionalOptions',
+           'Category': 'Command Line'
+          },
+          ['StringProperty.DisplayName',
+           ['sys:String', 'Additional Options'],
+          ],
+          ['StringProperty.Description',
+           ['sys:String', 'Additional Options'],
+          ],
+         ],
+        ],
+        ['ItemType',
+         {'Name': rule.rule_name,
+          'DisplayName': rule.display_name
+         }
+        ],
+        ['FileExtension',
+         {'Name': '*' + rule.extension,
+          'ContentType': rule.rule_name
+         }
+        ],
+        ['ContentType',
+         {'Name': rule.rule_name,
+          'DisplayName': '',
+          'ItemType': rule.rule_name
+         }
+        ]
+    ])
+  easy_xml.WriteXmlIfChanged(content, xml_path, pretty=True, win32=True)
+
+
+def _GetConfigurationAndPlatform(name, settings):
+  configuration = name.rsplit('_', 1)[0]
+  platform = settings.get('msvs_configuration_platform', 'Win32')
+  return (configuration, platform)
+
+
+def _GetConfigurationCondition(name, settings):
+  return (r"'$(Configuration)|$(Platform)'=='%s|%s'" %
+          _GetConfigurationAndPlatform(name, settings))
+
+
+def _GetMSBuildProjectConfigurations(configurations):
+  group = ['ItemGroup', {'Label': 'ProjectConfigurations'}]
+  for (name, settings) in sorted(configurations.iteritems()):
+    configuration, platform = _GetConfigurationAndPlatform(name, settings)
+    designation = '%s|%s' % (configuration, platform)
+    group.append(
+        ['ProjectConfiguration', {'Include': designation},
+         ['Configuration', configuration],
+         ['Platform', platform]])
+  return [group]
+
+
+def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
+  namespace = os.path.splitext(gyp_file_name)[0]
+  return [
+      ['PropertyGroup', {'Label': 'Globals'},
+       ['ProjectGuid', guid],
+       ['Keyword', 'Win32Proj'],
+       ['RootNamespace', namespace],
+       ['IgnoreWarnCompileDuplicatedFilename', 'true'],
+      ]
+  ]
+
+
+def _GetMSBuildConfigurationDetails(spec, build_file):
+  properties = {}
+  for name, settings in spec['configurations'].iteritems():
+    msbuild_attributes = _GetMSBuildAttributes(spec, settings, build_file)
+    condition = _GetConfigurationCondition(name, settings)
+    character_set = msbuild_attributes.get('CharacterSet')
+    _AddConditionalProperty(properties, condition, 'ConfigurationType',
+                            msbuild_attributes['ConfigurationType'])
+    if character_set:
+      _AddConditionalProperty(properties, condition, 'CharacterSet',
+                              character_set)
+  return _GetMSBuildPropertyGroup(spec, 'Configuration', properties)
+
+
+def _GetMSBuildLocalProperties(msbuild_toolset):
+  # Currently the only local property we support is PlatformToolset
+  properties = {}
+  if msbuild_toolset:
+    properties = [
+        ['PropertyGroup', {'Label': 'Locals'},
+          ['PlatformToolset', msbuild_toolset],
+        ]
+      ]
+  return properties
+
+
+def _GetMSBuildPropertySheets(configurations):
+  user_props = r'$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props'
+  additional_props = {}
+  props_specified = False
+  for name, settings in sorted(configurations.iteritems()):
+    configuration = _GetConfigurationCondition(name, settings)
+    if settings.has_key('msbuild_props'):
+      additional_props[configuration] = _FixPaths(settings['msbuild_props'])
+      props_specified = True
+    else:
+     additional_props[configuration] = ''
+
+  if not props_specified:
+    return [
+        ['ImportGroup',
+         {'Label': 'PropertySheets'},
+         ['Import',
+          {'Project': user_props,
+           'Condition': "exists('%s')" % user_props,
+           'Label': 'LocalAppDataPlatform'
+          }
+         ]
+        ]
+    ]
+  else:
+    sheets = []
+    for condition, props in additional_props.iteritems():
+      import_group = [
+        'ImportGroup',
+        {'Label': 'PropertySheets',
+         'Condition': condition
+        },
+        ['Import',
+         {'Project': user_props,
+          'Condition': "exists('%s')" % user_props,
+          'Label': 'LocalAppDataPlatform'
+         }
+        ]
+      ]
+      for props_file in props:
+        import_group.append(['Import', {'Project':props_file}])
+      sheets.append(import_group)
+    return sheets
+
+def _ConvertMSVSBuildAttributes(spec, config, build_file):
+  config_type = _GetMSVSConfigurationType(spec, build_file)
+  msvs_attributes = _GetMSVSAttributes(spec, config, config_type)
+  msbuild_attributes = {}
+  for a in msvs_attributes:
+    if a in ['IntermediateDirectory', 'OutputDirectory']:
+      directory = MSVSSettings.ConvertVCMacrosToMSBuild(msvs_attributes[a])
+      if not directory.endswith('\\'):
+        directory += '\\'
+      msbuild_attributes[a] = directory
+    elif a == 'CharacterSet':
+      msbuild_attributes[a] = _ConvertMSVSCharacterSet(msvs_attributes[a])
+    elif a == 'ConfigurationType':
+      msbuild_attributes[a] = _ConvertMSVSConfigurationType(msvs_attributes[a])
+    else:
+      print 'Warning: Do not know how to convert MSVS attribute ' + a
+  return msbuild_attributes
+
+
+def _ConvertMSVSCharacterSet(char_set):
+  if char_set.isdigit():
+    char_set = {
+        '0': 'MultiByte',
+        '1': 'Unicode',
+        '2': 'MultiByte',
+    }[char_set]
+  return char_set
+
+
+def _ConvertMSVSConfigurationType(config_type):
+  if config_type.isdigit():
+    config_type = {
+        '1': 'Application',
+        '2': 'DynamicLibrary',
+        '4': 'StaticLibrary',
+        '10': 'Utility'
+    }[config_type]
+  return config_type
+
+
+def _GetMSBuildAttributes(spec, config, build_file):
+  if 'msbuild_configuration_attributes' not in config:
+    msbuild_attributes = _ConvertMSVSBuildAttributes(spec, config, build_file)
+
+  else:
+    config_type = _GetMSVSConfigurationType(spec, build_file)
+    config_type = _ConvertMSVSConfigurationType(config_type)
+    msbuild_attributes = config.get('msbuild_configuration_attributes', {})
+    msbuild_attributes.setdefault('ConfigurationType', config_type)
+    output_dir = msbuild_attributes.get('OutputDirectory',
+                                      '$(SolutionDir)$(Configuration)')
+    msbuild_attributes['OutputDirectory'] = _FixPath(output_dir) + '\\'
+    if 'IntermediateDirectory' not in msbuild_attributes:
+      intermediate = _FixPath('$(Configuration)') + '\\'
+      msbuild_attributes['IntermediateDirectory'] = intermediate
+    if 'CharacterSet' in msbuild_attributes:
+      msbuild_attributes['CharacterSet'] = _ConvertMSVSCharacterSet(
+          msbuild_attributes['CharacterSet'])
+  if 'TargetName' not in msbuild_attributes:
+    prefix = spec.get('product_prefix', '')
+    product_name = spec.get('product_name', '$(ProjectName)')
+    target_name = prefix + product_name
+    msbuild_attributes['TargetName'] = target_name
+
+  if spec.get('msvs_external_builder'):
+    external_out_dir = spec.get('msvs_external_builder_out_dir', '.')
+    msbuild_attributes['OutputDirectory'] = _FixPath(external_out_dir) + '\\'
+
+  # Make sure that 'TargetPath' matches 'Lib.OutputFile' or 'Link.OutputFile'
+  # (depending on the tool used) to avoid MSB8012 warning.
+  msbuild_tool_map = {
+      'executable': 'Link',
+      'shared_library': 'Link',
+      'loadable_module': 'Link',
+      'static_library': 'Lib',
+  }
+  msbuild_tool = msbuild_tool_map.get(spec['type'])
+  if msbuild_tool:
+    msbuild_settings = config['finalized_msbuild_settings']
+    out_file = msbuild_settings[msbuild_tool].get('OutputFile')
+    if out_file:
+      msbuild_attributes['TargetPath'] = _FixPath(out_file)
+    target_ext = msbuild_settings[msbuild_tool].get('TargetExt')
+    if target_ext:
+      msbuild_attributes['TargetExt'] = target_ext
+
+  return msbuild_attributes
+
+
+def _GetMSBuildConfigurationGlobalProperties(spec, configurations, build_file):
+  # TODO(jeanluc) We could optimize out the following and do it only if
+  # there are actions.
+  # TODO(jeanluc) Handle the equivalent of setting 'CYGWIN=nontsec'.
+  new_paths = []
+  cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])[0]
+  if cygwin_dirs:
+    cyg_path = '$(MSBuildProjectDirectory)\\%s\\bin\\' % _FixPath(cygwin_dirs)
+    new_paths.append(cyg_path)
+    # TODO(jeanluc) Change the convention to have both a cygwin_dir and a
+    # python_dir.
+    python_path = cyg_path.replace('cygwin\\bin', 'python_26')
+    new_paths.append(python_path)
+    if new_paths:
+      new_paths = '$(ExecutablePath);' + ';'.join(new_paths)
+
+  properties = {}
+  for (name, configuration) in sorted(configurations.iteritems()):
+    condition = _GetConfigurationCondition(name, configuration)
+    attributes = _GetMSBuildAttributes(spec, configuration, build_file)
+    msbuild_settings = configuration['finalized_msbuild_settings']
+    _AddConditionalProperty(properties, condition, 'IntDir',
+                            attributes['IntermediateDirectory'])
+    _AddConditionalProperty(properties, condition, 'OutDir',
+                            attributes['OutputDirectory'])
+    _AddConditionalProperty(properties, condition, 'TargetName',
+                            attributes['TargetName'])
+
+    if attributes.get('TargetPath'):
+      _AddConditionalProperty(properties, condition, 'TargetPath',
+                              attributes['TargetPath'])
+    if attributes.get('TargetExt'):
+      _AddConditionalProperty(properties, condition, 'TargetExt',
+                              attributes['TargetExt'])
+
+    if new_paths:
+      _AddConditionalProperty(properties, condition, 'ExecutablePath',
+                              new_paths)
+    tool_settings = msbuild_settings.get('', {})
+    for name, value in sorted(tool_settings.iteritems()):
+      formatted_value = _GetValueFormattedForMSBuild('', name, value)
+      _AddConditionalProperty(properties, condition, name, formatted_value)
+  return _GetMSBuildPropertyGroup(spec, None, properties)
+
+
+def _AddConditionalProperty(properties, condition, name, value):
+  """Adds a property / conditional value pair to a dictionary.
+
+  Arguments:
+    properties: The dictionary to be modified.  The key is the name of the
+        property.  The value is itself a dictionary; its key is the value and
+        the value a list of condition for which this value is true.
+    condition: The condition under which the named property has the value.
+    name: The name of the property.
+    value: The value of the property.
+  """
+  if name not in properties:
+    properties[name] = {}
+  values = properties[name]
+  if value not in values:
+    values[value] = []
+  conditions = values[value]
+  conditions.append(condition)
+
+
+# Regex for msvs variable references ( i.e. $(FOO) ).
+MSVS_VARIABLE_REFERENCE = re.compile('\$\(([a-zA-Z_][a-zA-Z0-9_]*)\)')
+
+
+def _GetMSBuildPropertyGroup(spec, label, properties):
+  """Returns a PropertyGroup definition for the specified properties.
+
+  Arguments:
+    spec: The target project dict.
+    label: An optional label for the PropertyGroup.
+    properties: The dictionary to be converted.  The key is the name of the
+        property.  The value is itself a dictionary; its key is the value and
+        the value a list of condition for which this value is true.
+  """
+  group = ['PropertyGroup']
+  if label:
+    group.append({'Label': label})
+  num_configurations = len(spec['configurations'])
+  def GetEdges(node):
+    # Use a definition of edges such that user_of_variable -> used_varible.
+    # This happens to be easier in this case, since a variable's
+    # definition contains all variables it references in a single string.
+    edges = set()
+    for value in sorted(properties[node].keys()):
+      # Add to edges all $(...) references to variables.
+      #
+      # Variable references that refer to names not in properties are excluded
+      # These can exist for instance to refer built in definitions like
+      # $(SolutionDir).
+      #
+      # Self references are ignored. Self reference is used in a few places to
+      # append to the default value. I.e. PATH=$(PATH);other_path
+      edges.update(set([v for v in MSVS_VARIABLE_REFERENCE.findall(value)
+                        if v in properties and v != node]))
+    return edges
+  properties_ordered = gyp.common.TopologicallySorted(
+      properties.keys(), GetEdges)
+  # Walk properties in the reverse of a topological sort on
+  # user_of_variable -> used_variable as this ensures variables are
+  # defined before they are used.
+  # NOTE: reverse(topsort(DAG)) = topsort(reverse_edges(DAG))
+  for name in reversed(properties_ordered):
+    values = properties[name]
+    for value, conditions in sorted(values.iteritems()):
+      if len(conditions) == num_configurations:
+        # If the value is the same all configurations,
+        # just add one unconditional entry.
+        group.append([name, value])
+      else:
+        for condition in conditions:
+          group.append([name, {'Condition': condition}, value])
+  return [group]
+
+
+def _GetMSBuildToolSettingsSections(spec, configurations):
+  groups = []
+  for (name, configuration) in sorted(configurations.iteritems()):
+    msbuild_settings = configuration['finalized_msbuild_settings']
+    group = ['ItemDefinitionGroup',
+             {'Condition': _GetConfigurationCondition(name, configuration)}
+            ]
+    for tool_name, tool_settings in sorted(msbuild_settings.iteritems()):
+      # Skip the tool named '' which is a holder of global settings handled
+      # by _GetMSBuildConfigurationGlobalProperties.
+      if tool_name:
+        if tool_settings:
+          tool = [tool_name]
+          for name, value in sorted(tool_settings.iteritems()):
+            formatted_value = _GetValueFormattedForMSBuild(tool_name, name,
+                                                           value)
+            tool.append([name, formatted_value])
+          group.append(tool)
+    groups.append(group)
+  return groups
+
+
+def _FinalizeMSBuildSettings(spec, configuration):
+  if 'msbuild_settings' in configuration:
+    converted = False
+    msbuild_settings = configuration['msbuild_settings']
+    MSVSSettings.ValidateMSBuildSettings(msbuild_settings)
+  else:
+    converted = True
+    msvs_settings = configuration.get('msvs_settings', {})
+    msbuild_settings = MSVSSettings.ConvertToMSBuildSettings(msvs_settings)
+  include_dirs, resource_include_dirs = _GetIncludeDirs(configuration)
+  libraries = _GetLibraries(spec)
+  library_dirs = _GetLibraryDirs(configuration)
+  out_file, _, msbuild_tool = _GetOutputFilePathAndTool(spec, msbuild=True)
+  target_ext = _GetOutputTargetExt(spec)
+  defines = _GetDefines(configuration)
+  if converted:
+    # Visual Studio 2010 has TR1
+    defines = [d for d in defines if d != '_HAS_TR1=0']
+    # Warn of ignored settings
+    ignored_settings = ['msvs_tool_files']
+    for ignored_setting in ignored_settings:
+      value = configuration.get(ignored_setting)
+      if value:
+        print ('Warning: The automatic conversion to MSBuild does not handle '
+               '%s.  Ignoring setting of %s' % (ignored_setting, str(value)))
+
+  defines = [_EscapeCppDefineForMSBuild(d) for d in defines]
+  disabled_warnings = _GetDisabledWarnings(configuration)
+  prebuild = configuration.get('msvs_prebuild')
+  postbuild = configuration.get('msvs_postbuild')
+  def_file = _GetModuleDefinition(spec)
+  precompiled_header = configuration.get('msvs_precompiled_header')
+
+  # Add the information to the appropriate tool
+  # TODO(jeanluc) We could optimize and generate these settings only if
+  # the corresponding files are found, e.g. don't generate ResourceCompile
+  # if you don't have any resources.
+  _ToolAppend(msbuild_settings, 'ClCompile',
+              'AdditionalIncludeDirectories', include_dirs)
+  _ToolAppend(msbuild_settings, 'ResourceCompile',
+              'AdditionalIncludeDirectories', resource_include_dirs)
+  # Add in libraries, note that even for empty libraries, we want this
+  # set, to prevent inheriting default libraries from the enviroment.
+  _ToolSetOrAppend(msbuild_settings, 'Link', 'AdditionalDependencies',
+                  libraries)
+  _ToolAppend(msbuild_settings, 'Link', 'AdditionalLibraryDirectories',
+              library_dirs)
+  if out_file:
+    _ToolAppend(msbuild_settings, msbuild_tool, 'OutputFile', out_file,
+                only_if_unset=True)
+  if target_ext:
+    _ToolAppend(msbuild_settings, msbuild_tool, 'TargetExt', target_ext,
+                only_if_unset=True)
+  # Add defines.
+  _ToolAppend(msbuild_settings, 'ClCompile',
+              'PreprocessorDefinitions', defines)
+  _ToolAppend(msbuild_settings, 'ResourceCompile',
+              'PreprocessorDefinitions', defines)
+  # Add disabled warnings.
+  _ToolAppend(msbuild_settings, 'ClCompile',
+              'DisableSpecificWarnings', disabled_warnings)
+  # Turn on precompiled headers if appropriate.
+  if precompiled_header:
+    precompiled_header = os.path.split(precompiled_header)[1]
+    _ToolAppend(msbuild_settings, 'ClCompile', 'PrecompiledHeader', 'Use')
+    _ToolAppend(msbuild_settings, 'ClCompile',
+                'PrecompiledHeaderFile', precompiled_header)
+    _ToolAppend(msbuild_settings, 'ClCompile',
+                'ForcedIncludeFiles', [precompiled_header])
+  # Loadable modules don't generate import libraries;
+  # tell dependent projects to not expect one.
+  if spec['type'] == 'loadable_module':
+    _ToolAppend(msbuild_settings, '', 'IgnoreImportLibrary', 'true')
+  # Set the module definition file if any.
+  if def_file:
+    _ToolAppend(msbuild_settings, 'Link', 'ModuleDefinitionFile', def_file)
+  configuration['finalized_msbuild_settings'] = msbuild_settings
+  if prebuild:
+    _ToolAppend(msbuild_settings, 'PreBuildEvent', 'Command', prebuild)
+  if postbuild:
+    _ToolAppend(msbuild_settings, 'PostBuildEvent', 'Command', postbuild)
+
+
+def _GetValueFormattedForMSBuild(tool_name, name, value):
+  if type(value) == list:
+    # For some settings, VS2010 does not automatically extends the settings
+    # TODO(jeanluc) Is this what we want?
+    if name in ['AdditionalIncludeDirectories',
+                'AdditionalLibraryDirectories',
+                'AdditionalOptions',
+                'DelayLoadDLLs',
+                'DisableSpecificWarnings',
+                'PreprocessorDefinitions']:
+      value.append('%%(%s)' % name)
+    # For most tools, entries in a list should be separated with ';' but some
+    # settings use a space.  Check for those first.
+    exceptions = {
+        'ClCompile': ['AdditionalOptions'],
+        'Link': ['AdditionalOptions'],
+        'Lib': ['AdditionalOptions']}
+    if tool_name in exceptions and name in exceptions[tool_name]:
+      char = ' '
+    else:
+      char = ';'
+    formatted_value = char.join(
+        [MSVSSettings.ConvertVCMacrosToMSBuild(i) for i in value])
+  else:
+    formatted_value = MSVSSettings.ConvertVCMacrosToMSBuild(value)
+  return formatted_value
+
+
+def _VerifySourcesExist(sources, root_dir):
+  """Verifies that all source files exist on disk.
+
+  Checks that all regular source files, i.e. not created at run time,
+  exist on disk.  Missing files cause needless recompilation but no otherwise
+  visible errors.
+
+  Arguments:
+    sources: A recursive list of Filter/file names.
+    root_dir: The root directory for the relative path names.
+  Returns:
+    A list of source files that cannot be found on disk.
+  """
+  missing_sources = []
+  for source in sources:
+    if isinstance(source, MSVSProject.Filter):
+      missing_sources.extend(_VerifySourcesExist(source.contents, root_dir))
+    else:
+      if '$' not in source:
+        full_path = os.path.join(root_dir, source)
+        if not os.path.exists(full_path):
+          missing_sources.append(full_path)
+  return missing_sources
+
+
+def _GetMSBuildSources(spec, sources, exclusions, extension_to_rule_name,
+                       actions_spec, sources_handled_by_action, list_excluded):
+  groups = ['none', 'midl', 'include', 'compile', 'resource', 'rule']
+  grouped_sources = {}
+  for g in groups:
+    grouped_sources[g] = []
+
+  _AddSources2(spec, sources, exclusions, grouped_sources,
+               extension_to_rule_name, sources_handled_by_action, list_excluded)
+  sources = []
+  for g in groups:
+    if grouped_sources[g]:
+      sources.append(['ItemGroup'] + grouped_sources[g])
+  if actions_spec:
+    sources.append(['ItemGroup'] + actions_spec)
+  return sources
+
+
+def _AddSources2(spec, sources, exclusions, grouped_sources,
+                 extension_to_rule_name, sources_handled_by_action,
+                 list_excluded):
+  extensions_excluded_from_precompile = []
+  for source in sources:
+    if isinstance(source, MSVSProject.Filter):
+      _AddSources2(spec, source.contents, exclusions, grouped_sources,
+                   extension_to_rule_name, sources_handled_by_action,
+                   list_excluded)
+    else:
+      if not source in sources_handled_by_action:
+        detail = []
+        excluded_configurations = exclusions.get(source, [])
+        if len(excluded_configurations) == len(spec['configurations']):
+          detail.append(['ExcludedFromBuild', 'true'])
+        else:
+          for config_name, configuration in sorted(excluded_configurations):
+            condition = _GetConfigurationCondition(config_name, configuration)
+            detail.append(['ExcludedFromBuild',
+                           {'Condition': condition},
+                           'true'])
+        # Add precompile if needed
+        for config_name, configuration in spec['configurations'].iteritems():
+          precompiled_source = configuration.get('msvs_precompiled_source', '')
+          if precompiled_source != '':
+            precompiled_source = _FixPath(precompiled_source)
+            if not extensions_excluded_from_precompile:
+              # If the precompiled header is generated by a C source, we must
+              # not try to use it for C++ sources, and vice versa.
+              basename, extension = os.path.splitext(precompiled_source)
+              if extension == '.c':
+                extensions_excluded_from_precompile = ['.cc', '.cpp', '.cxx']
+              else:
+                extensions_excluded_from_precompile = ['.c']
+
+          if precompiled_source == source:
+            condition = _GetConfigurationCondition(config_name, configuration)
+            detail.append(['PrecompiledHeader',
+                           {'Condition': condition},
+                           'Create'
+                          ])
+          else:
+            # Turn off precompiled header usage for source files of a
+            # different type than the file that generated the
+            # precompiled header.
+            for extension in extensions_excluded_from_precompile:
+              if source.endswith(extension):
+                detail.append(['PrecompiledHeader', ''])
+                detail.append(['ForcedIncludeFiles', ''])
+
+        group, element = _MapFileToMsBuildSourceType(source,
+                                                     extension_to_rule_name)
+        grouped_sources[group].append([element, {'Include': source}] + detail)
+
+
+def _GetMSBuildProjectReferences(project):
+  references = []
+  if project.dependencies:
+    group = ['ItemGroup']
+    for dependency in project.dependencies:
+      guid = dependency.guid
+      project_dir = os.path.split(project.path)[0]
+      relative_path = gyp.common.RelativePath(dependency.path, project_dir)
+      project_ref = ['ProjectReference',
+          {'Include': relative_path},
+          ['Project', guid],
+          ['ReferenceOutputAssembly', 'false']
+          ]
+      for config in dependency.spec.get('configurations', {}).itervalues():
+        # If it's disabled in any config, turn it off in the reference.
+        if config.get('msvs_2010_disable_uldi_when_referenced', 0):
+          project_ref.append(['UseLibraryDependencyInputs', 'false'])
+          break
+      group.append(project_ref)
+    references.append(group)
+  return references
+
+
+def _GenerateMSBuildProject(project, options, version, generator_flags):
+  spec = project.spec
+  configurations = spec['configurations']
+  project_dir, project_file_name = os.path.split(project.path)
+  gyp.common.EnsureDirExists(project.path)
+  # Prepare list of sources and excluded sources.
+  gyp_path = _NormalizedSource(project.build_file)
+  relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, project_dir)
+
+  gyp_file = os.path.split(project.build_file)[1]
+  sources, excluded_sources = _PrepareListOfSources(spec, generator_flags,
+                                                    gyp_file)
+  # Add rules.
+  actions_to_add = {}
+  props_files_of_rules = set()
+  targets_files_of_rules = set()
+  extension_to_rule_name = {}
+  list_excluded = generator_flags.get('msvs_list_excluded_files', True)
+
+  # Don't generate rules if we are using an external builder like ninja.
+  if not spec.get('msvs_external_builder'):
+    _GenerateRulesForMSBuild(project_dir, options, spec,
+                             sources, excluded_sources,
+                             props_files_of_rules, targets_files_of_rules,
+                             actions_to_add, extension_to_rule_name)
+  else:
+    rules = spec.get('rules', [])
+    _AdjustSourcesForRules(spec, rules, sources, excluded_sources)
+
+  sources, excluded_sources, excluded_idl = (
+      _AdjustSourcesAndConvertToFilterHierarchy(spec, options,
+                                                project_dir, sources,
+                                                excluded_sources,
+                                                list_excluded, version))
+
+  # Don't add actions if we are using an external builder like ninja.
+  if not spec.get('msvs_external_builder'):
+    _AddActions(actions_to_add, spec, project.build_file)
+    _AddCopies(actions_to_add, spec)
+
+    # NOTE: this stanza must appear after all actions have been decided.
+    # Don't excluded sources with actions attached, or they won't run.
+    excluded_sources = _FilterActionsFromExcluded(
+        excluded_sources, actions_to_add)
+
+  exclusions = _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl)
+  actions_spec, sources_handled_by_action = _GenerateActionsForMSBuild(
+      spec, actions_to_add)
+
+  _GenerateMSBuildFiltersFile(project.path + '.filters', sources,
+                              extension_to_rule_name)
+  missing_sources = _VerifySourcesExist(sources, project_dir)
+
+  for configuration in configurations.itervalues():
+    _FinalizeMSBuildSettings(spec, configuration)
+
+  # Add attributes to root element
+
+  import_default_section = [
+      ['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.Default.props'}]]
+  import_cpp_props_section = [
+      ['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.props'}]]
+  import_cpp_targets_section = [
+      ['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.targets'}]]
+  macro_section = [['PropertyGroup', {'Label': 'UserMacros'}]]
+
+  content = [
+      'Project',
+      {'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003',
+       'ToolsVersion': version.ProjectVersion(),
+       'DefaultTargets': 'Build'
+      }]
+
+  content += _GetMSBuildProjectConfigurations(configurations)
+  content += _GetMSBuildGlobalProperties(spec, project.guid, project_file_name)
+  content += import_default_section
+  content += _GetMSBuildConfigurationDetails(spec, project.build_file)
+  content += _GetMSBuildLocalProperties(project.msbuild_toolset)
+  content += import_cpp_props_section
+  content += _GetMSBuildExtensions(props_files_of_rules)
+  content += _GetMSBuildPropertySheets(configurations)
+  content += macro_section
+  content += _GetMSBuildConfigurationGlobalProperties(spec, configurations,
+                                                      project.build_file)
+  content += _GetMSBuildToolSettingsSections(spec, configurations)
+  content += _GetMSBuildSources(
+      spec, sources, exclusions, extension_to_rule_name, actions_spec,
+      sources_handled_by_action, list_excluded)
+  content += _GetMSBuildProjectReferences(project)
+  content += import_cpp_targets_section
+  content += _GetMSBuildExtensionTargets(targets_files_of_rules)
+
+  if spec.get('msvs_external_builder'):
+    content += _GetMSBuildExternalBuilderTargets(spec)
+
+  # TODO(jeanluc) File a bug to get rid of runas.  We had in MSVS:
+  # has_run_as = _WriteMSVSUserFile(project.path, version, spec)
+
+  easy_xml.WriteXmlIfChanged(content, project.path, pretty=True, win32=True)
+
+  return missing_sources
+
+
+def _GetMSBuildExternalBuilderTargets(spec):
+  """Return a list of MSBuild targets for external builders.
+
+  The "Build" and "Clean" targets are always generated.  If the spec contains
+  'msvs_external_builder_clcompile_cmd', then the "ClCompile" target will also
+  be generated, to support building selected C/C++ files.
+
+  Arguments:
+    spec: The gyp target spec.
+  Returns:
+    List of MSBuild 'Target' specs.
+  """
+  build_cmd = _BuildCommandLineForRuleRaw(
+      spec, spec['msvs_external_builder_build_cmd'],
+      False, False, False, False)
+  build_target = ['Target', {'Name': 'Build'}]
+  build_target.append(['Exec', {'Command': build_cmd}])
+
+  clean_cmd = _BuildCommandLineForRuleRaw(
+      spec, spec['msvs_external_builder_clean_cmd'],
+      False, False, False, False)
+  clean_target = ['Target', {'Name': 'Clean'}]
+  clean_target.append(['Exec', {'Command': clean_cmd}])
+
+  targets = [build_target, clean_target]
+
+  if spec.get('msvs_external_builder_clcompile_cmd'):
+    clcompile_cmd = _BuildCommandLineForRuleRaw(
+        spec, spec['msvs_external_builder_clcompile_cmd'],
+        False, False, False, False)
+    clcompile_target = ['Target', {'Name': 'ClCompile'}]
+    clcompile_target.append(['Exec', {'Command': clcompile_cmd}])
+    targets.append(clcompile_target)
+
+  return targets
+
+
+def _GetMSBuildExtensions(props_files_of_rules):
+  extensions = ['ImportGroup', {'Label': 'ExtensionSettings'}]
+  for props_file in props_files_of_rules:
+    extensions.append(['Import', {'Project': props_file}])
+  return [extensions]
+
+
+def _GetMSBuildExtensionTargets(targets_files_of_rules):
+  targets_node = ['ImportGroup', {'Label': 'ExtensionTargets'}]
+  for targets_file in sorted(targets_files_of_rules):
+    targets_node.append(['Import', {'Project': targets_file}])
+  return [targets_node]
+
+
+def _GenerateActionsForMSBuild(spec, actions_to_add):
+  """Add actions accumulated into an actions_to_add, merging as needed.
+
+  Arguments:
+    spec: the target project dict
+    actions_to_add: dictionary keyed on input name, which maps to a list of
+        dicts describing the actions attached to that input file.
+
+  Returns:
+    A pair of (action specification, the sources handled by this action).
+  """
+  sources_handled_by_action = OrderedSet()
+  actions_spec = []
+  for primary_input, actions in actions_to_add.iteritems():
+    inputs = OrderedSet()
+    outputs = OrderedSet()
+    descriptions = []
+    commands = []
+    for action in actions:
+      inputs.update(OrderedSet(action['inputs']))
+      outputs.update(OrderedSet(action['outputs']))
+      descriptions.append(action['description'])
+      cmd = action['command']
+      # For most actions, add 'call' so that actions that invoke batch files
+      # return and continue executing.  msbuild_use_call provides a way to
+      # disable this but I have not seen any adverse effect from doing that
+      # for everything.
+      if action.get('msbuild_use_call', True):
+        cmd = 'call ' + cmd
+      commands.append(cmd)
+    # Add the custom build action for one input file.
+    description = ', and also '.join(descriptions)
+
+    # We can't join the commands simply with && because the command line will
+    # get too long. See also _AddActions: cygwin's setup_env mustn't be called
+    # for every invocation or the command that sets the PATH will grow too
+    # long.
+    command = '\r\n'.join([c + '\r\nif %errorlevel% neq 0 exit /b %errorlevel%'
+                           for c in commands])
+    _AddMSBuildAction(spec,
+                      primary_input,
+                      inputs,
+                      outputs,
+                      command,
+                      description,
+                      sources_handled_by_action,
+                      actions_spec)
+  return actions_spec, sources_handled_by_action
+
+
+def _AddMSBuildAction(spec, primary_input, inputs, outputs, cmd, description,
+                      sources_handled_by_action, actions_spec):
+  command = MSVSSettings.ConvertVCMacrosToMSBuild(cmd)
+  primary_input = _FixPath(primary_input)
+  inputs_array = _FixPaths(inputs)
+  outputs_array = _FixPaths(outputs)
+  additional_inputs = ';'.join([i for i in inputs_array
+                                if i != primary_input])
+  outputs = ';'.join(outputs_array)
+  sources_handled_by_action.add(primary_input)
+  action_spec = ['CustomBuild', {'Include': primary_input}]
+  action_spec.extend(
+      # TODO(jeanluc) 'Document' for all or just if as_sources?
+      [['FileType', 'Document'],
+       ['Command', command],
+       ['Message', description],
+       ['Outputs', outputs]
+      ])
+  if additional_inputs:
+    action_spec.append(['AdditionalInputs', additional_inputs])
+  actions_spec.append(action_spec)
diff --git a/gyp/pylib/gyp/generator/msvs_test.py b/gyp/pylib/gyp/generator/msvs_test.py
new file mode 100755 (executable)
index 0000000..c0b021d
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Unit tests for the msvs.py file. """
+
+import gyp.generator.msvs as msvs
+import unittest
+import StringIO
+
+
+class TestSequenceFunctions(unittest.TestCase):
+
+  def setUp(self):
+    self.stderr = StringIO.StringIO()
+
+  def test_GetLibraries(self):
+    self.assertEqual(
+      msvs._GetLibraries({}),
+      [])
+    self.assertEqual(
+      msvs._GetLibraries({'libraries': []}),
+      [])
+    self.assertEqual(
+      msvs._GetLibraries({'other':'foo', 'libraries': ['a.lib']}),
+      ['a.lib'])
+    self.assertEqual(
+      msvs._GetLibraries({'libraries': ['-la']}),
+      ['a.lib'])
+    self.assertEqual(
+      msvs._GetLibraries({'libraries': ['a.lib', 'b.lib', 'c.lib', '-lb.lib',
+                                   '-lb.lib', 'd.lib', 'a.lib']}),
+      ['c.lib', 'b.lib', 'd.lib', 'a.lib'])
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/gyp/pylib/gyp/generator/ninja.py b/gyp/pylib/gyp/generator/ninja.py
new file mode 100644 (file)
index 0000000..4eafb71
--- /dev/null
@@ -0,0 +1,2239 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import copy
+import hashlib
+import json
+import multiprocessing
+import os.path
+import re
+import signal
+import subprocess
+import sys
+import gyp
+import gyp.common
+from gyp.common import OrderedSet
+import gyp.msvs_emulation
+import gyp.MSVSUtil as MSVSUtil
+import gyp.xcode_emulation
+from cStringIO import StringIO
+
+from gyp.common import GetEnvironFallback
+import gyp.ninja_syntax as ninja_syntax
+
+generator_default_variables = {
+  'EXECUTABLE_PREFIX': '',
+  'EXECUTABLE_SUFFIX': '',
+  'STATIC_LIB_PREFIX': 'lib',
+  'STATIC_LIB_SUFFIX': '.a',
+  'SHARED_LIB_PREFIX': 'lib',
+
+  # Gyp expects the following variables to be expandable by the build
+  # system to the appropriate locations.  Ninja prefers paths to be
+  # known at gyp time.  To resolve this, introduce special
+  # variables starting with $! and $| (which begin with a $ so gyp knows it
+  # should be treated specially, but is otherwise an invalid
+  # ninja/shell variable) that are passed to gyp here but expanded
+  # before writing out into the target .ninja files; see
+  # ExpandSpecial.
+  # $! is used for variables that represent a path and that can only appear at
+  # the start of a string, while $| is used for variables that can appear
+  # anywhere in a string.
+  'INTERMEDIATE_DIR': '$!INTERMEDIATE_DIR',
+  'SHARED_INTERMEDIATE_DIR': '$!PRODUCT_DIR/gen',
+  'PRODUCT_DIR': '$!PRODUCT_DIR',
+  'CONFIGURATION_NAME': '$|CONFIGURATION_NAME',
+
+  # Special variables that may be used by gyp 'rule' targets.
+  # We generate definitions for these variables on the fly when processing a
+  # rule.
+  'RULE_INPUT_ROOT': '${root}',
+  'RULE_INPUT_DIRNAME': '${dirname}',
+  'RULE_INPUT_PATH': '${source}',
+  'RULE_INPUT_EXT': '${ext}',
+  'RULE_INPUT_NAME': '${name}',
+}
+
+# Placates pylint.
+generator_additional_non_configuration_keys = []
+generator_additional_path_sections = []
+generator_extra_sources_for_rules = []
+generator_filelist_paths = None
+
+# TODO: figure out how to not build extra host objects in the non-cross-compile
+# case when this is enabled, and enable unconditionally.
+generator_supports_multiple_toolsets = (
+  os.environ.get('GYP_CROSSCOMPILE') or
+  os.environ.get('AR_host') or
+  os.environ.get('CC_host') or
+  os.environ.get('CXX_host') or
+  os.environ.get('AR_target') or
+  os.environ.get('CC_target') or
+  os.environ.get('CXX_target'))
+
+
+def StripPrefix(arg, prefix):
+  if arg.startswith(prefix):
+    return arg[len(prefix):]
+  return arg
+
+
+def QuoteShellArgument(arg, flavor):
+  """Quote a string such that it will be interpreted as a single argument
+  by the shell."""
+  # Rather than attempting to enumerate the bad shell characters, just
+  # whitelist common OK ones and quote anything else.
+  if re.match(r'^[a-zA-Z0-9_=.\\/-]+$', arg):
+    return arg  # No quoting necessary.
+  if flavor == 'win':
+    return gyp.msvs_emulation.QuoteForRspFile(arg)
+  return "'" + arg.replace("'", "'" + '"\'"' + "'")  + "'"
+
+
+def Define(d, flavor):
+  """Takes a preprocessor define and returns a -D parameter that's ninja- and
+  shell-escaped."""
+  if flavor == 'win':
+    # cl.exe replaces literal # characters with = in preprocesor definitions for
+    # some reason. Octal-encode to work around that.
+    d = d.replace('#', '\\%03o' % ord('#'))
+  return QuoteShellArgument(ninja_syntax.escape('-D' + d), flavor)
+
+
+def AddArch(output, arch):
+  """Adds an arch string to an output path."""
+  output, extension = os.path.splitext(output)
+  return '%s.%s%s' % (output, arch, extension)
+
+
+class Target:
+  """Target represents the paths used within a single gyp target.
+
+  Conceptually, building a single target A is a series of steps:
+
+  1) actions/rules/copies  generates source/resources/etc.
+  2) compiles              generates .o files
+  3) link                  generates a binary (library/executable)
+  4) bundle                merges the above in a mac bundle
+
+  (Any of these steps can be optional.)
+
+  From a build ordering perspective, a dependent target B could just
+  depend on the last output of this series of steps.
+
+  But some dependent commands sometimes need to reach inside the box.
+  For example, when linking B it needs to get the path to the static
+  library generated by A.
+
+  This object stores those paths.  To keep things simple, member
+  variables only store concrete paths to single files, while methods
+  compute derived values like "the last output of the target".
+  """
+  def __init__(self, type):
+    # Gyp type ("static_library", etc.) of this target.
+    self.type = type
+    # File representing whether any input dependencies necessary for
+    # dependent actions have completed.
+    self.preaction_stamp = None
+    # File representing whether any input dependencies necessary for
+    # dependent compiles have completed.
+    self.precompile_stamp = None
+    # File representing the completion of actions/rules/copies, if any.
+    self.actions_stamp = None
+    # Path to the output of the link step, if any.
+    self.binary = None
+    # Path to the file representing the completion of building the bundle,
+    # if any.
+    self.bundle = None
+    # On Windows, incremental linking requires linking against all the .objs
+    # that compose a .lib (rather than the .lib itself). That list is stored
+    # here.
+    self.component_objs = None
+    # Windows only. The import .lib is the output of a build step, but
+    # because dependents only link against the lib (not both the lib and the
+    # dll) we keep track of the import library here.
+    self.import_lib = None
+
+  def Linkable(self):
+    """Return true if this is a target that can be linked against."""
+    return self.type in ('static_library', 'shared_library')
+
+  def UsesToc(self, flavor):
+    """Return true if the target should produce a restat rule based on a TOC
+    file."""
+    # For bundles, the .TOC should be produced for the binary, not for
+    # FinalOutput(). But the naive approach would put the TOC file into the
+    # bundle, so don't do this for bundles for now.
+    if flavor == 'win' or self.bundle:
+      return False
+    return self.type in ('shared_library', 'loadable_module')
+
+  def PreActionInput(self, flavor):
+    """Return the path, if any, that should be used as a dependency of
+    any dependent action step."""
+    if self.UsesToc(flavor):
+      return self.FinalOutput() + '.TOC'
+    return self.FinalOutput() or self.preaction_stamp
+
+  def PreCompileInput(self):
+    """Return the path, if any, that should be used as a dependency of
+    any dependent compile step."""
+    return self.actions_stamp or self.precompile_stamp
+
+  def FinalOutput(self):
+    """Return the last output of the target, which depends on all prior
+    steps."""
+    return self.bundle or self.binary or self.actions_stamp
+
+
+# A small discourse on paths as used within the Ninja build:
+# All files we produce (both at gyp and at build time) appear in the
+# build directory (e.g. out/Debug).
+#
+# Paths within a given .gyp file are always relative to the directory
+# containing the .gyp file.  Call these "gyp paths".  This includes
+# sources as well as the starting directory a given gyp rule/action
+# expects to be run from.  We call the path from the source root to
+# the gyp file the "base directory" within the per-.gyp-file
+# NinjaWriter code.
+#
+# All paths as written into the .ninja files are relative to the build
+# directory.  Call these paths "ninja paths".
+#
+# We translate between these two notions of paths with two helper
+# functions:
+#
+# - GypPathToNinja translates a gyp path (i.e. relative to the .gyp file)
+#   into the equivalent ninja path.
+#
+# - GypPathToUniqueOutput translates a gyp path into a ninja path to write
+#   an output file; the result can be namespaced such that it is unique
+#   to the input file name as well as the output target name.
+
+class NinjaWriter:
+  def __init__(self, qualified_target, target_outputs, base_dir, build_dir,
+               output_file, toplevel_build, output_file_name, flavor,
+               toplevel_dir=None):
+    """
+    base_dir: path from source root to directory containing this gyp file,
+              by gyp semantics, all input paths are relative to this
+    build_dir: path from source root to build output
+    toplevel_dir: path to the toplevel directory
+    """
+
+    self.qualified_target = qualified_target
+    self.target_outputs = target_outputs
+    self.base_dir = base_dir
+    self.build_dir = build_dir
+    self.ninja = ninja_syntax.Writer(output_file)
+    self.toplevel_build = toplevel_build
+    self.output_file_name = output_file_name
+
+    self.flavor = flavor
+    self.abs_build_dir = None
+    if toplevel_dir is not None:
+      self.abs_build_dir = os.path.abspath(os.path.join(toplevel_dir,
+                                                        build_dir))
+    self.obj_ext = '.obj' if flavor == 'win' else '.o'
+    if flavor == 'win':
+      # See docstring of msvs_emulation.GenerateEnvironmentFiles().
+      self.win_env = {}
+      for arch in ('x86', 'x64'):
+        self.win_env[arch] = 'environment.' + arch
+
+    # Relative path from build output dir to base dir.
+    build_to_top = gyp.common.InvertRelativePath(build_dir, toplevel_dir)
+    self.build_to_base = os.path.join(build_to_top, base_dir)
+    # Relative path from base dir to build dir.
+    base_to_top = gyp.common.InvertRelativePath(base_dir, toplevel_dir)
+    self.base_to_build = os.path.join(base_to_top, build_dir)
+
+  def ExpandSpecial(self, path, product_dir=None):
+    """Expand specials like $!PRODUCT_DIR in |path|.
+
+    If |product_dir| is None, assumes the cwd is already the product
+    dir.  Otherwise, |product_dir| is the relative path to the product
+    dir.
+    """
+
+    PRODUCT_DIR = '$!PRODUCT_DIR'
+    if PRODUCT_DIR in path:
+      if product_dir:
+        path = path.replace(PRODUCT_DIR, product_dir)
+      else:
+        path = path.replace(PRODUCT_DIR + '/', '')
+        path = path.replace(PRODUCT_DIR + '\\', '')
+        path = path.replace(PRODUCT_DIR, '.')
+
+    INTERMEDIATE_DIR = '$!INTERMEDIATE_DIR'
+    if INTERMEDIATE_DIR in path:
+      int_dir = self.GypPathToUniqueOutput('gen')
+      # GypPathToUniqueOutput generates a path relative to the product dir,
+      # so insert product_dir in front if it is provided.
+      path = path.replace(INTERMEDIATE_DIR,
+                          os.path.join(product_dir or '', int_dir))
+
+    CONFIGURATION_NAME = '$|CONFIGURATION_NAME'
+    path = path.replace(CONFIGURATION_NAME, self.config_name)
+
+    return path
+
+  def ExpandRuleVariables(self, path, root, dirname, source, ext, name):
+    if self.flavor == 'win':
+      path = self.msvs_settings.ConvertVSMacros(
+          path, config=self.config_name)
+    path = path.replace(generator_default_variables['RULE_INPUT_ROOT'], root)
+    path = path.replace(generator_default_variables['RULE_INPUT_DIRNAME'],
+                        dirname)
+    path = path.replace(generator_default_variables['RULE_INPUT_PATH'], source)
+    path = path.replace(generator_default_variables['RULE_INPUT_EXT'], ext)
+    path = path.replace(generator_default_variables['RULE_INPUT_NAME'], name)
+    return path
+
+  def GypPathToNinja(self, path, env=None):
+    """Translate a gyp path to a ninja path, optionally expanding environment
+    variable references in |path| with |env|.
+
+    See the above discourse on path conversions."""
+    if env:
+      if self.flavor == 'mac':
+        path = gyp.xcode_emulation.ExpandEnvVars(path, env)
+      elif self.flavor == 'win':
+        path = gyp.msvs_emulation.ExpandMacros(path, env)
+    if path.startswith('$!'):
+      expanded = self.ExpandSpecial(path)
+      if self.flavor == 'win':
+        expanded = os.path.normpath(expanded)
+      return expanded
+    if '$|' in path:
+      path = self.ExpandSpecial(path)
+    assert '$' not in path, path
+    return os.path.normpath(os.path.join(self.build_to_base, path))
+
+  def GypPathToUniqueOutput(self, path, qualified=True):
+    """Translate a gyp path to a ninja path for writing output.
+
+    If qualified is True, qualify the resulting filename with the name
+    of the target.  This is necessary when e.g. compiling the same
+    path twice for two separate output targets.
+
+    See the above discourse on path conversions."""
+
+    path = self.ExpandSpecial(path)
+    assert not path.startswith('$'), path
+
+    # Translate the path following this scheme:
+    #   Input: foo/bar.gyp, target targ, references baz/out.o
+    #   Output: obj/foo/baz/targ.out.o (if qualified)
+    #           obj/foo/baz/out.o (otherwise)
+    #     (and obj.host instead of obj for cross-compiles)
+    #
+    # Why this scheme and not some other one?
+    # 1) for a given input, you can compute all derived outputs by matching
+    #    its path, even if the input is brought via a gyp file with '..'.
+    # 2) simple files like libraries and stamps have a simple filename.
+
+    obj = 'obj'
+    if self.toolset != 'target':
+      obj += '.' + self.toolset
+
+    path_dir, path_basename = os.path.split(path)
+    if qualified:
+      path_basename = self.name + '.' + path_basename
+    return os.path.normpath(os.path.join(obj, self.base_dir, path_dir,
+                                         path_basename))
+
+  def WriteCollapsedDependencies(self, name, targets, order_only=None):
+    """Given a list of targets, return a path for a single file
+    representing the result of building all the targets or None.
+
+    Uses a stamp file if necessary."""
+
+    assert targets == filter(None, targets), targets
+    if len(targets) == 0:
+      assert not order_only
+      return None
+    if len(targets) > 1 or order_only:
+      stamp = self.GypPathToUniqueOutput(name + '.stamp')
+      targets = self.ninja.build(stamp, 'stamp', targets, order_only=order_only)
+      self.ninja.newline()
+    return targets[0]
+
+  def _SubninjaNameForArch(self, arch):
+    output_file_base = os.path.splitext(self.output_file_name)[0]
+    return '%s.%s.ninja' % (output_file_base, arch)
+
+  def WriteSpec(self, spec, config_name, generator_flags):
+    """The main entry point for NinjaWriter: write the build rules for a spec.
+
+    Returns a Target object, which represents the output paths for this spec.
+    Returns None if there are no outputs (e.g. a settings-only 'none' type
+    target)."""
+
+    self.config_name = config_name
+    self.name = spec['target_name']
+    self.toolset = spec['toolset']
+    config = spec['configurations'][config_name]
+    self.target = Target(spec['type'])
+    self.is_standalone_static_library = bool(
+        spec.get('standalone_static_library', 0))
+    # Track if this target contains any C++ files, to decide if gcc or g++
+    # should be used for linking.
+    self.uses_cpp = False
+
+    self.is_mac_bundle = gyp.xcode_emulation.IsMacBundle(self.flavor, spec)
+    self.xcode_settings = self.msvs_settings = None
+    if self.flavor == 'mac':
+      self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec)
+    if self.flavor == 'win':
+      self.msvs_settings = gyp.msvs_emulation.MsvsSettings(spec,
+                                                           generator_flags)
+      arch = self.msvs_settings.GetArch(config_name)
+      self.ninja.variable('arch', self.win_env[arch])
+      self.ninja.variable('cc', '$cl_' + arch)
+      self.ninja.variable('cxx', '$cl_' + arch)
+      self.ninja.variable('cc_host', '$cl_' + arch)
+      self.ninja.variable('cxx_host', '$cl_' + arch)
+
+    if self.flavor == 'mac':
+      self.archs = self.xcode_settings.GetActiveArchs(config_name)
+      if len(self.archs) > 1:
+        self.arch_subninjas = dict(
+            (arch, ninja_syntax.Writer(
+                OpenOutput(os.path.join(self.toplevel_build,
+                                        self._SubninjaNameForArch(arch)),
+                           'w')))
+            for arch in self.archs)
+
+    # Compute predepends for all rules.
+    # actions_depends is the dependencies this target depends on before running
+    # any of its action/rule/copy steps.
+    # compile_depends is the dependencies this target depends on before running
+    # any of its compile steps.
+    actions_depends = []
+    compile_depends = []
+    # TODO(evan): it is rather confusing which things are lists and which
+    # are strings.  Fix these.
+    if 'dependencies' in spec:
+      for dep in spec['dependencies']:
+        if dep in self.target_outputs:
+          target = self.target_outputs[dep]
+          actions_depends.append(target.PreActionInput(self.flavor))
+          compile_depends.append(target.PreCompileInput())
+      actions_depends = filter(None, actions_depends)
+      compile_depends = filter(None, compile_depends)
+      actions_depends = self.WriteCollapsedDependencies('actions_depends',
+                                                        actions_depends)
+      compile_depends = self.WriteCollapsedDependencies('compile_depends',
+                                                        compile_depends)
+      self.target.preaction_stamp = actions_depends
+      self.target.precompile_stamp = compile_depends
+
+    # Write out actions, rules, and copies.  These must happen before we
+    # compile any sources, so compute a list of predependencies for sources
+    # while we do it.
+    extra_sources = []
+    mac_bundle_depends = []
+    self.target.actions_stamp = self.WriteActionsRulesCopies(
+        spec, extra_sources, actions_depends, mac_bundle_depends)
+
+    # If we have actions/rules/copies, we depend directly on those, but
+    # otherwise we depend on dependent target's actions/rules/copies etc.
+    # We never need to explicitly depend on previous target's link steps,
+    # because no compile ever depends on them.
+    compile_depends_stamp = (self.target.actions_stamp or compile_depends)
+
+    # Write out the compilation steps, if any.
+    link_deps = []
+    sources = extra_sources + spec.get('sources', [])
+    if sources:
+      if self.flavor == 'mac' and len(self.archs) > 1:
+        # Write subninja file containing compile and link commands scoped to
+        # a single arch if a fat binary is being built.
+        for arch in self.archs:
+          self.ninja.subninja(self._SubninjaNameForArch(arch))
+
+      pch = None
+      if self.flavor == 'win':
+        gyp.msvs_emulation.VerifyMissingSources(
+            sources, self.abs_build_dir, generator_flags, self.GypPathToNinja)
+        pch = gyp.msvs_emulation.PrecompiledHeader(
+            self.msvs_settings, config_name, self.GypPathToNinja,
+            self.GypPathToUniqueOutput, self.obj_ext)
+      else:
+        pch = gyp.xcode_emulation.MacPrefixHeader(
+            self.xcode_settings, self.GypPathToNinja,
+            lambda path, lang: self.GypPathToUniqueOutput(path + '-' + lang))
+      link_deps = self.WriteSources(
+          self.ninja, config_name, config, sources, compile_depends_stamp, pch,
+          spec)
+      # Some actions/rules output 'sources' that are already object files.
+      obj_outputs = [f for f in sources if f.endswith(self.obj_ext)]
+      if obj_outputs:
+        if self.flavor != 'mac' or len(self.archs) == 1:
+          link_deps += [self.GypPathToNinja(o) for o in obj_outputs]
+        else:
+          print "Warning: Actions/rules writing object files don't work with " \
+                "multiarch targets, dropping. (target %s)" % spec['target_name']
+    elif self.flavor == 'mac' and len(self.archs) > 1:
+      link_deps = collections.defaultdict(list)
+
+
+    if self.flavor == 'win' and self.target.type == 'static_library':
+      self.target.component_objs = link_deps
+
+    # Write out a link step, if needed.
+    output = None
+    is_empty_bundle = not link_deps and not mac_bundle_depends
+    if link_deps or self.target.actions_stamp or actions_depends:
+      output = self.WriteTarget(spec, config_name, config, link_deps,
+                                self.target.actions_stamp or actions_depends)
+      if self.is_mac_bundle:
+        mac_bundle_depends.append(output)
+
+    # Bundle all of the above together, if needed.
+    if self.is_mac_bundle:
+      output = self.WriteMacBundle(spec, mac_bundle_depends, is_empty_bundle)
+
+    if not output:
+      return None
+
+    assert self.target.FinalOutput(), output
+    return self.target
+
+  def _WinIdlRule(self, source, prebuild, outputs):
+    """Handle the implicit VS .idl rule for one source file. Fills |outputs|
+    with files that are generated."""
+    outdir, output, vars, flags = self.msvs_settings.GetIdlBuildData(
+        source, self.config_name)
+    outdir = self.GypPathToNinja(outdir)
+    def fix_path(path, rel=None):
+      path = os.path.join(outdir, path)
+      dirname, basename = os.path.split(source)
+      root, ext = os.path.splitext(basename)
+      path = self.ExpandRuleVariables(
+          path, root, dirname, source, ext, basename)
+      if rel:
+        path = os.path.relpath(path, rel)
+      return path
+    vars = [(name, fix_path(value, outdir)) for name, value in vars]
+    output = [fix_path(p) for p in output]
+    vars.append(('outdir', outdir))
+    vars.append(('idlflags', flags))
+    input = self.GypPathToNinja(source)
+    self.ninja.build(output, 'idl', input,
+        variables=vars, order_only=prebuild)
+    outputs.extend(output)
+
+  def WriteWinIdlFiles(self, spec, prebuild):
+    """Writes rules to match MSVS's implicit idl handling."""
+    assert self.flavor == 'win'
+    if self.msvs_settings.HasExplicitIdlRulesOrActions(spec):
+      return []
+    outputs = []
+    for source in filter(lambda x: x.endswith('.idl'), spec['sources']):
+      self._WinIdlRule(source, prebuild, outputs)
+    return outputs
+
+  def WriteActionsRulesCopies(self, spec, extra_sources, prebuild,
+                              mac_bundle_depends):
+    """Write out the Actions, Rules, and Copies steps.  Return a path
+    representing the outputs of these steps."""
+    outputs = []
+    if self.is_mac_bundle:
+      mac_bundle_resources = spec.get('mac_bundle_resources', [])[:]
+    else:
+      mac_bundle_resources = []
+    extra_mac_bundle_resources = []
+
+    if 'actions' in spec:
+      outputs += self.WriteActions(spec['actions'], extra_sources, prebuild,
+                                   extra_mac_bundle_resources)
+    if 'rules' in spec:
+      outputs += self.WriteRules(spec['rules'], extra_sources, prebuild,
+                                 mac_bundle_resources,
+                                 extra_mac_bundle_resources)
+    if 'copies' in spec:
+      outputs += self.WriteCopies(spec['copies'], prebuild, mac_bundle_depends)
+
+    if 'sources' in spec and self.flavor == 'win':
+      outputs += self.WriteWinIdlFiles(spec, prebuild)
+
+    stamp = self.WriteCollapsedDependencies('actions_rules_copies', outputs)
+
+    if self.is_mac_bundle:
+      self.WriteMacBundleResources(
+          extra_mac_bundle_resources + mac_bundle_resources, mac_bundle_depends)
+      self.WriteMacInfoPlist(mac_bundle_depends)
+
+    return stamp
+
+  def GenerateDescription(self, verb, message, fallback):
+    """Generate and return a description of a build step.
+
+    |verb| is the short summary, e.g. ACTION or RULE.
+    |message| is a hand-written description, or None if not available.
+    |fallback| is the gyp-level name of the step, usable as a fallback.
+    """
+    if self.toolset != 'target':
+      verb += '(%s)' % self.toolset
+    if message:
+      return '%s %s' % (verb, self.ExpandSpecial(message))
+    else:
+      return '%s %s: %s' % (verb, self.name, fallback)
+
+  def WriteActions(self, actions, extra_sources, prebuild,
+                   extra_mac_bundle_resources):
+    # Actions cd into the base directory.
+    env = self.GetToolchainEnv()
+    all_outputs = []
+    for action in actions:
+      # First write out a rule for the action.
+      name = '%s_%s' % (action['action_name'],
+                        hashlib.md5(self.qualified_target).hexdigest())
+      description = self.GenerateDescription('ACTION',
+                                             action.get('message', None),
+                                             name)
+      is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(action)
+                   if self.flavor == 'win' else False)
+      args = action['action']
+      pool = 'console' if int(action.get('ninja_use_console', 0)) else None
+      rule_name, _ = self.WriteNewNinjaRule(name, args, description,
+                                            is_cygwin, env, pool)
+
+      inputs = [self.GypPathToNinja(i, env) for i in action['inputs']]
+      if int(action.get('process_outputs_as_sources', False)):
+        extra_sources += action['outputs']
+      if int(action.get('process_outputs_as_mac_bundle_resources', False)):
+        extra_mac_bundle_resources += action['outputs']
+      outputs = [self.GypPathToNinja(o, env) for o in action['outputs']]
+
+      # Then write out an edge using the rule.
+      self.ninja.build(outputs, rule_name, inputs,
+                       order_only=prebuild)
+      all_outputs += outputs
+
+      self.ninja.newline()
+
+    return all_outputs
+
+  def WriteRules(self, rules, extra_sources, prebuild,
+                 mac_bundle_resources, extra_mac_bundle_resources):
+    env = self.GetToolchainEnv()
+    all_outputs = []
+    for rule in rules:
+      # Skip a rule with no action and no inputs.
+      if 'action' not in rule and not rule.get('rule_sources', []):
+        continue
+
+      # First write out a rule for the rule action.
+      name = '%s_%s' % (rule['rule_name'],
+                        hashlib.md5(self.qualified_target).hexdigest())
+
+      args = rule['action']
+      description = self.GenerateDescription(
+          'RULE',
+          rule.get('message', None),
+          ('%s ' + generator_default_variables['RULE_INPUT_PATH']) % name)
+      is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(rule)
+                   if self.flavor == 'win' else False)
+      pool = 'console' if int(rule.get('ninja_use_console', 0)) else None
+      rule_name, args = self.WriteNewNinjaRule(
+          name, args, description, is_cygwin, env, pool)
+
+      # TODO: if the command references the outputs directly, we should
+      # simplify it to just use $out.
+
+      # Rules can potentially make use of some special variables which
+      # must vary per source file.
+      # Compute the list of variables we'll need to provide.
+      special_locals = ('source', 'root', 'dirname', 'ext', 'name')
+      needed_variables = set(['source'])
+      for argument in args:
+        for var in special_locals:
+          if ('${%s}' % var) in argument:
+            needed_variables.add(var)
+
+      def cygwin_munge(path):
+        if is_cygwin:
+          return path.replace('\\', '/')
+        return path
+
+      inputs = [self.GypPathToNinja(i, env) for i in rule.get('inputs', [])]
+
+      # If there are n source files matching the rule, and m additional rule
+      # inputs, then adding 'inputs' to each build edge written below will
+      # write m * n inputs. Collapsing reduces this to m + n.
+      sources = rule.get('rule_sources', [])
+      num_inputs = len(inputs)
+      if prebuild:
+        num_inputs += 1
+      if num_inputs > 2 and len(sources) > 2:
+        inputs = [self.WriteCollapsedDependencies(
+          rule['rule_name'], inputs, order_only=prebuild)]
+        prebuild = []
+
+      # For each source file, write an edge that generates all the outputs.
+      for source in sources:
+        source = os.path.normpath(source)
+        dirname, basename = os.path.split(source)
+        root, ext = os.path.splitext(basename)
+
+        # Gather the list of inputs and outputs, expanding $vars if possible.
+        outputs = [self.ExpandRuleVariables(o, root, dirname,
+                                            source, ext, basename)
+                   for o in rule['outputs']]
+
+        if int(rule.get('process_outputs_as_sources', False)):
+          extra_sources += outputs
+
+        was_mac_bundle_resource = source in mac_bundle_resources
+        if was_mac_bundle_resource or \
+            int(rule.get('process_outputs_as_mac_bundle_resources', False)):
+          extra_mac_bundle_resources += outputs
+          # Note: This is n_resources * n_outputs_in_rule.  Put to-be-removed
+          # items in a set and remove them all in a single pass if this becomes
+          # a performance issue.
+          if was_mac_bundle_resource:
+            mac_bundle_resources.remove(source)
+
+        extra_bindings = []
+        for var in needed_variables:
+          if var == 'root':
+            extra_bindings.append(('root', cygwin_munge(root)))
+          elif var == 'dirname':
+            # '$dirname' is a parameter to the rule action, which means
+            # it shouldn't be converted to a Ninja path.  But we don't
+            # want $!PRODUCT_DIR in there either.
+            dirname_expanded = self.ExpandSpecial(dirname, self.base_to_build)
+            extra_bindings.append(('dirname', cygwin_munge(dirname_expanded)))
+          elif var == 'source':
+            # '$source' is a parameter to the rule action, which means
+            # it shouldn't be converted to a Ninja path.  But we don't
+            # want $!PRODUCT_DIR in there either.
+            source_expanded = self.ExpandSpecial(source, self.base_to_build)
+            extra_bindings.append(('source', cygwin_munge(source_expanded)))
+          elif var == 'ext':
+            extra_bindings.append(('ext', ext))
+          elif var == 'name':
+            extra_bindings.append(('name', cygwin_munge(basename)))
+          else:
+            assert var == None, repr(var)
+
+        outputs = [self.GypPathToNinja(o, env) for o in outputs]
+        if self.flavor == 'win':
+          # WriteNewNinjaRule uses unique_name for creating an rsp file on win.
+          extra_bindings.append(('unique_name',
+              hashlib.md5(outputs[0]).hexdigest()))
+        self.ninja.build(outputs, rule_name, self.GypPathToNinja(source),
+                         implicit=inputs,
+                         order_only=prebuild,
+                         variables=extra_bindings)
+
+        all_outputs.extend(outputs)
+
+    return all_outputs
+
+  def WriteCopies(self, copies, prebuild, mac_bundle_depends):
+    outputs = []
+    env = self.GetToolchainEnv()
+    for copy in copies:
+      for path in copy['files']:
+        # Normalize the path so trailing slashes don't confuse us.
+        path = os.path.normpath(path)
+        basename = os.path.split(path)[1]
+        src = self.GypPathToNinja(path, env)
+        dst = self.GypPathToNinja(os.path.join(copy['destination'], basename),
+                                  env)
+        outputs += self.ninja.build(dst, 'copy', src, order_only=prebuild)
+        if self.is_mac_bundle:
+          # gyp has mac_bundle_resources to copy things into a bundle's
+          # Resources folder, but there's no built-in way to copy files to other
+          # places in the bundle. Hence, some targets use copies for this. Check
+          # if this file is copied into the current bundle, and if so add it to
+          # the bundle depends so that dependent targets get rebuilt if the copy
+          # input changes.
+          if dst.startswith(self.xcode_settings.GetBundleContentsFolderPath()):
+            mac_bundle_depends.append(dst)
+
+    return outputs
+
+  def WriteMacBundleResources(self, resources, bundle_depends):
+    """Writes ninja edges for 'mac_bundle_resources'."""
+    for output, res in gyp.xcode_emulation.GetMacBundleResources(
+        generator_default_variables['PRODUCT_DIR'],
+        self.xcode_settings, map(self.GypPathToNinja, resources)):
+      output = self.ExpandSpecial(output)
+      self.ninja.build(output, 'mac_tool', res,
+                       variables=[('mactool_cmd', 'copy-bundle-resource')])
+      bundle_depends.append(output)
+
+  def WriteMacInfoPlist(self, bundle_depends):
+    """Write build rules for bundle Info.plist files."""
+    info_plist, out, defines, extra_env = gyp.xcode_emulation.GetMacInfoPlist(
+        generator_default_variables['PRODUCT_DIR'],
+        self.xcode_settings, self.GypPathToNinja)
+    if not info_plist:
+      return
+    out = self.ExpandSpecial(out)
+    if defines:
+      # Create an intermediate file to store preprocessed results.
+      intermediate_plist = self.GypPathToUniqueOutput(
+          os.path.basename(info_plist))
+      defines = ' '.join([Define(d, self.flavor) for d in defines])
+      info_plist = self.ninja.build(
+          intermediate_plist, 'preprocess_infoplist', info_plist,
+          variables=[('defines',defines)])
+
+    env = self.GetSortedXcodeEnv(additional_settings=extra_env)
+    env = self.ComputeExportEnvString(env)
+
+    keys = self.xcode_settings.GetExtraPlistItems(self.config_name)
+    keys = QuoteShellArgument(json.dumps(keys), self.flavor)
+    self.ninja.build(out, 'copy_infoplist', info_plist,
+                     variables=[('env', env), ('keys', keys)])
+    bundle_depends.append(out)
+
+  def WriteSources(self, ninja_file, config_name, config, sources, predepends,
+                   precompiled_header, spec):
+    """Write build rules to compile all of |sources|."""
+    if self.toolset == 'host':
+      self.ninja.variable('ar', '$ar_host')
+      self.ninja.variable('cc', '$cc_host')
+      self.ninja.variable('cxx', '$cxx_host')
+      self.ninja.variable('ld', '$ld_host')
+      self.ninja.variable('ldxx', '$ldxx_host')
+
+    if self.flavor != 'mac' or len(self.archs) == 1:
+      return self.WriteSourcesForArch(
+          self.ninja, config_name, config, sources, predepends,
+          precompiled_header, spec)
+    else:
+      return dict((arch, self.WriteSourcesForArch(
+            self.arch_subninjas[arch], config_name, config, sources, predepends,
+            precompiled_header, spec, arch=arch))
+          for arch in self.archs)
+
+  def WriteSourcesForArch(self, ninja_file, config_name, config, sources,
+                          predepends, precompiled_header, spec, arch=None):
+    """Write build rules to compile all of |sources|."""
+
+    extra_defines = []
+    if self.flavor == 'mac':
+      cflags = self.xcode_settings.GetCflags(config_name, arch=arch)
+      cflags_c = self.xcode_settings.GetCflagsC(config_name)
+      cflags_cc = self.xcode_settings.GetCflagsCC(config_name)
+      cflags_objc = ['$cflags_c'] + \
+                    self.xcode_settings.GetCflagsObjC(config_name)
+      cflags_objcc = ['$cflags_cc'] + \
+                     self.xcode_settings.GetCflagsObjCC(config_name)
+    elif self.flavor == 'win':
+      asmflags = self.msvs_settings.GetAsmflags(config_name)
+      cflags = self.msvs_settings.GetCflags(config_name)
+      cflags_c = self.msvs_settings.GetCflagsC(config_name)
+      cflags_cc = self.msvs_settings.GetCflagsCC(config_name)
+      extra_defines = self.msvs_settings.GetComputedDefines(config_name)
+      # See comment at cc_command for why there's two .pdb files.
+      pdbpath_c = pdbpath_cc = self.msvs_settings.GetCompilerPdbName(
+          config_name, self.ExpandSpecial)
+      if not pdbpath_c:
+        obj = 'obj'
+        if self.toolset != 'target':
+          obj += '.' + self.toolset
+        pdbpath = os.path.normpath(os.path.join(obj, self.base_dir, self.name))
+        pdbpath_c = pdbpath + '.c.pdb'
+        pdbpath_cc = pdbpath + '.cc.pdb'
+      self.WriteVariableList(ninja_file, 'pdbname_c', [pdbpath_c])
+      self.WriteVariableList(ninja_file, 'pdbname_cc', [pdbpath_cc])
+      self.WriteVariableList(ninja_file, 'pchprefix', [self.name])
+    else:
+      cflags = config.get('cflags', [])
+      cflags_c = config.get('cflags_c', [])
+      cflags_cc = config.get('cflags_cc', [])
+
+    # Respect environment variables related to build, but target-specific
+    # flags can still override them.
+    if self.toolset == 'target':
+      cflags_c = (os.environ.get('CPPFLAGS', '').split() +
+                  os.environ.get('CFLAGS', '').split() + cflags_c)
+      cflags_cc = (os.environ.get('CPPFLAGS', '').split() +
+                   os.environ.get('CXXFLAGS', '').split() + cflags_cc)
+
+    defines = config.get('defines', []) + extra_defines
+    self.WriteVariableList(ninja_file, 'defines',
+                           [Define(d, self.flavor) for d in defines])
+    if self.flavor == 'win':
+      self.WriteVariableList(ninja_file, 'asmflags',
+                             map(self.ExpandSpecial, asmflags))
+      self.WriteVariableList(ninja_file, 'rcflags',
+          [QuoteShellArgument(self.ExpandSpecial(f), self.flavor)
+           for f in self.msvs_settings.GetRcflags(config_name,
+                                                  self.GypPathToNinja)])
+
+    include_dirs = config.get('include_dirs', [])
+
+    env = self.GetToolchainEnv()
+    if self.flavor == 'win':
+      include_dirs = self.msvs_settings.AdjustIncludeDirs(include_dirs,
+                                                          config_name)
+    self.WriteVariableList(ninja_file, 'includes',
+        [QuoteShellArgument('-I' + self.GypPathToNinja(i, env), self.flavor)
+         for i in include_dirs])
+
+    pch_commands = precompiled_header.GetPchBuildCommands(arch)
+    if self.flavor == 'mac':
+      # Most targets use no precompiled headers, so only write these if needed.
+      for ext, var in [('c', 'cflags_pch_c'), ('cc', 'cflags_pch_cc'),
+                       ('m', 'cflags_pch_objc'), ('mm', 'cflags_pch_objcc')]:
+        include = precompiled_header.GetInclude(ext, arch)
+        if include: ninja_file.variable(var, include)
+
+    self.WriteVariableList(ninja_file, 'cflags',
+                           map(self.ExpandSpecial, cflags))
+    self.WriteVariableList(ninja_file, 'cflags_c',
+                           map(self.ExpandSpecial, cflags_c))
+    self.WriteVariableList(ninja_file, 'cflags_cc',
+                           map(self.ExpandSpecial, cflags_cc))
+    if self.flavor == 'mac':
+      self.WriteVariableList(ninja_file, 'cflags_objc',
+                             map(self.ExpandSpecial, cflags_objc))
+      self.WriteVariableList(ninja_file, 'cflags_objcc',
+                             map(self.ExpandSpecial, cflags_objcc))
+    ninja_file.newline()
+    outputs = []
+    has_rc_source = False
+    for source in sources:
+      filename, ext = os.path.splitext(source)
+      ext = ext[1:]
+      obj_ext = self.obj_ext
+      if ext in ('cc', 'cpp', 'cxx'):
+        command = 'cxx'
+        self.uses_cpp = True
+      elif ext == 'c' or (ext == 'S' and self.flavor != 'win'):
+        command = 'cc'
+      elif ext == 's' and self.flavor != 'win':  # Doesn't generate .o.d files.
+        command = 'cc_s'
+      elif (self.flavor == 'win' and ext == 'asm' and
+            self.msvs_settings.GetArch(config_name) == 'x86' and
+            not self.msvs_settings.HasExplicitAsmRules(spec)):
+        # Asm files only get auto assembled for x86 (not x64).
+        command = 'asm'
+        # Add the _asm suffix as msvs is capable of handling .cc and
+        # .asm files of the same name without collision.
+        obj_ext = '_asm.obj'
+      elif self.flavor == 'mac' and ext == 'm':
+        command = 'objc'
+      elif self.flavor == 'mac' and ext == 'mm':
+        command = 'objcxx'
+        self.uses_cpp = True
+      elif self.flavor == 'win' and ext == 'rc':
+        command = 'rc'
+        obj_ext = '.res'
+        has_rc_source = True
+      else:
+        # Ignore unhandled extensions.
+        continue
+      input = self.GypPathToNinja(source)
+      output = self.GypPathToUniqueOutput(filename + obj_ext)
+      if arch is not None:
+        output = AddArch(output, arch)
+      implicit = precompiled_header.GetObjDependencies([input], [output], arch)
+      variables = []
+      if self.flavor == 'win':
+        variables, output, implicit = precompiled_header.GetFlagsModifications(
+            input, output, implicit, command, cflags_c, cflags_cc,
+            self.ExpandSpecial)
+      ninja_file.build(output, command, input,
+                       implicit=[gch for _, _, gch in implicit],
+                       order_only=predepends, variables=variables)
+      outputs.append(output)
+
+    if has_rc_source:
+      resource_include_dirs = config.get('resource_include_dirs', include_dirs)
+      self.WriteVariableList(ninja_file, 'resource_includes',
+          [QuoteShellArgument('-I' + self.GypPathToNinja(i, env), self.flavor)
+           for i in resource_include_dirs])
+
+    self.WritePchTargets(ninja_file, pch_commands)
+
+    ninja_file.newline()
+    return outputs
+
+  def WritePchTargets(self, ninja_file, pch_commands):
+    """Writes ninja rules to compile prefix headers."""
+    if not pch_commands:
+      return
+
+    for gch, lang_flag, lang, input in pch_commands:
+      var_name = {
+        'c': 'cflags_pch_c',
+        'cc': 'cflags_pch_cc',
+        'm': 'cflags_pch_objc',
+        'mm': 'cflags_pch_objcc',
+      }[lang]
+
+      map = { 'c': 'cc', 'cc': 'cxx', 'm': 'objc', 'mm': 'objcxx', }
+      cmd = map.get(lang)
+      ninja_file.build(gch, cmd, input, variables=[(var_name, lang_flag)])
+
+  def WriteLink(self, spec, config_name, config, link_deps):
+    """Write out a link step. Fills out target.binary. """
+    if self.flavor != 'mac' or len(self.archs) == 1:
+      return self.WriteLinkForArch(
+          self.ninja, spec, config_name, config, link_deps)
+    else:
+      output = self.ComputeOutput(spec)
+      inputs = [self.WriteLinkForArch(self.arch_subninjas[arch], spec,
+                                      config_name, config, link_deps[arch],
+                                      arch=arch)
+                for arch in self.archs]
+      extra_bindings = []
+      if not self.is_mac_bundle:
+        self.AppendPostbuildVariable(extra_bindings, spec, output, output)
+      self.ninja.build(output, 'lipo', inputs, variables=extra_bindings)
+      return output
+
+  def WriteLinkForArch(self, ninja_file, spec, config_name, config,
+                       link_deps, arch=None):
+    """Write out a link step. Fills out target.binary. """
+    command = {
+      'executable':      'link',
+      'loadable_module': 'solink_module',
+      'shared_library':  'solink',
+    }[spec['type']]
+    command_suffix = ''
+
+    implicit_deps = set()
+    solibs = set()
+
+    if 'dependencies' in spec:
+      # Two kinds of dependencies:
+      # - Linkable dependencies (like a .a or a .so): add them to the link line.
+      # - Non-linkable dependencies (like a rule that generates a file
+      #   and writes a stamp file): add them to implicit_deps
+      extra_link_deps = set()
+      for dep in spec['dependencies']:
+        target = self.target_outputs.get(dep)
+        if not target:
+          continue
+        linkable = target.Linkable()
+        if linkable:
+          new_deps = []
+          if (self.flavor == 'win' and
+              target.component_objs and
+              self.msvs_settings.IsUseLibraryDependencyInputs(config_name)):
+            new_deps = target.component_objs
+          elif self.flavor == 'win' and target.import_lib:
+            new_deps = [target.import_lib]
+          elif target.UsesToc(self.flavor):
+            solibs.add(target.binary)
+            implicit_deps.add(target.binary + '.TOC')
+          else:
+            new_deps = [target.binary]
+          for new_dep in new_deps:
+            if new_dep not in extra_link_deps:
+              extra_link_deps.add(new_dep)
+              link_deps.append(new_dep)
+
+        final_output = target.FinalOutput()
+        if not linkable or final_output != target.binary:
+          implicit_deps.add(final_output)
+
+    extra_bindings = []
+    if self.uses_cpp and self.flavor != 'win':
+      extra_bindings.append(('ld', '$ldxx'))
+
+    output = self.ComputeOutput(spec, arch)
+    if arch is None and not self.is_mac_bundle:
+      self.AppendPostbuildVariable(extra_bindings, spec, output, output)
+
+    is_executable = spec['type'] == 'executable'
+    # The ldflags config key is not used on mac or win. On those platforms
+    # linker flags are set via xcode_settings and msvs_settings, respectively.
+    env_ldflags = os.environ.get('LDFLAGS', '').split()
+    if self.flavor == 'mac':
+      ldflags = self.xcode_settings.GetLdflags(config_name,
+          self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
+          self.GypPathToNinja, arch)
+      ldflags = env_ldflags + ldflags
+    elif self.flavor == 'win':
+      manifest_base_name = self.GypPathToUniqueOutput(
+          self.ComputeOutputFileName(spec))
+      ldflags, intermediate_manifest, manifest_files = \
+          self.msvs_settings.GetLdflags(config_name, self.GypPathToNinja,
+                                        self.ExpandSpecial, manifest_base_name,
+                                        output, is_executable,
+                                        self.toplevel_build)
+      ldflags = env_ldflags + ldflags
+      self.WriteVariableList(ninja_file, 'manifests', manifest_files)
+      implicit_deps = implicit_deps.union(manifest_files)
+      if intermediate_manifest:
+        self.WriteVariableList(
+            ninja_file, 'intermediatemanifest', [intermediate_manifest])
+      command_suffix = _GetWinLinkRuleNameSuffix(
+          self.msvs_settings.IsEmbedManifest(config_name))
+      def_file = self.msvs_settings.GetDefFile(self.GypPathToNinja)
+      if def_file:
+        implicit_deps.add(def_file)
+    else:
+      # Respect environment variables related to build, but target-specific
+      # flags can still override them.
+      ldflags = env_ldflags + config.get('ldflags', [])
+      if is_executable and len(solibs):
+        rpath = 'lib/'
+        if self.toolset != 'target':
+          rpath += self.toolset
+        ldflags.append('-Wl,-rpath=\$$ORIGIN/%s' % rpath)
+        ldflags.append('-Wl,-rpath-link=%s' % rpath)
+    self.WriteVariableList(ninja_file, 'ldflags',
+                           gyp.common.uniquer(map(self.ExpandSpecial, ldflags)))
+
+    library_dirs = config.get('library_dirs', [])
+    if self.flavor == 'win':
+      library_dirs = [self.msvs_settings.ConvertVSMacros(l, config_name)
+                      for l in library_dirs]
+      library_dirs = ['/LIBPATH:' + QuoteShellArgument(self.GypPathToNinja(l),
+                                                       self.flavor)
+                      for l in library_dirs]
+    else:
+      library_dirs = [QuoteShellArgument('-L' + self.GypPathToNinja(l),
+                                         self.flavor)
+                      for l in library_dirs]
+
+    libraries = gyp.common.uniquer(map(self.ExpandSpecial,
+                                       spec.get('libraries', [])))
+    if self.flavor == 'mac':
+      libraries = self.xcode_settings.AdjustLibraries(libraries, config_name)
+    elif self.flavor == 'win':
+      libraries = self.msvs_settings.AdjustLibraries(libraries)
+
+    self.WriteVariableList(ninja_file, 'libs', library_dirs + libraries)
+
+    linked_binary = output
+
+    if command in ('solink', 'solink_module'):
+      extra_bindings.append(('soname', os.path.split(output)[1]))
+      extra_bindings.append(('lib',
+                            gyp.common.EncodePOSIXShellArgument(output)))
+      if self.flavor != 'win':
+        link_file_list = output
+        if self.is_mac_bundle:
+          # 'Dependency Framework.framework/Versions/A/Dependency Framework' ->
+          # 'Dependency Framework.framework.rsp'
+          link_file_list = self.xcode_settings.GetWrapperName()
+        if arch:
+          link_file_list += '.' + arch
+        link_file_list += '.rsp'
+        # If an rspfile contains spaces, ninja surrounds the filename with
+        # quotes around it and then passes it to open(), creating a file with
+        # quotes in its name (and when looking for the rsp file, the name
+        # makes it through bash which strips the quotes) :-/
+        link_file_list = link_file_list.replace(' ', '_')
+        extra_bindings.append(
+          ('link_file_list',
+            gyp.common.EncodePOSIXShellArgument(link_file_list)))
+      if self.flavor == 'win':
+        extra_bindings.append(('binary', output))
+        if '/NOENTRY' not in ldflags:
+          self.target.import_lib = output + '.lib'
+          extra_bindings.append(('implibflag',
+                                 '/IMPLIB:%s' % self.target.import_lib))
+          pdbname = self.msvs_settings.GetPDBName(
+              config_name, self.ExpandSpecial, output + '.pdb')
+          output = [output, self.target.import_lib]
+          if pdbname:
+            output.append(pdbname)
+      elif not self.is_mac_bundle:
+        output = [output, output + '.TOC']
+      else:
+        command = command + '_notoc'
+    elif self.flavor == 'win':
+      extra_bindings.append(('binary', output))
+      pdbname = self.msvs_settings.GetPDBName(
+          config_name, self.ExpandSpecial, output + '.pdb')
+      if pdbname:
+        output = [output, pdbname]
+
+
+    if len(solibs):
+      extra_bindings.append(('solibs', gyp.common.EncodePOSIXShellList(solibs)))
+
+    ninja_file.build(output, command + command_suffix, link_deps,
+                     implicit=list(implicit_deps),
+                     variables=extra_bindings)
+    return linked_binary
+
+  def WriteTarget(self, spec, config_name, config, link_deps, compile_deps):
+    extra_link_deps = any(self.target_outputs.get(dep).Linkable()
+                          for dep in spec.get('dependencies', [])
+                          if dep in self.target_outputs)
+    if spec['type'] == 'none' or (not link_deps and not extra_link_deps):
+      # TODO(evan): don't call this function for 'none' target types, as
+      # it doesn't do anything, and we fake out a 'binary' with a stamp file.
+      self.target.binary = compile_deps
+      self.target.type = 'none'
+    elif spec['type'] == 'static_library':
+      self.target.binary = self.ComputeOutput(spec)
+      if (self.flavor not in ('mac', 'openbsd', 'win') and not
+          self.is_standalone_static_library):
+        self.ninja.build(self.target.binary, 'alink_thin', link_deps,
+                         order_only=compile_deps)
+      else:
+        variables = []
+        if self.xcode_settings:
+          libtool_flags = self.xcode_settings.GetLibtoolflags(config_name)
+          if libtool_flags:
+            variables.append(('libtool_flags', libtool_flags))
+        if self.msvs_settings:
+          libflags = self.msvs_settings.GetLibFlags(config_name,
+                                                    self.GypPathToNinja)
+          variables.append(('libflags', libflags))
+
+        if self.flavor != 'mac' or len(self.archs) == 1:
+          self.AppendPostbuildVariable(variables, spec,
+                                       self.target.binary, self.target.binary)
+          self.ninja.build(self.target.binary, 'alink', link_deps,
+                           order_only=compile_deps, variables=variables)
+        else:
+          inputs = []
+          for arch in self.archs:
+            output = self.ComputeOutput(spec, arch)
+            self.arch_subninjas[arch].build(output, 'alink', link_deps[arch],
+                                            order_only=compile_deps,
+                                            variables=variables)
+            inputs.append(output)
+          # TODO: It's not clear if libtool_flags should be passed to the alink
+          # call that combines single-arch .a files into a fat .a file.
+          self.AppendPostbuildVariable(variables, spec,
+                                       self.target.binary, self.target.binary)
+          self.ninja.build(self.target.binary, 'alink', inputs,
+                           # FIXME: test proving order_only=compile_deps isn't
+                           # needed.
+                           variables=variables)
+    else:
+      self.target.binary = self.WriteLink(spec, config_name, config, link_deps)
+    return self.target.binary
+
+  def WriteMacBundle(self, spec, mac_bundle_depends, is_empty):
+    assert self.is_mac_bundle
+    package_framework = spec['type'] in ('shared_library', 'loadable_module')
+    output = self.ComputeMacBundleOutput()
+    if is_empty:
+      output += '.stamp'
+    variables = []
+    self.AppendPostbuildVariable(variables, spec, output, self.target.binary,
+                                 is_command_start=not package_framework)
+    if package_framework and not is_empty:
+      variables.append(('version', self.xcode_settings.GetFrameworkVersion()))
+      self.ninja.build(output, 'package_framework', mac_bundle_depends,
+                       variables=variables)
+    else:
+      self.ninja.build(output, 'stamp', mac_bundle_depends,
+                       variables=variables)
+    self.target.bundle = output
+    return output
+
+  def GetToolchainEnv(self, additional_settings=None):
+    """Returns the variables toolchain would set for build steps."""
+    env = self.GetSortedXcodeEnv(additional_settings=additional_settings)
+    if self.flavor == 'win':
+      env = self.GetMsvsToolchainEnv(
+          additional_settings=additional_settings)
+    return env
+
+  def GetMsvsToolchainEnv(self, additional_settings=None):
+    """Returns the variables Visual Studio would set for build steps."""
+    return self.msvs_settings.GetVSMacroEnv('$!PRODUCT_DIR',
+                                             config=self.config_name)
+
+  def GetSortedXcodeEnv(self, additional_settings=None):
+    """Returns the variables Xcode would set for build steps."""
+    assert self.abs_build_dir
+    abs_build_dir = self.abs_build_dir
+    return gyp.xcode_emulation.GetSortedXcodeEnv(
+        self.xcode_settings, abs_build_dir,
+        os.path.join(abs_build_dir, self.build_to_base), self.config_name,
+        additional_settings)
+
+  def GetSortedXcodePostbuildEnv(self):
+    """Returns the variables Xcode would set for postbuild steps."""
+    postbuild_settings = {}
+    # CHROMIUM_STRIP_SAVE_FILE is a chromium-specific hack.
+    # TODO(thakis): It would be nice to have some general mechanism instead.
+    strip_save_file = self.xcode_settings.GetPerTargetSetting(
+        'CHROMIUM_STRIP_SAVE_FILE')
+    if strip_save_file:
+      postbuild_settings['CHROMIUM_STRIP_SAVE_FILE'] = strip_save_file
+    return self.GetSortedXcodeEnv(additional_settings=postbuild_settings)
+
+  def AppendPostbuildVariable(self, variables, spec, output, binary,
+                              is_command_start=False):
+    """Adds a 'postbuild' variable if there is a postbuild for |output|."""
+    postbuild = self.GetPostbuildCommand(spec, output, binary, is_command_start)
+    if postbuild:
+      variables.append(('postbuilds', postbuild))
+
+  def GetPostbuildCommand(self, spec, output, output_binary, is_command_start):
+    """Returns a shell command that runs all the postbuilds, and removes
+    |output| if any of them fails. If |is_command_start| is False, then the
+    returned string will start with ' && '."""
+    if not self.xcode_settings or spec['type'] == 'none' or not output:
+      return ''
+    output = QuoteShellArgument(output, self.flavor)
+    postbuilds = gyp.xcode_emulation.GetSpecPostbuildCommands(spec, quiet=True)
+    if output_binary is not None:
+      postbuilds = self.xcode_settings.AddImplicitPostbuilds(
+          self.config_name,
+          os.path.normpath(os.path.join(self.base_to_build, output)),
+          QuoteShellArgument(
+              os.path.normpath(os.path.join(self.base_to_build, output_binary)),
+              self.flavor),
+          postbuilds, quiet=True)
+
+    if not postbuilds:
+      return ''
+    # Postbuilds expect to be run in the gyp file's directory, so insert an
+    # implicit postbuild to cd to there.
+    postbuilds.insert(0, gyp.common.EncodePOSIXShellList(
+        ['cd', self.build_to_base]))
+    env = self.ComputeExportEnvString(self.GetSortedXcodePostbuildEnv())
+    # G will be non-null if any postbuild fails. Run all postbuilds in a
+    # subshell.
+    commands = env + ' (' + \
+        ' && '.join([ninja_syntax.escape(command) for command in postbuilds])
+    command_string = (commands + '); G=$$?; '
+                      # Remove the final output if any postbuild failed.
+                      '((exit $$G) || rm -rf %s) ' % output + '&& exit $$G)')
+    if is_command_start:
+      return '(' + command_string + ' && '
+    else:
+      return '$ && (' + command_string
+
+  def ComputeExportEnvString(self, env):
+    """Given an environment, returns a string looking like
+        'export FOO=foo; export BAR="${FOO} bar;'
+    that exports |env| to the shell."""
+    export_str = []
+    for k, v in env:
+      export_str.append('export %s=%s;' %
+          (k, ninja_syntax.escape(gyp.common.EncodePOSIXShellArgument(v))))
+    return ' '.join(export_str)
+
+  def ComputeMacBundleOutput(self):
+    """Return the 'output' (full output path) to a bundle output directory."""
+    assert self.is_mac_bundle
+    path = generator_default_variables['PRODUCT_DIR']
+    return self.ExpandSpecial(
+        os.path.join(path, self.xcode_settings.GetWrapperName()))
+
+  def ComputeOutputFileName(self, spec, type=None):
+    """Compute the filename of the final output for the current target."""
+    if not type:
+      type = spec['type']
+
+    default_variables = copy.copy(generator_default_variables)
+    CalculateVariables(default_variables, {'flavor': self.flavor})
+
+    # Compute filename prefix: the product prefix, or a default for
+    # the product type.
+    DEFAULT_PREFIX = {
+      'loadable_module': default_variables['SHARED_LIB_PREFIX'],
+      'shared_library': default_variables['SHARED_LIB_PREFIX'],
+      'static_library': default_variables['STATIC_LIB_PREFIX'],
+      'executable': default_variables['EXECUTABLE_PREFIX'],
+      }
+    prefix = spec.get('product_prefix', DEFAULT_PREFIX.get(type, ''))
+
+    # Compute filename extension: the product extension, or a default
+    # for the product type.
+    DEFAULT_EXTENSION = {
+        'loadable_module': default_variables['SHARED_LIB_SUFFIX'],
+        'shared_library': default_variables['SHARED_LIB_SUFFIX'],
+        'static_library': default_variables['STATIC_LIB_SUFFIX'],
+        'executable': default_variables['EXECUTABLE_SUFFIX'],
+      }
+    extension = spec.get('product_extension')
+    if extension:
+      extension = '.' + extension
+    else:
+      extension = DEFAULT_EXTENSION.get(type, '')
+
+    if 'product_name' in spec:
+      # If we were given an explicit name, use that.
+      target = spec['product_name']
+    else:
+      # Otherwise, derive a name from the target name.
+      target = spec['target_name']
+      if prefix == 'lib':
+        # Snip out an extra 'lib' from libs if appropriate.
+        target = StripPrefix(target, 'lib')
+
+    if type in ('static_library', 'loadable_module', 'shared_library',
+                        'executable'):
+      return '%s%s%s' % (prefix, target, extension)
+    elif type == 'none':
+      return '%s.stamp' % target
+    else:
+      raise Exception('Unhandled output type %s' % type)
+
+  def ComputeOutput(self, spec, arch=None):
+    """Compute the path for the final output of the spec."""
+    type = spec['type']
+
+    if self.flavor == 'win':
+      override = self.msvs_settings.GetOutputName(self.config_name,
+                                                  self.ExpandSpecial)
+      if override:
+        return override
+
+    if arch is None and self.flavor == 'mac' and type in (
+        'static_library', 'executable', 'shared_library', 'loadable_module'):
+      filename = self.xcode_settings.GetExecutablePath()
+    else:
+      filename = self.ComputeOutputFileName(spec, type)
+
+    if arch is None and 'product_dir' in spec:
+      path = os.path.join(spec['product_dir'], filename)
+      return self.ExpandSpecial(path)
+
+    # Some products go into the output root, libraries go into shared library
+    # dir, and everything else goes into the normal place.
+    type_in_output_root = ['executable', 'loadable_module']
+    if self.flavor == 'mac' and self.toolset == 'target':
+      type_in_output_root += ['shared_library', 'static_library']
+    elif self.flavor == 'win' and self.toolset == 'target':
+      type_in_output_root += ['shared_library']
+
+    if arch is not None:
+      # Make sure partial executables don't end up in a bundle or the regular
+      # output directory.
+      archdir = 'arch'
+      if self.toolset != 'target':
+        archdir = os.path.join('arch', '%s' % self.toolset)
+      return os.path.join(archdir, AddArch(filename, arch))
+    elif type in type_in_output_root or self.is_standalone_static_library:
+      return filename
+    elif type == 'shared_library':
+      libdir = 'lib'
+      if self.toolset != 'target':
+        libdir = os.path.join('lib', '%s' % self.toolset)
+      return os.path.join(libdir, filename)
+    else:
+      return self.GypPathToUniqueOutput(filename, qualified=False)
+
+  def WriteVariableList(self, ninja_file, var, values):
+    assert not isinstance(values, str)
+    if values is None:
+      values = []
+    ninja_file.variable(var, ' '.join(values))
+
+  def WriteNewNinjaRule(self, name, args, description, is_cygwin, env, pool):
+    """Write out a new ninja "rule" statement for a given command.
+
+    Returns the name of the new rule, and a copy of |args| with variables
+    expanded."""
+
+    if self.flavor == 'win':
+      args = [self.msvs_settings.ConvertVSMacros(
+                  arg, self.base_to_build, config=self.config_name)
+              for arg in args]
+      description = self.msvs_settings.ConvertVSMacros(
+          description, config=self.config_name)
+    elif self.flavor == 'mac':
+      # |env| is an empty list on non-mac.
+      args = [gyp.xcode_emulation.ExpandEnvVars(arg, env) for arg in args]
+      description = gyp.xcode_emulation.ExpandEnvVars(description, env)
+
+    # TODO: we shouldn't need to qualify names; we do it because
+    # currently the ninja rule namespace is global, but it really
+    # should be scoped to the subninja.
+    rule_name = self.name
+    if self.toolset == 'target':
+      rule_name += '.' + self.toolset
+    rule_name += '.' + name
+    rule_name = re.sub('[^a-zA-Z0-9_]', '_', rule_name)
+
+    # Remove variable references, but not if they refer to the magic rule
+    # variables.  This is not quite right, as it also protects these for
+    # actions, not just for rules where they are valid. Good enough.
+    protect = [ '${root}', '${dirname}', '${source}', '${ext}', '${name}' ]
+    protect = '(?!' + '|'.join(map(re.escape, protect)) + ')'
+    description = re.sub(protect + r'\$', '_', description)
+
+    # gyp dictates that commands are run from the base directory.
+    # cd into the directory before running, and adjust paths in
+    # the arguments to point to the proper locations.
+    rspfile = None
+    rspfile_content = None
+    args = [self.ExpandSpecial(arg, self.base_to_build) for arg in args]
+    if self.flavor == 'win':
+      rspfile = rule_name + '.$unique_name.rsp'
+      # The cygwin case handles this inside the bash sub-shell.
+      run_in = '' if is_cygwin else ' ' + self.build_to_base
+      if is_cygwin:
+        rspfile_content = self.msvs_settings.BuildCygwinBashCommandLine(
+            args, self.build_to_base)
+      else:
+        rspfile_content = gyp.msvs_emulation.EncodeRspFileList(args)
+      command = ('%s gyp-win-tool action-wrapper $arch ' % sys.executable +
+                 rspfile + run_in)
+    else:
+      env = self.ComputeExportEnvString(env)
+      command = gyp.common.EncodePOSIXShellList(args)
+      command = 'cd %s; ' % self.build_to_base + env + command
+
+    # GYP rules/actions express being no-ops by not touching their outputs.
+    # Avoid executing downstream dependencies in this case by specifying
+    # restat=1 to ninja.
+    self.ninja.rule(rule_name, command, description, restat=True, pool=pool,
+                    rspfile=rspfile, rspfile_content=rspfile_content)
+    self.ninja.newline()
+
+    return rule_name, args
+
+
+def CalculateVariables(default_variables, params):
+  """Calculate additional variables for use in the build (called by gyp)."""
+  global generator_additional_non_configuration_keys
+  global generator_additional_path_sections
+  flavor = gyp.common.GetFlavor(params)
+  if flavor == 'mac':
+    default_variables.setdefault('OS', 'mac')
+    default_variables.setdefault('SHARED_LIB_SUFFIX', '.dylib')
+    default_variables.setdefault('SHARED_LIB_DIR',
+                                 generator_default_variables['PRODUCT_DIR'])
+    default_variables.setdefault('LIB_DIR',
+                                 generator_default_variables['PRODUCT_DIR'])
+
+    # Copy additional generator configuration data from Xcode, which is shared
+    # by the Mac Ninja generator.
+    import gyp.generator.xcode as xcode_generator
+    generator_additional_non_configuration_keys = getattr(xcode_generator,
+        'generator_additional_non_configuration_keys', [])
+    generator_additional_path_sections = getattr(xcode_generator,
+        'generator_additional_path_sections', [])
+    global generator_extra_sources_for_rules
+    generator_extra_sources_for_rules = getattr(xcode_generator,
+        'generator_extra_sources_for_rules', [])
+  elif flavor == 'win':
+    default_variables.setdefault('OS', 'win')
+    default_variables['EXECUTABLE_SUFFIX'] = '.exe'
+    default_variables['STATIC_LIB_PREFIX'] = ''
+    default_variables['STATIC_LIB_SUFFIX'] = '.lib'
+    default_variables['SHARED_LIB_PREFIX'] = ''
+    default_variables['SHARED_LIB_SUFFIX'] = '.dll'
+
+    # Copy additional generator configuration data from VS, which is shared
+    # by the Windows Ninja generator.
+    import gyp.generator.msvs as msvs_generator
+    generator_additional_non_configuration_keys = getattr(msvs_generator,
+        'generator_additional_non_configuration_keys', [])
+    generator_additional_path_sections = getattr(msvs_generator,
+        'generator_additional_path_sections', [])
+
+    gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
+  else:
+    operating_system = flavor
+    if flavor == 'android':
+      operating_system = 'linux'  # Keep this legacy behavior for now.
+    default_variables.setdefault('OS', operating_system)
+    default_variables.setdefault('SHARED_LIB_SUFFIX', '.so')
+    default_variables.setdefault('SHARED_LIB_DIR',
+                                 os.path.join('$!PRODUCT_DIR', 'lib'))
+    default_variables.setdefault('LIB_DIR',
+                                 os.path.join('$!PRODUCT_DIR', 'obj'))
+
+def ComputeOutputDir(params):
+  """Returns the path from the toplevel_dir to the build output directory."""
+  # generator_dir: relative path from pwd to where make puts build files.
+  # Makes migrating from make to ninja easier, ninja doesn't put anything here.
+  generator_dir = os.path.relpath(params['options'].generator_output or '.')
+
+  # output_dir: relative path from generator_dir to the build directory.
+  output_dir = params.get('generator_flags', {}).get('output_dir', 'out')
+
+  # Relative path from source root to our output files.  e.g. "out"
+  return os.path.normpath(os.path.join(generator_dir, output_dir))
+
+
+def CalculateGeneratorInputInfo(params):
+  """Called by __init__ to initialize generator values based on params."""
+  # E.g. "out/gypfiles"
+  toplevel = params['options'].toplevel_dir
+  qualified_out_dir = os.path.normpath(os.path.join(
+      toplevel, ComputeOutputDir(params), 'gypfiles'))
+
+  global generator_filelist_paths
+  generator_filelist_paths = {
+      'toplevel': toplevel,
+      'qualified_out_dir': qualified_out_dir,
+  }
+
+
+def OpenOutput(path, mode='w'):
+  """Open |path| for writing, creating directories if necessary."""
+  gyp.common.EnsureDirExists(path)
+  return open(path, mode)
+
+
+def CommandWithWrapper(cmd, wrappers, prog):
+  wrapper = wrappers.get(cmd, '')
+  if wrapper:
+    return wrapper + ' ' + prog
+  return prog
+
+
+def GetDefaultConcurrentLinks():
+  """Returns a best-guess for a number of concurrent links."""
+  pool_size = int(os.getenv('GYP_LINK_CONCURRENCY', 0))
+  if pool_size:
+    return pool_size
+
+  if sys.platform in ('win32', 'cygwin'):
+    import ctypes
+
+    class MEMORYSTATUSEX(ctypes.Structure):
+      _fields_ = [
+        ("dwLength", ctypes.c_ulong),
+        ("dwMemoryLoad", ctypes.c_ulong),
+        ("ullTotalPhys", ctypes.c_ulonglong),
+        ("ullAvailPhys", ctypes.c_ulonglong),
+        ("ullTotalPageFile", ctypes.c_ulonglong),
+        ("ullAvailPageFile", ctypes.c_ulonglong),
+        ("ullTotalVirtual", ctypes.c_ulonglong),
+        ("ullAvailVirtual", ctypes.c_ulonglong),
+        ("sullAvailExtendedVirtual", ctypes.c_ulonglong),
+      ]
+
+    stat = MEMORYSTATUSEX()
+    stat.dwLength = ctypes.sizeof(stat)
+    ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat))
+
+    mem_limit = max(1, stat.ullTotalPhys / (4 * (2 ** 30)))  # total / 4GB
+    hard_cap = max(1, int(os.getenv('GYP_LINK_CONCURRENCY_MAX', 2**32)))
+    return min(mem_limit, hard_cap)
+  elif sys.platform.startswith('linux'):
+    if os.path.exists("/proc/meminfo"):
+      with open("/proc/meminfo") as meminfo:
+        memtotal_re = re.compile(r'^MemTotal:\s*(\d*)\s*kB')
+        for line in meminfo:
+          match = memtotal_re.match(line)
+          if not match:
+            continue
+          # Allow 8Gb per link on Linux because Gold is quite memory hungry
+          return max(1, int(match.group(1)) / (8 * (2 ** 20)))
+    return 1
+  elif sys.platform == 'darwin':
+    try:
+      avail_bytes = int(subprocess.check_output(['sysctl', '-n', 'hw.memsize']))
+      # A static library debug build of Chromium's unit_tests takes ~2.7GB, so
+      # 4GB per ld process allows for some more bloat.
+      return max(1, avail_bytes / (4 * (2 ** 30)))  # total / 4GB
+    except:
+      return 1
+  else:
+    # TODO(scottmg): Implement this for other platforms.
+    return 1
+
+
+def _GetWinLinkRuleNameSuffix(embed_manifest):
+  """Returns the suffix used to select an appropriate linking rule depending on
+  whether the manifest embedding is enabled."""
+  return '_embed' if embed_manifest else ''
+
+
+def _AddWinLinkRules(master_ninja, embed_manifest):
+  """Adds link rules for Windows platform to |master_ninja|."""
+  def FullLinkCommand(ldcmd, out, binary_type):
+    resource_name = {
+      'exe': '1',
+      'dll': '2',
+    }[binary_type]
+    return '%(python)s gyp-win-tool link-with-manifests $arch %(embed)s ' \
+           '%(out)s "%(ldcmd)s" %(resname)s $mt $rc "$intermediatemanifest" ' \
+           '$manifests' % {
+               'python': sys.executable,
+               'out': out,
+               'ldcmd': ldcmd,
+               'resname': resource_name,
+               'embed': embed_manifest }
+  rule_name_suffix = _GetWinLinkRuleNameSuffix(embed_manifest)
+  use_separate_mspdbsrv = (
+      int(os.environ.get('GYP_USE_SEPARATE_MSPDBSRV', '0')) != 0)
+  dlldesc = 'LINK%s(DLL) $binary' % rule_name_suffix.upper()
+  dllcmd = ('%s gyp-win-tool link-wrapper $arch %s '
+            '$ld /nologo $implibflag /DLL /OUT:$binary '
+            '@$binary.rsp' % (sys.executable, use_separate_mspdbsrv))
+  dllcmd = FullLinkCommand(dllcmd, '$binary', 'dll')
+  master_ninja.rule('solink' + rule_name_suffix,
+                    description=dlldesc, command=dllcmd,
+                    rspfile='$binary.rsp',
+                    rspfile_content='$libs $in_newline $ldflags',
+                    restat=True,
+                    pool='link_pool')
+  master_ninja.rule('solink_module' + rule_name_suffix,
+                    description=dlldesc, command=dllcmd,
+                    rspfile='$binary.rsp',
+                    rspfile_content='$libs $in_newline $ldflags',
+                    restat=True,
+                    pool='link_pool')
+  # Note that ldflags goes at the end so that it has the option of
+  # overriding default settings earlier in the command line.
+  exe_cmd = ('%s gyp-win-tool link-wrapper $arch %s '
+             '$ld /nologo /OUT:$binary @$binary.rsp' %
+              (sys.executable, use_separate_mspdbsrv))
+  exe_cmd = FullLinkCommand(exe_cmd, '$binary', 'exe')
+  master_ninja.rule('link' + rule_name_suffix,
+                    description='LINK%s $binary' % rule_name_suffix.upper(),
+                    command=exe_cmd,
+                    rspfile='$binary.rsp',
+                    rspfile_content='$in_newline $libs $ldflags',
+                    pool='link_pool')
+
+
+def GenerateOutputForConfig(target_list, target_dicts, data, params,
+                            config_name):
+  options = params['options']
+  flavor = gyp.common.GetFlavor(params)
+  generator_flags = params.get('generator_flags', {})
+
+  # build_dir: relative path from source root to our output files.
+  # e.g. "out/Debug"
+  build_dir = os.path.normpath(
+      os.path.join(ComputeOutputDir(params), config_name))
+
+  toplevel_build = os.path.join(options.toplevel_dir, build_dir)
+
+  master_ninja_file = OpenOutput(os.path.join(toplevel_build, 'build.ninja'))
+  master_ninja = ninja_syntax.Writer(master_ninja_file, width=120)
+
+  # Put build-time support tools in out/{config_name}.
+  gyp.common.CopyTool(flavor, toplevel_build)
+
+  # Grab make settings for CC/CXX.
+  # The rules are
+  # - The priority from low to high is gcc/g++, the 'make_global_settings' in
+  #   gyp, the environment variable.
+  # - If there is no 'make_global_settings' for CC.host/CXX.host or
+  #   'CC_host'/'CXX_host' enviroment variable, cc_host/cxx_host should be set
+  #   to cc/cxx.
+  if flavor == 'win':
+    ar = 'lib.exe'
+    # cc and cxx must be set to the correct architecture by overriding with one
+    # of cl_x86 or cl_x64 below.
+    cc = 'UNSET'
+    cxx = 'UNSET'
+    ld = 'link.exe'
+    ld_host = '$ld'
+  else:
+    ar = 'ar'
+    cc = 'cc'
+    cxx = 'c++'
+    ld = '$cc'
+    ldxx = '$cxx'
+    ld_host = '$cc_host'
+    ldxx_host = '$cxx_host'
+
+  ar_host = 'ar'
+  cc_host = None
+  cxx_host = None
+  cc_host_global_setting = None
+  cxx_host_global_setting = None
+  clang_cl = None
+
+  build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
+  make_global_settings = data[build_file].get('make_global_settings', [])
+  build_to_root = gyp.common.InvertRelativePath(build_dir,
+                                                options.toplevel_dir)
+  wrappers = {}
+  for key, value in make_global_settings:
+    if key == 'AR':
+      ar = os.path.join(build_to_root, value)
+    if key == 'AR.host':
+      ar_host = os.path.join(build_to_root, value)
+    if key == 'CC':
+      cc = os.path.join(build_to_root, value)
+      if cc.endswith('clang-cl'):
+        clang_cl = cc
+    if key == 'CXX':
+      cxx = os.path.join(build_to_root, value)
+    if key == 'CC.host':
+      cc_host = os.path.join(build_to_root, value)
+      cc_host_global_setting = value
+    if key == 'CXX.host':
+      cxx_host = os.path.join(build_to_root, value)
+      cxx_host_global_setting = value
+    if key == 'LD':
+      ld = os.path.join(build_to_root, value)
+    if key == 'LD.host':
+      ld_host = os.path.join(build_to_root, value)
+    if key.endswith('_wrapper'):
+      wrappers[key[:-len('_wrapper')]] = os.path.join(build_to_root, value)
+
+  # Support wrappers from environment variables too.
+  for key, value in os.environ.iteritems():
+    if key.lower().endswith('_wrapper'):
+      key_prefix = key[:-len('_wrapper')]
+      key_prefix = re.sub(r'\.HOST$', '.host', key_prefix)
+      wrappers[key_prefix] = os.path.join(build_to_root, value)
+
+  if flavor == 'win':
+    configs = [target_dicts[qualified_target]['configurations'][config_name]
+               for qualified_target in target_list]
+    shared_system_includes = None
+    if not generator_flags.get('ninja_use_custom_environment_files', 0):
+      shared_system_includes = \
+          gyp.msvs_emulation.ExtractSharedMSVSSystemIncludes(
+              configs, generator_flags)
+    cl_paths = gyp.msvs_emulation.GenerateEnvironmentFiles(
+        toplevel_build, generator_flags, shared_system_includes, OpenOutput)
+    for arch, path in cl_paths.iteritems():
+      if clang_cl:
+        # If we have selected clang-cl, use that instead.
+        path = clang_cl
+      command = CommandWithWrapper('CC', wrappers,
+          QuoteShellArgument(path, 'win'))
+      if clang_cl:
+        # Use clang-cl to cross-compile for x86 or x86_64.
+        command += (' -m32' if arch == 'x86' else ' -m64')
+      master_ninja.variable('cl_' + arch, command)
+
+  cc = GetEnvironFallback(['CC_target', 'CC'], cc)
+  master_ninja.variable('cc', CommandWithWrapper('CC', wrappers, cc))
+  cxx = GetEnvironFallback(['CXX_target', 'CXX'], cxx)
+  master_ninja.variable('cxx', CommandWithWrapper('CXX', wrappers, cxx))
+
+  if flavor == 'win':
+    master_ninja.variable('ld', ld)
+    master_ninja.variable('idl', 'midl.exe')
+    master_ninja.variable('ar', ar)
+    master_ninja.variable('rc', 'rc.exe')
+    master_ninja.variable('asm', 'ml.exe')
+    master_ninja.variable('mt', 'mt.exe')
+  else:
+    master_ninja.variable('ld', CommandWithWrapper('LINK', wrappers, ld))
+    master_ninja.variable('ldxx', CommandWithWrapper('LINK', wrappers, ldxx))
+    master_ninja.variable('ar', GetEnvironFallback(['AR_target', 'AR'], ar))
+
+  if generator_supports_multiple_toolsets:
+    if not cc_host:
+      cc_host = cc
+    if not cxx_host:
+      cxx_host = cxx
+
+    master_ninja.variable('ar_host', GetEnvironFallback(['AR_host'], ar_host))
+    cc_host = GetEnvironFallback(['CC_host'], cc_host)
+    cxx_host = GetEnvironFallback(['CXX_host'], cxx_host)
+
+    # The environment variable could be used in 'make_global_settings', like
+    # ['CC.host', '$(CC)'] or ['CXX.host', '$(CXX)'], transform them here.
+    if '$(CC)' in cc_host and cc_host_global_setting:
+      cc_host = cc_host_global_setting.replace('$(CC)', cc)
+    if '$(CXX)' in cxx_host and cxx_host_global_setting:
+      cxx_host = cxx_host_global_setting.replace('$(CXX)', cxx)
+    master_ninja.variable('cc_host',
+                          CommandWithWrapper('CC.host', wrappers, cc_host))
+    master_ninja.variable('cxx_host',
+                          CommandWithWrapper('CXX.host', wrappers, cxx_host))
+    if flavor == 'win':
+      master_ninja.variable('ld_host', ld_host)
+    else:
+      master_ninja.variable('ld_host', CommandWithWrapper(
+          'LINK', wrappers, ld_host))
+      master_ninja.variable('ldxx_host', CommandWithWrapper(
+          'LINK', wrappers, ldxx_host))
+
+  master_ninja.newline()
+
+  master_ninja.pool('link_pool', depth=GetDefaultConcurrentLinks())
+  master_ninja.newline()
+
+  deps = 'msvc' if flavor == 'win' else 'gcc'
+
+  if flavor != 'win':
+    master_ninja.rule(
+      'cc',
+      description='CC $out',
+      command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_c '
+              '$cflags_pch_c -c $in -o $out'),
+      depfile='$out.d',
+      deps=deps)
+    master_ninja.rule(
+      'cc_s',
+      description='CC $out',
+      command=('$cc $defines $includes $cflags $cflags_c '
+              '$cflags_pch_c -c $in -o $out'))
+    master_ninja.rule(
+      'cxx',
+      description='CXX $out',
+      command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc '
+              '$cflags_pch_cc -c $in -o $out'),
+      depfile='$out.d',
+      deps=deps)
+  else:
+    # TODO(scottmg) Separate pdb names is a test to see if it works around
+    # http://crbug.com/142362. It seems there's a race between the creation of
+    # the .pdb by the precompiled header step for .cc and the compilation of
+    # .c files. This should be handled by mspdbsrv, but rarely errors out with
+    #   c1xx : fatal error C1033: cannot open program database
+    # By making the rules target separate pdb files this might be avoided.
+    cc_command = ('ninja -t msvc -e $arch ' +
+                  '-- '
+                  '$cc /nologo /showIncludes /FC '
+                  '@$out.rsp /c $in /Fo$out /Fd$pdbname_c ')
+    cxx_command = ('ninja -t msvc -e $arch ' +
+                   '-- '
+                   '$cxx /nologo /showIncludes /FC '
+                   '@$out.rsp /c $in /Fo$out /Fd$pdbname_cc ')
+    master_ninja.rule(
+      'cc',
+      description='CC $out',
+      command=cc_command,
+      rspfile='$out.rsp',
+      rspfile_content='$defines $includes $cflags $cflags_c',
+      deps=deps)
+    master_ninja.rule(
+      'cxx',
+      description='CXX $out',
+      command=cxx_command,
+      rspfile='$out.rsp',
+      rspfile_content='$defines $includes $cflags $cflags_cc',
+      deps=deps)
+    master_ninja.rule(
+      'idl',
+      description='IDL $in',
+      command=('%s gyp-win-tool midl-wrapper $arch $outdir '
+               '$tlb $h $dlldata $iid $proxy $in '
+               '$idlflags' % sys.executable))
+    master_ninja.rule(
+      'rc',
+      description='RC $in',
+      # Note: $in must be last otherwise rc.exe complains.
+      command=('%s gyp-win-tool rc-wrapper '
+               '$arch $rc $defines $resource_includes $rcflags /fo$out $in' %
+               sys.executable))
+    master_ninja.rule(
+      'asm',
+      description='ASM $out',
+      command=('%s gyp-win-tool asm-wrapper '
+               '$arch $asm $defines $includes $asmflags /c /Fo $out $in' %
+               sys.executable))
+
+  if flavor != 'mac' and flavor != 'win':
+    master_ninja.rule(
+      'alink',
+      description='AR $out',
+      command='rm -f $out && $ar rcs $out $in')
+    master_ninja.rule(
+      'alink_thin',
+      description='AR $out',
+      command='rm -f $out && $ar rcsT $out $in')
+
+    # This allows targets that only need to depend on $lib's API to declare an
+    # order-only dependency on $lib.TOC and avoid relinking such downstream
+    # dependencies when $lib changes only in non-public ways.
+    # The resulting string leaves an uninterpolated %{suffix} which
+    # is used in the final substitution below.
+    mtime_preserving_solink_base = (
+        'if [ ! -e $lib -o ! -e $lib.TOC ]; then '
+        '%(solink)s && %(extract_toc)s > $lib.TOC; else '
+        '%(solink)s && %(extract_toc)s > $lib.tmp && '
+        'if ! cmp -s $lib.tmp $lib.TOC; then mv $lib.tmp $lib.TOC ; '
+        'fi; fi'
+        % { 'solink':
+              '$ld -shared $ldflags -o $lib -Wl,-soname=$soname %(suffix)s',
+            'extract_toc':
+              ('{ readelf -d $lib | grep SONAME ; '
+               'nm -gD -f p $lib | cut -f1-2 -d\' \'; }')})
+
+    master_ninja.rule(
+      'solink',
+      description='SOLINK $lib',
+      restat=True,
+      command=mtime_preserving_solink_base % {'suffix': '@$link_file_list'},
+      rspfile='$link_file_list',
+      rspfile_content=
+          '-Wl,--whole-archive $in $solibs -Wl,--no-whole-archive $libs',
+      pool='link_pool')
+    master_ninja.rule(
+      'solink_module',
+      description='SOLINK(module) $lib',
+      restat=True,
+      command=mtime_preserving_solink_base % {'suffix': '@$link_file_list'},
+      rspfile='$link_file_list',
+      rspfile_content='-Wl,--start-group $in -Wl,--end-group $solibs $libs',
+      pool='link_pool')
+    master_ninja.rule(
+      'link',
+      description='LINK $out',
+      command=('$ld $ldflags -o $out '
+               '-Wl,--start-group $in -Wl,--end-group $solibs $libs'),
+      pool='link_pool')
+  elif flavor == 'win':
+    master_ninja.rule(
+        'alink',
+        description='LIB $out',
+        command=('%s gyp-win-tool link-wrapper $arch False '
+                 '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' %
+                 sys.executable),
+        rspfile='$out.rsp',
+        rspfile_content='$in_newline $libflags')
+    _AddWinLinkRules(master_ninja, embed_manifest=True)
+    _AddWinLinkRules(master_ninja, embed_manifest=False)
+  else:
+    master_ninja.rule(
+      'objc',
+      description='OBJC $out',
+      command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_objc '
+               '$cflags_pch_objc -c $in -o $out'),
+      depfile='$out.d',
+      deps=deps)
+    master_ninja.rule(
+      'objcxx',
+      description='OBJCXX $out',
+      command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_objcc '
+               '$cflags_pch_objcc -c $in -o $out'),
+      depfile='$out.d',
+      deps=deps)
+    master_ninja.rule(
+      'alink',
+      description='LIBTOOL-STATIC $out, POSTBUILDS',
+      command='rm -f $out && '
+              './gyp-mac-tool filter-libtool libtool $libtool_flags '
+              '-static -o $out $in'
+              '$postbuilds')
+    master_ninja.rule(
+      'lipo',
+      description='LIPO $out, POSTBUILDS',
+      command='rm -f $out && lipo -create $in -output $out$postbuilds')
+
+    # Record the public interface of $lib in $lib.TOC. See the corresponding
+    # comment in the posix section above for details.
+    solink_base = '$ld %(type)s $ldflags -o $lib %(suffix)s'
+    mtime_preserving_solink_base = (
+        'if [ ! -e $lib -o ! -e $lib.TOC ] || '
+             # Always force dependent targets to relink if this library
+             # reexports something. Handling this correctly would require
+             # recursive TOC dumping but this is rare in practice, so punt.
+             'otool -l $lib | grep -q LC_REEXPORT_DYLIB ; then '
+          '%(solink)s && %(extract_toc)s > $lib.TOC; '
+        'else '
+          '%(solink)s && %(extract_toc)s > $lib.tmp && '
+          'if ! cmp -s $lib.tmp $lib.TOC; then '
+            'mv $lib.tmp $lib.TOC ; '
+          'fi; '
+        'fi'
+        % { 'solink': solink_base,
+            'extract_toc':
+              '{ otool -l $lib | grep LC_ID_DYLIB -A 5; '
+              'nm -gP $lib | cut -f1-2 -d\' \' | grep -v U$$; true; }'})
+
+
+    solink_suffix = '@$link_file_list$postbuilds'
+    master_ninja.rule(
+      'solink',
+      description='SOLINK $lib, POSTBUILDS',
+      restat=True,
+      command=mtime_preserving_solink_base % {'suffix': solink_suffix,
+                                              'type': '-shared'},
+      rspfile='$link_file_list',
+      rspfile_content='$in $solibs $libs',
+      pool='link_pool')
+    master_ninja.rule(
+      'solink_notoc',
+      description='SOLINK $lib, POSTBUILDS',
+      restat=True,
+      command=solink_base % {'suffix':solink_suffix, 'type': '-shared'},
+      rspfile='$link_file_list',
+      rspfile_content='$in $solibs $libs',
+      pool='link_pool')
+
+    master_ninja.rule(
+      'solink_module',
+      description='SOLINK(module) $lib, POSTBUILDS',
+      restat=True,
+      command=mtime_preserving_solink_base % {'suffix': solink_suffix,
+                                              'type': '-bundle'},
+      rspfile='$link_file_list',
+      rspfile_content='$in $solibs $libs',
+      pool='link_pool')
+    master_ninja.rule(
+      'solink_module_notoc',
+      description='SOLINK(module) $lib, POSTBUILDS',
+      restat=True,
+      command=solink_base % {'suffix': solink_suffix, 'type': '-bundle'},
+      rspfile='$link_file_list',
+      rspfile_content='$in $solibs $libs',
+      pool='link_pool')
+
+    master_ninja.rule(
+      'link',
+      description='LINK $out, POSTBUILDS',
+      command=('$ld $ldflags -o $out '
+               '$in $solibs $libs$postbuilds'),
+      pool='link_pool')
+    master_ninja.rule(
+      'preprocess_infoplist',
+      description='PREPROCESS INFOPLIST $out',
+      command=('$cc -E -P -Wno-trigraphs -x c $defines $in -o $out && '
+               'plutil -convert xml1 $out $out'))
+    master_ninja.rule(
+      'copy_infoplist',
+      description='COPY INFOPLIST $in',
+      command='$env ./gyp-mac-tool copy-info-plist $in $out $keys')
+    master_ninja.rule(
+      'mac_tool',
+      description='MACTOOL $mactool_cmd $in',
+      command='$env ./gyp-mac-tool $mactool_cmd $in $out')
+    master_ninja.rule(
+      'package_framework',
+      description='PACKAGE FRAMEWORK $out, POSTBUILDS',
+      command='./gyp-mac-tool package-framework $out $version$postbuilds '
+              '&& touch $out')
+  if flavor == 'win':
+    master_ninja.rule(
+      'stamp',
+      description='STAMP $out',
+      command='%s gyp-win-tool stamp $out' % sys.executable)
+    master_ninja.rule(
+      'copy',
+      description='COPY $in $out',
+      command='%s gyp-win-tool recursive-mirror $in $out' % sys.executable)
+  else:
+    master_ninja.rule(
+      'stamp',
+      description='STAMP $out',
+      command='${postbuilds}touch $out')
+    master_ninja.rule(
+      'copy',
+      description='COPY $in $out',
+      command='ln -f $in $out 2>/dev/null || (rm -rf $out && cp -af $in $out)')
+  master_ninja.newline()
+
+  all_targets = set()
+  for build_file in params['build_files']:
+    for target in gyp.common.AllTargets(target_list,
+                                        target_dicts,
+                                        os.path.normpath(build_file)):
+      all_targets.add(target)
+  all_outputs = set()
+
+  # target_outputs is a map from qualified target name to a Target object.
+  target_outputs = {}
+  # target_short_names is a map from target short name to a list of Target
+  # objects.
+  target_short_names = {}
+
+  for qualified_target in target_list:
+    # qualified_target is like: third_party/icu/icu.gyp:icui18n#target
+    build_file, name, toolset = \
+        gyp.common.ParseQualifiedTarget(qualified_target)
+
+    this_make_global_settings = data[build_file].get('make_global_settings', [])
+    assert make_global_settings == this_make_global_settings, (
+        "make_global_settings needs to be the same for all targets. %s vs. %s" %
+        (this_make_global_settings, make_global_settings))
+
+    spec = target_dicts[qualified_target]
+    if flavor == 'mac':
+      gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec)
+
+    build_file = gyp.common.RelativePath(build_file, options.toplevel_dir)
+
+    base_path = os.path.dirname(build_file)
+    obj = 'obj'
+    if toolset != 'target':
+      obj += '.' + toolset
+    output_file = os.path.join(obj, base_path, name + '.ninja')
+
+    ninja_output = StringIO()
+    writer = NinjaWriter(qualified_target, target_outputs, base_path, build_dir,
+                         ninja_output,
+                         toplevel_build, output_file,
+                         flavor, toplevel_dir=options.toplevel_dir)
+
+    target = writer.WriteSpec(spec, config_name, generator_flags)
+
+    if ninja_output.tell() > 0:
+      # Only create files for ninja files that actually have contents.
+      with OpenOutput(os.path.join(toplevel_build, output_file)) as ninja_file:
+        ninja_file.write(ninja_output.getvalue())
+      ninja_output.close()
+      master_ninja.subninja(output_file)
+
+    if target:
+      if name != target.FinalOutput() and spec['toolset'] == 'target':
+        target_short_names.setdefault(name, []).append(target)
+      target_outputs[qualified_target] = target
+      if qualified_target in all_targets:
+        all_outputs.add(target.FinalOutput())
+
+  if target_short_names:
+    # Write a short name to build this target.  This benefits both the
+    # "build chrome" case as well as the gyp tests, which expect to be
+    # able to run actions and build libraries by their short name.
+    master_ninja.newline()
+    master_ninja.comment('Short names for targets.')
+    for short_name in target_short_names:
+      master_ninja.build(short_name, 'phony', [x.FinalOutput() for x in
+                                               target_short_names[short_name]])
+
+  if all_outputs:
+    master_ninja.newline()
+    master_ninja.build('all', 'phony', list(all_outputs))
+    master_ninja.default(generator_flags.get('default_target', 'all'))
+
+  master_ninja_file.close()
+
+
+def PerformBuild(data, configurations, params):
+  options = params['options']
+  for config in configurations:
+    builddir = os.path.join(options.toplevel_dir, 'out', config)
+    arguments = ['ninja', '-C', builddir]
+    print 'Building [%s]: %s' % (config, arguments)
+    subprocess.check_call(arguments)
+
+
+def CallGenerateOutputForConfig(arglist):
+  # Ignore the interrupt signal so that the parent process catches it and
+  # kills all multiprocessing children.
+  signal.signal(signal.SIGINT, signal.SIG_IGN)
+
+  (target_list, target_dicts, data, params, config_name) = arglist
+  GenerateOutputForConfig(target_list, target_dicts, data, params, config_name)
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  # Update target_dicts for iOS device builds.
+  target_dicts = gyp.xcode_emulation.CloneConfigurationForDeviceAndEmulator(
+      target_dicts)
+
+  user_config = params.get('generator_flags', {}).get('config', None)
+  if gyp.common.GetFlavor(params) == 'win':
+    target_list, target_dicts = MSVSUtil.ShardTargets(target_list, target_dicts)
+    target_list, target_dicts = MSVSUtil.InsertLargePdbShims(
+        target_list, target_dicts, generator_default_variables)
+
+  if user_config:
+    GenerateOutputForConfig(target_list, target_dicts, data, params,
+                            user_config)
+  else:
+    config_names = target_dicts[target_list[0]]['configurations'].keys()
+    if params['parallel']:
+      try:
+        pool = multiprocessing.Pool(len(config_names))
+        arglists = []
+        for config_name in config_names:
+          arglists.append(
+              (target_list, target_dicts, data, params, config_name))
+        pool.map(CallGenerateOutputForConfig, arglists)
+      except KeyboardInterrupt, e:
+        pool.terminate()
+        raise e
+    else:
+      for config_name in config_names:
+        GenerateOutputForConfig(target_list, target_dicts, data, params,
+                                config_name)
diff --git a/gyp/pylib/gyp/generator/ninja_test.py b/gyp/pylib/gyp/generator/ninja_test.py
new file mode 100644 (file)
index 0000000..52661bc
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Unit tests for the ninja.py file. """
+
+import gyp.generator.ninja as ninja
+import unittest
+import StringIO
+import sys
+import TestCommon
+
+
+class TestPrefixesAndSuffixes(unittest.TestCase):
+  def test_BinaryNamesWindows(self):
+    writer = ninja.NinjaWriter('foo', 'wee', '.', '.', 'build.ninja', '.',
+        'build.ninja', 'win')
+    spec = { 'target_name': 'wee' }
+    self.assertTrue(writer.ComputeOutputFileName(spec, 'executable').
+        endswith('.exe'))
+    self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library').
+        endswith('.dll'))
+    self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library').
+        endswith('.lib'))
+
+  def test_BinaryNamesLinux(self):
+    writer = ninja.NinjaWriter('foo', 'wee', '.', '.', 'build.ninja', '.',
+        'build.ninja', 'linux')
+    spec = { 'target_name': 'wee' }
+    self.assertTrue('.' not in writer.ComputeOutputFileName(spec,
+                                                            'executable'))
+    self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library').
+        startswith('lib'))
+    self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library').
+        startswith('lib'))
+    self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library').
+        endswith('.so'))
+    self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library').
+        endswith('.a'))
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/gyp/pylib/gyp/generator/xcode.py b/gyp/pylib/gyp/generator/xcode.py
new file mode 100644 (file)
index 0000000..b4d1e19
--- /dev/null
@@ -0,0 +1,1243 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import filecmp
+import gyp.common
+import gyp.xcodeproj_file
+import gyp.xcode_ninja
+import errno
+import os
+import sys
+import posixpath
+import re
+import shutil
+import subprocess
+import tempfile
+
+
+# Project files generated by this module will use _intermediate_var as a
+# custom Xcode setting whose value is a DerivedSources-like directory that's
+# project-specific and configuration-specific.  The normal choice,
+# DERIVED_FILE_DIR, is target-specific, which is thought to be too restrictive
+# as it is likely that multiple targets within a single project file will want
+# to access the same set of generated files.  The other option,
+# PROJECT_DERIVED_FILE_DIR, is unsuitable because while it is project-specific,
+# it is not configuration-specific.  INTERMEDIATE_DIR is defined as
+# $(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION).
+_intermediate_var = 'INTERMEDIATE_DIR'
+
+# SHARED_INTERMEDIATE_DIR is the same, except that it is shared among all
+# targets that share the same BUILT_PRODUCTS_DIR.
+_shared_intermediate_var = 'SHARED_INTERMEDIATE_DIR'
+
+_library_search_paths_var = 'LIBRARY_SEARCH_PATHS'
+
+generator_default_variables = {
+  'EXECUTABLE_PREFIX': '',
+  'EXECUTABLE_SUFFIX': '',
+  'STATIC_LIB_PREFIX': 'lib',
+  'SHARED_LIB_PREFIX': 'lib',
+  'STATIC_LIB_SUFFIX': '.a',
+  'SHARED_LIB_SUFFIX': '.dylib',
+  # INTERMEDIATE_DIR is a place for targets to build up intermediate products.
+  # It is specific to each build environment.  It is only guaranteed to exist
+  # and be constant within the context of a project, corresponding to a single
+  # input file.  Some build environments may allow their intermediate directory
+  # to be shared on a wider scale, but this is not guaranteed.
+  'INTERMEDIATE_DIR': '$(%s)' % _intermediate_var,
+  'OS': 'mac',
+  'PRODUCT_DIR': '$(BUILT_PRODUCTS_DIR)',
+  'LIB_DIR': '$(BUILT_PRODUCTS_DIR)',
+  'RULE_INPUT_ROOT': '$(INPUT_FILE_BASE)',
+  'RULE_INPUT_EXT': '$(INPUT_FILE_SUFFIX)',
+  'RULE_INPUT_NAME': '$(INPUT_FILE_NAME)',
+  'RULE_INPUT_PATH': '$(INPUT_FILE_PATH)',
+  'RULE_INPUT_DIRNAME': '$(INPUT_FILE_DIRNAME)',
+  'SHARED_INTERMEDIATE_DIR': '$(%s)' % _shared_intermediate_var,
+  'CONFIGURATION_NAME': '$(CONFIGURATION)',
+}
+
+# The Xcode-specific sections that hold paths.
+generator_additional_path_sections = [
+  'mac_bundle_resources',
+  'mac_framework_headers',
+  'mac_framework_private_headers',
+  # 'mac_framework_dirs', input already handles _dirs endings.
+]
+
+# The Xcode-specific keys that exist on targets and aren't moved down to
+# configurations.
+generator_additional_non_configuration_keys = [
+  'ios_app_extension',
+  'mac_bundle',
+  'mac_bundle_resources',
+  'mac_framework_headers',
+  'mac_framework_private_headers',
+  'mac_xctest_bundle',
+  'xcode_create_dependents_test_runner',
+]
+
+# We want to let any rules apply to files that are resources also.
+generator_extra_sources_for_rules = [
+  'mac_bundle_resources',
+  'mac_framework_headers',
+  'mac_framework_private_headers',
+]
+
+# Xcode's standard set of library directories, which don't need to be duplicated
+# in LIBRARY_SEARCH_PATHS. This list is not exhaustive, but that's okay.
+xcode_standard_library_dirs = frozenset([
+  '$(SDKROOT)/usr/lib',
+  '$(SDKROOT)/usr/local/lib',
+])
+
+def CreateXCConfigurationList(configuration_names):
+  xccl = gyp.xcodeproj_file.XCConfigurationList({'buildConfigurations': []})
+  if len(configuration_names) == 0:
+    configuration_names = ['Default']
+  for configuration_name in configuration_names:
+    xcbc = gyp.xcodeproj_file.XCBuildConfiguration({
+        'name': configuration_name})
+    xccl.AppendProperty('buildConfigurations', xcbc)
+  xccl.SetProperty('defaultConfigurationName', configuration_names[0])
+  return xccl
+
+
+class XcodeProject(object):
+  def __init__(self, gyp_path, path, build_file_dict):
+    self.gyp_path = gyp_path
+    self.path = path
+    self.project = gyp.xcodeproj_file.PBXProject(path=path)
+    projectDirPath = gyp.common.RelativePath(
+                         os.path.dirname(os.path.abspath(self.gyp_path)),
+                         os.path.dirname(path) or '.')
+    self.project.SetProperty('projectDirPath', projectDirPath)
+    self.project_file = \
+        gyp.xcodeproj_file.XCProjectFile({'rootObject': self.project})
+    self.build_file_dict = build_file_dict
+
+    # TODO(mark): add destructor that cleans up self.path if created_dir is
+    # True and things didn't complete successfully.  Or do something even
+    # better with "try"?
+    self.created_dir = False
+    try:
+      os.makedirs(self.path)
+      self.created_dir = True
+    except OSError, e:
+      if e.errno != errno.EEXIST:
+        raise
+
+  def Finalize1(self, xcode_targets, serialize_all_tests):
+    # Collect a list of all of the build configuration names used by the
+    # various targets in the file.  It is very heavily advised to keep each
+    # target in an entire project (even across multiple project files) using
+    # the same set of configuration names.
+    configurations = []
+    for xct in self.project.GetProperty('targets'):
+      xccl = xct.GetProperty('buildConfigurationList')
+      xcbcs = xccl.GetProperty('buildConfigurations')
+      for xcbc in xcbcs:
+        name = xcbc.GetProperty('name')
+        if name not in configurations:
+          configurations.append(name)
+
+    # Replace the XCConfigurationList attached to the PBXProject object with
+    # a new one specifying all of the configuration names used by the various
+    # targets.
+    try:
+      xccl = CreateXCConfigurationList(configurations)
+      self.project.SetProperty('buildConfigurationList', xccl)
+    except:
+      sys.stderr.write("Problem with gyp file %s\n" % self.gyp_path)
+      raise
+
+    # The need for this setting is explained above where _intermediate_var is
+    # defined.  The comments below about wanting to avoid project-wide build
+    # settings apply here too, but this needs to be set on a project-wide basis
+    # so that files relative to the _intermediate_var setting can be displayed
+    # properly in the Xcode UI.
+    #
+    # Note that for configuration-relative files such as anything relative to
+    # _intermediate_var, for the purposes of UI tree view display, Xcode will
+    # only resolve the configuration name once, when the project file is
+    # opened.  If the active build configuration is changed, the project file
+    # must be closed and reopened if it is desired for the tree view to update.
+    # This is filed as Apple radar 6588391.
+    xccl.SetBuildSetting(_intermediate_var,
+                         '$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)')
+    xccl.SetBuildSetting(_shared_intermediate_var,
+                         '$(SYMROOT)/DerivedSources/$(CONFIGURATION)')
+
+    # Set user-specified project-wide build settings and config files.  This
+    # is intended to be used very sparingly.  Really, almost everything should
+    # go into target-specific build settings sections.  The project-wide
+    # settings are only intended to be used in cases where Xcode attempts to
+    # resolve variable references in a project context as opposed to a target
+    # context, such as when resolving sourceTree references while building up
+    # the tree tree view for UI display.
+    # Any values set globally are applied to all configurations, then any
+    # per-configuration values are applied.
+    for xck, xcv in self.build_file_dict.get('xcode_settings', {}).iteritems():
+      xccl.SetBuildSetting(xck, xcv)
+    if 'xcode_config_file' in self.build_file_dict:
+      config_ref = self.project.AddOrGetFileInRootGroup(
+          self.build_file_dict['xcode_config_file'])
+      xccl.SetBaseConfiguration(config_ref)
+    build_file_configurations = self.build_file_dict.get('configurations', {})
+    if build_file_configurations:
+      for config_name in configurations:
+        build_file_configuration_named = \
+            build_file_configurations.get(config_name, {})
+        if build_file_configuration_named:
+          xcc = xccl.ConfigurationNamed(config_name)
+          for xck, xcv in build_file_configuration_named.get('xcode_settings',
+                                                             {}).iteritems():
+            xcc.SetBuildSetting(xck, xcv)
+          if 'xcode_config_file' in build_file_configuration_named:
+            config_ref = self.project.AddOrGetFileInRootGroup(
+                build_file_configurations[config_name]['xcode_config_file'])
+            xcc.SetBaseConfiguration(config_ref)
+
+    # Sort the targets based on how they appeared in the input.
+    # TODO(mark): Like a lot of other things here, this assumes internal
+    # knowledge of PBXProject - in this case, of its "targets" property.
+
+    # ordinary_targets are ordinary targets that are already in the project
+    # file. run_test_targets are the targets that run unittests and should be
+    # used for the Run All Tests target.  support_targets are the action/rule
+    # targets used by GYP file targets, just kept for the assert check.
+    ordinary_targets = []
+    run_test_targets = []
+    support_targets = []
+
+    # targets is full list of targets in the project.
+    targets = []
+
+    # does the it define it's own "all"?
+    has_custom_all = False
+
+    # targets_for_all is the list of ordinary_targets that should be listed
+    # in this project's "All" target.  It includes each non_runtest_target
+    # that does not have suppress_wildcard set.
+    targets_for_all = []
+
+    for target in self.build_file_dict['targets']:
+      target_name = target['target_name']
+      toolset = target['toolset']
+      qualified_target = gyp.common.QualifiedTarget(self.gyp_path, target_name,
+                                                    toolset)
+      xcode_target = xcode_targets[qualified_target]
+      # Make sure that the target being added to the sorted list is already in
+      # the unsorted list.
+      assert xcode_target in self.project._properties['targets']
+      targets.append(xcode_target)
+      ordinary_targets.append(xcode_target)
+      if xcode_target.support_target:
+        support_targets.append(xcode_target.support_target)
+        targets.append(xcode_target.support_target)
+
+      if not int(target.get('suppress_wildcard', False)):
+        targets_for_all.append(xcode_target)
+
+      if target_name.lower() == 'all':
+        has_custom_all = True;
+
+      # If this target has a 'run_as' attribute, add its target to the
+      # targets, and add it to the test targets.
+      if target.get('run_as'):
+        # Make a target to run something.  It should have one
+        # dependency, the parent xcode target.
+        xccl = CreateXCConfigurationList(configurations)
+        run_target = gyp.xcodeproj_file.PBXAggregateTarget({
+              'name':                   'Run ' + target_name,
+              'productName':            xcode_target.GetProperty('productName'),
+              'buildConfigurationList': xccl,
+            },
+            parent=self.project)
+        run_target.AddDependency(xcode_target)
+
+        command = target['run_as']
+        script = ''
+        if command.get('working_directory'):
+          script = script + 'cd "%s"\n' % \
+                   gyp.xcodeproj_file.ConvertVariablesToShellSyntax(
+                       command.get('working_directory'))
+
+        if command.get('environment'):
+          script = script + "\n".join(
+            ['export %s="%s"' %
+             (key, gyp.xcodeproj_file.ConvertVariablesToShellSyntax(val))
+             for (key, val) in command.get('environment').iteritems()]) + "\n"
+
+        # Some test end up using sockets, files on disk, etc. and can get
+        # confused if more then one test runs at a time.  The generator
+        # flag 'xcode_serialize_all_test_runs' controls the forcing of all
+        # tests serially.  It defaults to True.  To get serial runs this
+        # little bit of python does the same as the linux flock utility to
+        # make sure only one runs at a time.
+        command_prefix = ''
+        if serialize_all_tests:
+          command_prefix = \
+"""python -c "import fcntl, subprocess, sys
+file = open('$TMPDIR/GYP_serialize_test_runs', 'a')
+fcntl.flock(file.fileno(), fcntl.LOCK_EX)
+sys.exit(subprocess.call(sys.argv[1:]))" """
+
+        # If we were unable to exec for some reason, we want to exit
+        # with an error, and fixup variable references to be shell
+        # syntax instead of xcode syntax.
+        script = script + 'exec ' + command_prefix + '%s\nexit 1\n' % \
+                 gyp.xcodeproj_file.ConvertVariablesToShellSyntax(
+                     gyp.common.EncodePOSIXShellList(command.get('action')))
+
+        ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({
+              'shellScript':      script,
+              'showEnvVarsInLog': 0,
+            })
+        run_target.AppendProperty('buildPhases', ssbp)
+
+        # Add the run target to the project file.
+        targets.append(run_target)
+        run_test_targets.append(run_target)
+        xcode_target.test_runner = run_target
+
+
+    # Make sure that the list of targets being replaced is the same length as
+    # the one replacing it, but allow for the added test runner targets.
+    assert len(self.project._properties['targets']) == \
+      len(ordinary_targets) + len(support_targets)
+
+    self.project._properties['targets'] = targets
+
+    # Get rid of unnecessary levels of depth in groups like the Source group.
+    self.project.RootGroupsTakeOverOnlyChildren(True)
+
+    # Sort the groups nicely.  Do this after sorting the targets, because the
+    # Products group is sorted based on the order of the targets.
+    self.project.SortGroups()
+
+    # Create an "All" target if there's more than one target in this project
+    # file and the project didn't define its own "All" target.  Put a generated
+    # "All" target first so that people opening up the project for the first
+    # time will build everything by default.
+    if len(targets_for_all) > 1 and not has_custom_all:
+      xccl = CreateXCConfigurationList(configurations)
+      all_target = gyp.xcodeproj_file.PBXAggregateTarget(
+          {
+            'buildConfigurationList': xccl,
+            'name':                   'All',
+          },
+          parent=self.project)
+
+      for target in targets_for_all:
+        all_target.AddDependency(target)
+
+      # TODO(mark): This is evil because it relies on internal knowledge of
+      # PBXProject._properties.  It's important to get the "All" target first,
+      # though.
+      self.project._properties['targets'].insert(0, all_target)
+
+    # The same, but for run_test_targets.
+    if len(run_test_targets) > 1:
+      xccl = CreateXCConfigurationList(configurations)
+      run_all_tests_target = gyp.xcodeproj_file.PBXAggregateTarget(
+          {
+            'buildConfigurationList': xccl,
+            'name':                   'Run All Tests',
+          },
+          parent=self.project)
+      for run_test_target in run_test_targets:
+        run_all_tests_target.AddDependency(run_test_target)
+
+      # Insert after the "All" target, which must exist if there is more than
+      # one run_test_target.
+      self.project._properties['targets'].insert(1, run_all_tests_target)
+
+  def Finalize2(self, xcode_targets, xcode_target_to_target_dict):
+    # Finalize2 needs to happen in a separate step because the process of
+    # updating references to other projects depends on the ordering of targets
+    # within remote project files.  Finalize1 is responsible for sorting duty,
+    # and once all project files are sorted, Finalize2 can come in and update
+    # these references.
+
+    # To support making a "test runner" target that will run all the tests
+    # that are direct dependents of any given target, we look for
+    # xcode_create_dependents_test_runner being set on an Aggregate target,
+    # and generate a second target that will run the tests runners found under
+    # the marked target.
+    for bf_tgt in self.build_file_dict['targets']:
+      if int(bf_tgt.get('xcode_create_dependents_test_runner', 0)):
+        tgt_name = bf_tgt['target_name']
+        toolset = bf_tgt['toolset']
+        qualified_target = gyp.common.QualifiedTarget(self.gyp_path,
+                                                      tgt_name, toolset)
+        xcode_target = xcode_targets[qualified_target]
+        if isinstance(xcode_target, gyp.xcodeproj_file.PBXAggregateTarget):
+          # Collect all the run test targets.
+          all_run_tests = []
+          pbxtds = xcode_target.GetProperty('dependencies')
+          for pbxtd in pbxtds:
+            pbxcip = pbxtd.GetProperty('targetProxy')
+            dependency_xct = pbxcip.GetProperty('remoteGlobalIDString')
+            if hasattr(dependency_xct, 'test_runner'):
+              all_run_tests.append(dependency_xct.test_runner)
+
+          # Directly depend on all the runners as they depend on the target
+          # that builds them.
+          if len(all_run_tests) > 0:
+            run_all_target = gyp.xcodeproj_file.PBXAggregateTarget({
+                  'name':        'Run %s Tests' % tgt_name,
+                  'productName': tgt_name,
+                },
+                parent=self.project)
+            for run_test_target in all_run_tests:
+              run_all_target.AddDependency(run_test_target)
+
+            # Insert the test runner after the related target.
+            idx = self.project._properties['targets'].index(xcode_target)
+            self.project._properties['targets'].insert(idx + 1, run_all_target)
+
+    # Update all references to other projects, to make sure that the lists of
+    # remote products are complete.  Otherwise, Xcode will fill them in when
+    # it opens the project file, which will result in unnecessary diffs.
+    # TODO(mark): This is evil because it relies on internal knowledge of
+    # PBXProject._other_pbxprojects.
+    for other_pbxproject in self.project._other_pbxprojects.keys():
+      self.project.AddOrGetProjectReference(other_pbxproject)
+
+    self.project.SortRemoteProductReferences()
+
+    # Give everything an ID.
+    self.project_file.ComputeIDs()
+
+    # Make sure that no two objects in the project file have the same ID.  If
+    # multiple objects wind up with the same ID, upon loading the file, Xcode
+    # will only recognize one object (the last one in the file?) and the
+    # results are unpredictable.
+    self.project_file.EnsureNoIDCollisions()
+
+  def Write(self):
+    # Write the project file to a temporary location first.  Xcode watches for
+    # changes to the project file and presents a UI sheet offering to reload
+    # the project when it does change.  However, in some cases, especially when
+    # multiple projects are open or when Xcode is busy, things don't work so
+    # seamlessly.  Sometimes, Xcode is able to detect that a project file has
+    # changed but can't unload it because something else is referencing it.
+    # To mitigate this problem, and to avoid even having Xcode present the UI
+    # sheet when an open project is rewritten for inconsequential changes, the
+    # project file is written to a temporary file in the xcodeproj directory
+    # first.  The new temporary file is then compared to the existing project
+    # file, if any.  If they differ, the new file replaces the old; otherwise,
+    # the new project file is simply deleted.  Xcode properly detects a file
+    # being renamed over an open project file as a change and so it remains
+    # able to present the "project file changed" sheet under this system.
+    # Writing to a temporary file first also avoids the possible problem of
+    # Xcode rereading an incomplete project file.
+    (output_fd, new_pbxproj_path) = \
+        tempfile.mkstemp(suffix='.tmp', prefix='project.pbxproj.gyp.',
+                         dir=self.path)
+
+    try:
+      output_file = os.fdopen(output_fd, 'wb')
+
+      self.project_file.Print(output_file)
+      output_file.close()
+
+      pbxproj_path = os.path.join(self.path, 'project.pbxproj')
+
+      same = False
+      try:
+        same = filecmp.cmp(pbxproj_path, new_pbxproj_path, False)
+      except OSError, e:
+        if e.errno != errno.ENOENT:
+          raise
+
+      if same:
+        # The new file is identical to the old one, just get rid of the new
+        # one.
+        os.unlink(new_pbxproj_path)
+      else:
+        # The new file is different from the old one, or there is no old one.
+        # Rename the new file to the permanent name.
+        #
+        # tempfile.mkstemp uses an overly restrictive mode, resulting in a
+        # file that can only be read by the owner, regardless of the umask.
+        # There's no reason to not respect the umask here, which means that
+        # an extra hoop is required to fetch it and reset the new file's mode.
+        #
+        # No way to get the umask without setting a new one?  Set a safe one
+        # and then set it back to the old value.
+        umask = os.umask(077)
+        os.umask(umask)
+
+        os.chmod(new_pbxproj_path, 0666 & ~umask)
+        os.rename(new_pbxproj_path, pbxproj_path)
+
+    except Exception:
+      # Don't leave turds behind.  In fact, if this code was responsible for
+      # creating the xcodeproj directory, get rid of that too.
+      os.unlink(new_pbxproj_path)
+      if self.created_dir:
+        shutil.rmtree(self.path, True)
+      raise
+
+
+def AddSourceToTarget(source, type, pbxp, xct):
+  # TODO(mark): Perhaps source_extensions and library_extensions can be made a
+  # little bit fancier.
+  source_extensions = ['c', 'cc', 'cpp', 'cxx', 'm', 'mm', 's']
+
+  # .o is conceptually more of a "source" than a "library," but Xcode thinks
+  # of "sources" as things to compile and "libraries" (or "frameworks") as
+  # things to link with. Adding an object file to an Xcode target's frameworks
+  # phase works properly.
+  library_extensions = ['a', 'dylib', 'framework', 'o']
+
+  basename = posixpath.basename(source)
+  (root, ext) = posixpath.splitext(basename)
+  if ext:
+    ext = ext[1:].lower()
+
+  if ext in source_extensions and type != 'none':
+    xct.SourcesPhase().AddFile(source)
+  elif ext in library_extensions and type != 'none':
+    xct.FrameworksPhase().AddFile(source)
+  else:
+    # Files that aren't added to a sources or frameworks build phase can still
+    # go into the project file, just not as part of a build phase.
+    pbxp.AddOrGetFileInRootGroup(source)
+
+
+def AddResourceToTarget(resource, pbxp, xct):
+  # TODO(mark): Combine with AddSourceToTarget above?  Or just inline this call
+  # where it's used.
+  xct.ResourcesPhase().AddFile(resource)
+
+
+def AddHeaderToTarget(header, pbxp, xct, is_public):
+  # TODO(mark): Combine with AddSourceToTarget above?  Or just inline this call
+  # where it's used.
+  settings = '{ATTRIBUTES = (%s, ); }' % ('Private', 'Public')[is_public]
+  xct.HeadersPhase().AddFile(header, settings)
+
+
+_xcode_variable_re = re.compile('(\$\((.*?)\))')
+def ExpandXcodeVariables(string, expansions):
+  """Expands Xcode-style $(VARIABLES) in string per the expansions dict.
+
+  In some rare cases, it is appropriate to expand Xcode variables when a
+  project file is generated.  For any substring $(VAR) in string, if VAR is a
+  key in the expansions dict, $(VAR) will be replaced with expansions[VAR].
+  Any $(VAR) substring in string for which VAR is not a key in the expansions
+  dict will remain in the returned string.
+  """
+
+  matches = _xcode_variable_re.findall(string)
+  if matches == None:
+    return string
+
+  matches.reverse()
+  for match in matches:
+    (to_replace, variable) = match
+    if not variable in expansions:
+      continue
+
+    replacement = expansions[variable]
+    string = re.sub(re.escape(to_replace), replacement, string)
+
+  return string
+
+
+_xcode_define_re = re.compile(r'([\\\"\' ])')
+def EscapeXcodeDefine(s):
+  """We must escape the defines that we give to XCode so that it knows not to
+     split on spaces and to respect backslash and quote literals. However, we
+     must not quote the define, or Xcode will incorrectly intepret variables
+     especially $(inherited)."""
+  return re.sub(_xcode_define_re, r'\\\1', s)
+
+
+def PerformBuild(data, configurations, params):
+  options = params['options']
+
+  for build_file, build_file_dict in data.iteritems():
+    (build_file_root, build_file_ext) = os.path.splitext(build_file)
+    if build_file_ext != '.gyp':
+      continue
+    xcodeproj_path = build_file_root + options.suffix + '.xcodeproj'
+    if options.generator_output:
+      xcodeproj_path = os.path.join(options.generator_output, xcodeproj_path)
+
+  for config in configurations:
+    arguments = ['xcodebuild', '-project', xcodeproj_path]
+    arguments += ['-configuration', config]
+    print "Building [%s]: %s" % (config, arguments)
+    subprocess.check_call(arguments)
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  # Optionally configure each spec to use ninja as the external builder.
+  ninja_wrapper = params.get('flavor') == 'ninja'
+  if ninja_wrapper:
+    (target_list, target_dicts, data) = \
+        gyp.xcode_ninja.CreateWrapper(target_list, target_dicts, data, params)
+
+  options = params['options']
+  generator_flags = params.get('generator_flags', {})
+  parallel_builds = generator_flags.get('xcode_parallel_builds', True)
+  serialize_all_tests = \
+      generator_flags.get('xcode_serialize_all_test_runs', True)
+  project_version = generator_flags.get('xcode_project_version', None)
+  skip_excluded_files = \
+      not generator_flags.get('xcode_list_excluded_files', True)
+  xcode_projects = {}
+  for build_file, build_file_dict in data.iteritems():
+    (build_file_root, build_file_ext) = os.path.splitext(build_file)
+    if build_file_ext != '.gyp':
+      continue
+    xcodeproj_path = build_file_root + options.suffix + '.xcodeproj'
+    if options.generator_output:
+      xcodeproj_path = os.path.join(options.generator_output, xcodeproj_path)
+    xcp = XcodeProject(build_file, xcodeproj_path, build_file_dict)
+    xcode_projects[build_file] = xcp
+    pbxp = xcp.project
+
+    if parallel_builds:
+      pbxp.SetProperty('attributes',
+                       {'BuildIndependentTargetsInParallel': 'YES'})
+    if project_version:
+      xcp.project_file.SetXcodeVersion(project_version)
+
+    # Add gyp/gypi files to project
+    if not generator_flags.get('standalone'):
+      main_group = pbxp.GetProperty('mainGroup')
+      build_group = gyp.xcodeproj_file.PBXGroup({'name': 'Build'})
+      main_group.AppendChild(build_group)
+      for included_file in build_file_dict['included_files']:
+        build_group.AddOrGetFileByPath(included_file, False)
+
+  xcode_targets = {}
+  xcode_target_to_target_dict = {}
+  for qualified_target in target_list:
+    [build_file, target_name, toolset] = \
+        gyp.common.ParseQualifiedTarget(qualified_target)
+
+    spec = target_dicts[qualified_target]
+    if spec['toolset'] != 'target':
+      raise Exception(
+          'Multiple toolsets not supported in xcode build (target %s)' %
+          qualified_target)
+    configuration_names = [spec['default_configuration']]
+    for configuration_name in sorted(spec['configurations'].keys()):
+      if configuration_name not in configuration_names:
+        configuration_names.append(configuration_name)
+    xcp = xcode_projects[build_file]
+    pbxp = xcp.project
+
+    # Set up the configurations for the target according to the list of names
+    # supplied.
+    xccl = CreateXCConfigurationList(configuration_names)
+
+    # Create an XCTarget subclass object for the target. The type with
+    # "+bundle" appended will be used if the target has "mac_bundle" set.
+    # loadable_modules not in a mac_bundle are mapped to
+    # com.googlecode.gyp.xcode.bundle, a pseudo-type that xcode.py interprets
+    # to create a single-file mh_bundle.
+    _types = {
+      'executable':                  'com.apple.product-type.tool',
+      'loadable_module':             'com.googlecode.gyp.xcode.bundle',
+      'shared_library':              'com.apple.product-type.library.dynamic',
+      'static_library':              'com.apple.product-type.library.static',
+      'executable+bundle':           'com.apple.product-type.application',
+      'loadable_module+bundle':      'com.apple.product-type.bundle',
+      'loadable_module+xctest':      'com.apple.product-type.bundle.unit-test',
+      'shared_library+bundle':       'com.apple.product-type.framework',
+      'executable+extension+bundle': 'com.apple.product-type.app-extension',
+    }
+
+    target_properties = {
+      'buildConfigurationList': xccl,
+      'name':                   target_name,
+    }
+
+    type = spec['type']
+    is_xctest = int(spec.get('mac_xctest_bundle', 0))
+    is_bundle = int(spec.get('mac_bundle', 0)) or is_xctest
+    is_extension = int(spec.get('ios_app_extension', 0))
+    if type != 'none':
+      type_bundle_key = type
+      if is_xctest:
+        type_bundle_key += '+xctest'
+        assert type == 'loadable_module', (
+            'mac_xctest_bundle targets must have type loadable_module '
+            '(target %s)' % target_name)
+      elif is_extension:
+        assert is_bundle, ('ios_app_extension flag requires mac_bundle '
+            '(target %s)' % target_name)
+        type_bundle_key += '+extension+bundle'
+      elif is_bundle:
+        type_bundle_key += '+bundle'
+
+      xctarget_type = gyp.xcodeproj_file.PBXNativeTarget
+      try:
+        target_properties['productType'] = _types[type_bundle_key]
+      except KeyError, e:
+        gyp.common.ExceptionAppend(e, "-- unknown product type while "
+                                   "writing target %s" % target_name)
+        raise
+    else:
+      xctarget_type = gyp.xcodeproj_file.PBXAggregateTarget
+      assert not is_bundle, (
+          'mac_bundle targets cannot have type none (target "%s")' %
+          target_name)
+      assert not is_xctest, (
+          'mac_xctest_bundle targets cannot have type none (target "%s")' %
+          target_name)
+
+    target_product_name = spec.get('product_name')
+    if target_product_name is not None:
+      target_properties['productName'] = target_product_name
+
+    xct = xctarget_type(target_properties, parent=pbxp,
+                        force_outdir=spec.get('product_dir'),
+                        force_prefix=spec.get('product_prefix'),
+                        force_extension=spec.get('product_extension'))
+    pbxp.AppendProperty('targets', xct)
+    xcode_targets[qualified_target] = xct
+    xcode_target_to_target_dict[xct] = spec
+
+    spec_actions = spec.get('actions', [])
+    spec_rules = spec.get('rules', [])
+
+    # Xcode has some "issues" with checking dependencies for the "Compile
+    # sources" step with any source files/headers generated by actions/rules.
+    # To work around this, if a target is building anything directly (not
+    # type "none"), then a second target is used to run the GYP actions/rules
+    # and is made a dependency of this target.  This way the work is done
+    # before the dependency checks for what should be recompiled.
+    support_xct = None
+    # The Xcode "issues" don't affect xcode-ninja builds, since the dependency
+    # logic all happens in ninja.  Don't bother creating the extra targets in
+    # that case.
+    if type != 'none' and (spec_actions or spec_rules) and not ninja_wrapper:
+      support_xccl = CreateXCConfigurationList(configuration_names);
+      support_target_suffix = generator_flags.get(
+          'support_target_suffix', ' Support')
+      support_target_properties = {
+        'buildConfigurationList': support_xccl,
+        'name':                   target_name + support_target_suffix,
+      }
+      if target_product_name:
+        support_target_properties['productName'] = \
+            target_product_name + ' Support'
+      support_xct = \
+          gyp.xcodeproj_file.PBXAggregateTarget(support_target_properties,
+                                                parent=pbxp)
+      pbxp.AppendProperty('targets', support_xct)
+      xct.AddDependency(support_xct)
+    # Hang the support target off the main target so it can be tested/found
+    # by the generator during Finalize.
+    xct.support_target = support_xct
+
+    prebuild_index = 0
+
+    # Add custom shell script phases for "actions" sections.
+    for action in spec_actions:
+      # There's no need to write anything into the script to ensure that the
+      # output directories already exist, because Xcode will look at the
+      # declared outputs and automatically ensure that they exist for us.
+
+      # Do we have a message to print when this action runs?
+      message = action.get('message')
+      if message:
+        message = 'echo note: ' + gyp.common.EncodePOSIXShellArgument(message)
+      else:
+        message = ''
+
+      # Turn the list into a string that can be passed to a shell.
+      action_string = gyp.common.EncodePOSIXShellList(action['action'])
+
+      # Convert Xcode-type variable references to sh-compatible environment
+      # variable references.
+      message_sh = gyp.xcodeproj_file.ConvertVariablesToShellSyntax(message)
+      action_string_sh = gyp.xcodeproj_file.ConvertVariablesToShellSyntax(
+        action_string)
+
+      script = ''
+      # Include the optional message
+      if message_sh:
+        script += message_sh + '\n'
+      # Be sure the script runs in exec, and that if exec fails, the script
+      # exits signalling an error.
+      script += 'exec ' + action_string_sh + '\nexit 1\n'
+      ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({
+            'inputPaths': action['inputs'],
+            'name': 'Action "' + action['action_name'] + '"',
+            'outputPaths': action['outputs'],
+            'shellScript': script,
+            'showEnvVarsInLog': 0,
+          })
+
+      if support_xct:
+        support_xct.AppendProperty('buildPhases', ssbp)
+      else:
+        # TODO(mark): this assumes too much knowledge of the internals of
+        # xcodeproj_file; some of these smarts should move into xcodeproj_file
+        # itself.
+        xct._properties['buildPhases'].insert(prebuild_index, ssbp)
+        prebuild_index = prebuild_index + 1
+
+      # TODO(mark): Should verify that at most one of these is specified.
+      if int(action.get('process_outputs_as_sources', False)):
+        for output in action['outputs']:
+          AddSourceToTarget(output, type, pbxp, xct)
+
+      if int(action.get('process_outputs_as_mac_bundle_resources', False)):
+        for output in action['outputs']:
+          AddResourceToTarget(output, pbxp, xct)
+
+    # tgt_mac_bundle_resources holds the list of bundle resources so
+    # the rule processing can check against it.
+    if is_bundle:
+      tgt_mac_bundle_resources = spec.get('mac_bundle_resources', [])
+    else:
+      tgt_mac_bundle_resources = []
+
+    # Add custom shell script phases driving "make" for "rules" sections.
+    #
+    # Xcode's built-in rule support is almost powerful enough to use directly,
+    # but there are a few significant deficiencies that render them unusable.
+    # There are workarounds for some of its inadequacies, but in aggregate,
+    # the workarounds added complexity to the generator, and some workarounds
+    # actually require input files to be crafted more carefully than I'd like.
+    # Consequently, until Xcode rules are made more capable, "rules" input
+    # sections will be handled in Xcode output by shell script build phases
+    # performed prior to the compilation phase.
+    #
+    # The following problems with Xcode rules were found.  The numbers are
+    # Apple radar IDs.  I hope that these shortcomings are addressed, I really
+    # liked having the rules handled directly in Xcode during the period that
+    # I was prototyping this.
+    #
+    # 6588600 Xcode compiles custom script rule outputs too soon, compilation
+    #         fails.  This occurs when rule outputs from distinct inputs are
+    #         interdependent.  The only workaround is to put rules and their
+    #         inputs in a separate target from the one that compiles the rule
+    #         outputs.  This requires input file cooperation and it means that
+    #         process_outputs_as_sources is unusable.
+    # 6584932 Need to declare that custom rule outputs should be excluded from
+    #         compilation.  A possible workaround is to lie to Xcode about a
+    #         rule's output, giving it a dummy file it doesn't know how to
+    #         compile.  The rule action script would need to touch the dummy.
+    # 6584839 I need a way to declare additional inputs to a custom rule.
+    #         A possible workaround is a shell script phase prior to
+    #         compilation that touches a rule's primary input files if any
+    #         would-be additional inputs are newer than the output.  Modifying
+    #         the source tree - even just modification times - feels dirty.
+    # 6564240 Xcode "custom script" build rules always dump all environment
+    #         variables.  This is a low-prioroty problem and is not a
+    #         show-stopper.
+    rules_by_ext = {}
+    for rule in spec_rules:
+      rules_by_ext[rule['extension']] = rule
+
+      # First, some definitions:
+      #
+      # A "rule source" is a file that was listed in a target's "sources"
+      # list and will have a rule applied to it on the basis of matching the
+      # rule's "extensions" attribute.  Rule sources are direct inputs to
+      # rules.
+      #
+      # Rule definitions may specify additional inputs in their "inputs"
+      # attribute.  These additional inputs are used for dependency tracking
+      # purposes.
+      #
+      # A "concrete output" is a rule output with input-dependent variables
+      # resolved.  For example, given a rule with:
+      #   'extension': 'ext', 'outputs': ['$(INPUT_FILE_BASE).cc'],
+      # if the target's "sources" list contained "one.ext" and "two.ext",
+      # the "concrete output" for rule input "two.ext" would be "two.cc".  If
+      # a rule specifies multiple outputs, each input file that the rule is
+      # applied to will have the same number of concrete outputs.
+      #
+      # If any concrete outputs are outdated or missing relative to their
+      # corresponding rule_source or to any specified additional input, the
+      # rule action must be performed to generate the concrete outputs.
+
+      # concrete_outputs_by_rule_source will have an item at the same index
+      # as the rule['rule_sources'] that it corresponds to.  Each item is a
+      # list of all of the concrete outputs for the rule_source.
+      concrete_outputs_by_rule_source = []
+
+      # concrete_outputs_all is a flat list of all concrete outputs that this
+      # rule is able to produce, given the known set of input files
+      # (rule_sources) that apply to it.
+      concrete_outputs_all = []
+
+      # messages & actions are keyed by the same indices as rule['rule_sources']
+      # and concrete_outputs_by_rule_source.  They contain the message and
+      # action to perform after resolving input-dependent variables.  The
+      # message is optional, in which case None is stored for each rule source.
+      messages = []
+      actions = []
+
+      for rule_source in rule.get('rule_sources', []):
+        rule_source_dirname, rule_source_basename = \
+            posixpath.split(rule_source)
+        (rule_source_root, rule_source_ext) = \
+            posixpath.splitext(rule_source_basename)
+
+        # These are the same variable names that Xcode uses for its own native
+        # rule support.  Because Xcode's rule engine is not being used, they
+        # need to be expanded as they are written to the makefile.
+        rule_input_dict = {
+          'INPUT_FILE_BASE':   rule_source_root,
+          'INPUT_FILE_SUFFIX': rule_source_ext,
+          'INPUT_FILE_NAME':   rule_source_basename,
+          'INPUT_FILE_PATH':   rule_source,
+          'INPUT_FILE_DIRNAME': rule_source_dirname,
+        }
+
+        concrete_outputs_for_this_rule_source = []
+        for output in rule.get('outputs', []):
+          # Fortunately, Xcode and make both use $(VAR) format for their
+          # variables, so the expansion is the only transformation necessary.
+          # Any remaning $(VAR)-type variables in the string can be given
+          # directly to make, which will pick up the correct settings from
+          # what Xcode puts into the environment.
+          concrete_output = ExpandXcodeVariables(output, rule_input_dict)
+          concrete_outputs_for_this_rule_source.append(concrete_output)
+
+          # Add all concrete outputs to the project.
+          pbxp.AddOrGetFileInRootGroup(concrete_output)
+
+        concrete_outputs_by_rule_source.append( \
+            concrete_outputs_for_this_rule_source)
+        concrete_outputs_all.extend(concrete_outputs_for_this_rule_source)
+
+        # TODO(mark): Should verify that at most one of these is specified.
+        if int(rule.get('process_outputs_as_sources', False)):
+          for output in concrete_outputs_for_this_rule_source:
+            AddSourceToTarget(output, type, pbxp, xct)
+
+        # If the file came from the mac_bundle_resources list or if the rule
+        # is marked to process outputs as bundle resource, do so.
+        was_mac_bundle_resource = rule_source in tgt_mac_bundle_resources
+        if was_mac_bundle_resource or \
+            int(rule.get('process_outputs_as_mac_bundle_resources', False)):
+          for output in concrete_outputs_for_this_rule_source:
+            AddResourceToTarget(output, pbxp, xct)
+
+        # Do we have a message to print when this rule runs?
+        message = rule.get('message')
+        if message:
+          message = gyp.common.EncodePOSIXShellArgument(message)
+          message = ExpandXcodeVariables(message, rule_input_dict)
+        messages.append(message)
+
+        # Turn the list into a string that can be passed to a shell.
+        action_string = gyp.common.EncodePOSIXShellList(rule['action'])
+
+        action = ExpandXcodeVariables(action_string, rule_input_dict)
+        actions.append(action)
+
+      if len(concrete_outputs_all) > 0:
+        # TODO(mark): There's a possibilty for collision here.  Consider
+        # target "t" rule "A_r" and target "t_A" rule "r".
+        makefile_name = '%s.make' % re.sub(
+            '[^a-zA-Z0-9_]', '_' , '%s_%s' % (target_name, rule['rule_name']))
+        makefile_path = os.path.join(xcode_projects[build_file].path,
+                                     makefile_name)
+        # TODO(mark): try/close?  Write to a temporary file and swap it only
+        # if it's got changes?
+        makefile = open(makefile_path, 'wb')
+
+        # make will build the first target in the makefile by default.  By
+        # convention, it's called "all".  List all (or at least one)
+        # concrete output for each rule source as a prerequisite of the "all"
+        # target.
+        makefile.write('all: \\\n')
+        for concrete_output_index in \
+            xrange(0, len(concrete_outputs_by_rule_source)):
+          # Only list the first (index [0]) concrete output of each input
+          # in the "all" target.  Otherwise, a parallel make (-j > 1) would
+          # attempt to process each input multiple times simultaneously.
+          # Otherwise, "all" could just contain the entire list of
+          # concrete_outputs_all.
+          concrete_output = \
+              concrete_outputs_by_rule_source[concrete_output_index][0]
+          if concrete_output_index == len(concrete_outputs_by_rule_source) - 1:
+            eol = ''
+          else:
+            eol = ' \\'
+          makefile.write('    %s%s\n' % (concrete_output, eol))
+
+        for (rule_source, concrete_outputs, message, action) in \
+            zip(rule['rule_sources'], concrete_outputs_by_rule_source,
+                messages, actions):
+          makefile.write('\n')
+
+          # Add a rule that declares it can build each concrete output of a
+          # rule source.  Collect the names of the directories that are
+          # required.
+          concrete_output_dirs = []
+          for concrete_output_index in xrange(0, len(concrete_outputs)):
+            concrete_output = concrete_outputs[concrete_output_index]
+            if concrete_output_index == 0:
+              bol = ''
+            else:
+              bol = '    '
+            makefile.write('%s%s \\\n' % (bol, concrete_output))
+
+            concrete_output_dir = posixpath.dirname(concrete_output)
+            if (concrete_output_dir and
+                concrete_output_dir not in concrete_output_dirs):
+              concrete_output_dirs.append(concrete_output_dir)
+
+          makefile.write('    : \\\n')
+
+          # The prerequisites for this rule are the rule source itself and
+          # the set of additional rule inputs, if any.
+          prerequisites = [rule_source]
+          prerequisites.extend(rule.get('inputs', []))
+          for prerequisite_index in xrange(0, len(prerequisites)):
+            prerequisite = prerequisites[prerequisite_index]
+            if prerequisite_index == len(prerequisites) - 1:
+              eol = ''
+            else:
+              eol = ' \\'
+            makefile.write('    %s%s\n' % (prerequisite, eol))
+
+          # Make sure that output directories exist before executing the rule
+          # action.
+          if len(concrete_output_dirs) > 0:
+            makefile.write('\t@mkdir -p "%s"\n' %
+                           '" "'.join(concrete_output_dirs))
+
+          # The rule message and action have already had the necessary variable
+          # substitutions performed.
+          if message:
+            # Mark it with note: so Xcode picks it up in build output.
+            makefile.write('\t@echo note: %s\n' % message)
+          makefile.write('\t%s\n' % action)
+
+        makefile.close()
+
+        # It might be nice to ensure that needed output directories exist
+        # here rather than in each target in the Makefile, but that wouldn't
+        # work if there ever was a concrete output that had an input-dependent
+        # variable anywhere other than in the leaf position.
+
+        # Don't declare any inputPaths or outputPaths.  If they're present,
+        # Xcode will provide a slight optimization by only running the script
+        # phase if any output is missing or outdated relative to any input.
+        # Unfortunately, it will also assume that all outputs are touched by
+        # the script, and if the outputs serve as files in a compilation
+        # phase, they will be unconditionally rebuilt.  Since make might not
+        # rebuild everything that could be declared here as an output, this
+        # extra compilation activity is unnecessary.  With inputPaths and
+        # outputPaths not supplied, make will always be called, but it knows
+        # enough to not do anything when everything is up-to-date.
+
+        # To help speed things up, pass -j COUNT to make so it does some work
+        # in parallel.  Don't use ncpus because Xcode will build ncpus targets
+        # in parallel and if each target happens to have a rules step, there
+        # would be ncpus^2 things going.  With a machine that has 2 quad-core
+        # Xeons, a build can quickly run out of processes based on
+        # scheduling/other tasks, and randomly failing builds are no good.
+        script = \
+"""JOB_COUNT="$(/usr/sbin/sysctl -n hw.ncpu)"
+if [ "${JOB_COUNT}" -gt 4 ]; then
+  JOB_COUNT=4
+fi
+exec xcrun make -f "${PROJECT_FILE_PATH}/%s" -j "${JOB_COUNT}"
+exit 1
+""" % makefile_name
+        ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({
+              'name': 'Rule "' + rule['rule_name'] + '"',
+              'shellScript': script,
+              'showEnvVarsInLog': 0,
+            })
+
+        if support_xct:
+          support_xct.AppendProperty('buildPhases', ssbp)
+        else:
+          # TODO(mark): this assumes too much knowledge of the internals of
+          # xcodeproj_file; some of these smarts should move into xcodeproj_file
+          # itself.
+          xct._properties['buildPhases'].insert(prebuild_index, ssbp)
+          prebuild_index = prebuild_index + 1
+
+      # Extra rule inputs also go into the project file.  Concrete outputs were
+      # already added when they were computed.
+      groups = ['inputs', 'inputs_excluded']
+      if skip_excluded_files:
+        groups = [x for x in groups if not x.endswith('_excluded')]
+      for group in groups:
+        for item in rule.get(group, []):
+          pbxp.AddOrGetFileInRootGroup(item)
+
+    # Add "sources".
+    for source in spec.get('sources', []):
+      (source_root, source_extension) = posixpath.splitext(source)
+      if source_extension[1:] not in rules_by_ext:
+        # AddSourceToTarget will add the file to a root group if it's not
+        # already there.
+        AddSourceToTarget(source, type, pbxp, xct)
+      else:
+        pbxp.AddOrGetFileInRootGroup(source)
+
+    # Add "mac_bundle_resources" and "mac_framework_private_headers" if
+    # it's a bundle of any type.
+    if is_bundle:
+      for resource in tgt_mac_bundle_resources:
+        (resource_root, resource_extension) = posixpath.splitext(resource)
+        if resource_extension[1:] not in rules_by_ext:
+          AddResourceToTarget(resource, pbxp, xct)
+        else:
+          pbxp.AddOrGetFileInRootGroup(resource)
+
+      for header in spec.get('mac_framework_private_headers', []):
+        AddHeaderToTarget(header, pbxp, xct, False)
+
+    # Add "mac_framework_headers". These can be valid for both frameworks
+    # and static libraries.
+    if is_bundle or type == 'static_library':
+      for header in spec.get('mac_framework_headers', []):
+        AddHeaderToTarget(header, pbxp, xct, True)
+
+    # Add "copies".
+    pbxcp_dict = {}
+    for copy_group in spec.get('copies', []):
+      dest = copy_group['destination']
+      if dest[0] not in ('/', '$'):
+        # Relative paths are relative to $(SRCROOT).
+        dest = '$(SRCROOT)/' + dest
+
+      # Coalesce multiple "copies" sections in the same target with the same
+      # "destination" property into the same PBXCopyFilesBuildPhase, otherwise
+      # they'll wind up with ID collisions.
+      pbxcp = pbxcp_dict.get(dest, None)
+      if pbxcp is None:
+        pbxcp = gyp.xcodeproj_file.PBXCopyFilesBuildPhase({
+              'name': 'Copy to ' + copy_group['destination']
+            },
+            parent=xct)
+        pbxcp.SetDestination(dest)
+
+        # TODO(mark): The usual comment about this knowing too much about
+        # gyp.xcodeproj_file internals applies.
+        xct._properties['buildPhases'].insert(prebuild_index, pbxcp)
+
+        pbxcp_dict[dest] = pbxcp
+
+      for file in copy_group['files']:
+        pbxcp.AddFile(file)
+
+    # Excluded files can also go into the project file.
+    if not skip_excluded_files:
+      for key in ['sources', 'mac_bundle_resources', 'mac_framework_headers',
+                  'mac_framework_private_headers']:
+        excluded_key = key + '_excluded'
+        for item in spec.get(excluded_key, []):
+          pbxp.AddOrGetFileInRootGroup(item)
+
+    # So can "inputs" and "outputs" sections of "actions" groups.
+    groups = ['inputs', 'inputs_excluded', 'outputs', 'outputs_excluded']
+    if skip_excluded_files:
+      groups = [x for x in groups if not x.endswith('_excluded')]
+    for action in spec.get('actions', []):
+      for group in groups:
+        for item in action.get(group, []):
+          # Exclude anything in BUILT_PRODUCTS_DIR.  They're products, not
+          # sources.
+          if not item.startswith('$(BUILT_PRODUCTS_DIR)/'):
+            pbxp.AddOrGetFileInRootGroup(item)
+
+    for postbuild in spec.get('postbuilds', []):
+      action_string_sh = gyp.common.EncodePOSIXShellList(postbuild['action'])
+      script = 'exec ' + action_string_sh + '\nexit 1\n'
+
+      # Make the postbuild step depend on the output of ld or ar from this
+      # target. Apparently putting the script step after the link step isn't
+      # sufficient to ensure proper ordering in all cases. With an input
+      # declared but no outputs, the script step should run every time, as
+      # desired.
+      ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({
+            'inputPaths': ['$(BUILT_PRODUCTS_DIR)/$(EXECUTABLE_PATH)'],
+            'name': 'Postbuild "' + postbuild['postbuild_name'] + '"',
+            'shellScript': script,
+            'showEnvVarsInLog': 0,
+          })
+      xct.AppendProperty('buildPhases', ssbp)
+
+    # Add dependencies before libraries, because adding a dependency may imply
+    # adding a library.  It's preferable to keep dependencies listed first
+    # during a link phase so that they can override symbols that would
+    # otherwise be provided by libraries, which will usually include system
+    # libraries.  On some systems, ld is finicky and even requires the
+    # libraries to be ordered in such a way that unresolved symbols in
+    # earlier-listed libraries may only be resolved by later-listed libraries.
+    # The Mac linker doesn't work that way, but other platforms do, and so
+    # their linker invocations need to be constructed in this way.  There's
+    # no compelling reason for Xcode's linker invocations to differ.
+
+    if 'dependencies' in spec:
+      for dependency in spec['dependencies']:
+        xct.AddDependency(xcode_targets[dependency])
+        # The support project also gets the dependencies (in case they are
+        # needed for the actions/rules to work).
+        if support_xct:
+          support_xct.AddDependency(xcode_targets[dependency])
+
+    if 'libraries' in spec:
+      for library in spec['libraries']:
+        xct.FrameworksPhase().AddFile(library)
+        # Add the library's directory to LIBRARY_SEARCH_PATHS if necessary.
+        # I wish Xcode handled this automatically.
+        library_dir = posixpath.dirname(library)
+        if library_dir not in xcode_standard_library_dirs and (
+            not xct.HasBuildSetting(_library_search_paths_var) or
+            library_dir not in xct.GetBuildSetting(_library_search_paths_var)):
+          xct.AppendBuildSetting(_library_search_paths_var, library_dir)
+
+    for configuration_name in configuration_names:
+      configuration = spec['configurations'][configuration_name]
+      xcbc = xct.ConfigurationNamed(configuration_name)
+      for include_dir in configuration.get('mac_framework_dirs', []):
+        xcbc.AppendBuildSetting('FRAMEWORK_SEARCH_PATHS', include_dir)
+      for include_dir in configuration.get('include_dirs', []):
+        xcbc.AppendBuildSetting('HEADER_SEARCH_PATHS', include_dir)
+      for library_dir in configuration.get('library_dirs', []):
+        if library_dir not in xcode_standard_library_dirs and (
+            not xcbc.HasBuildSetting(_library_search_paths_var) or
+            library_dir not in xcbc.GetBuildSetting(_library_search_paths_var)):
+          xcbc.AppendBuildSetting(_library_search_paths_var, library_dir)
+
+      if 'defines' in configuration:
+        for define in configuration['defines']:
+          set_define = EscapeXcodeDefine(define)
+          xcbc.AppendBuildSetting('GCC_PREPROCESSOR_DEFINITIONS', set_define)
+      if 'xcode_settings' in configuration:
+        for xck, xcv in configuration['xcode_settings'].iteritems():
+          xcbc.SetBuildSetting(xck, xcv)
+      if 'xcode_config_file' in configuration:
+        config_ref = pbxp.AddOrGetFileInRootGroup(
+            configuration['xcode_config_file'])
+        xcbc.SetBaseConfiguration(config_ref)
+
+  build_files = []
+  for build_file, build_file_dict in data.iteritems():
+    if build_file.endswith('.gyp'):
+      build_files.append(build_file)
+
+  for build_file in build_files:
+    xcode_projects[build_file].Finalize1(xcode_targets, serialize_all_tests)
+
+  for build_file in build_files:
+    xcode_projects[build_file].Finalize2(xcode_targets,
+                                         xcode_target_to_target_dict)
+
+  for build_file in build_files:
+    xcode_projects[build_file].Write()
diff --git a/gyp/pylib/gyp/generator/xcode_test.py b/gyp/pylib/gyp/generator/xcode_test.py
new file mode 100644 (file)
index 0000000..260324a
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Unit tests for the xcode.py file. """
+
+import gyp.generator.xcode as xcode
+import unittest
+import sys
+
+
+class TestEscapeXcodeDefine(unittest.TestCase):
+  if sys.platform == 'darwin':
+    def test_InheritedRemainsUnescaped(self):
+      self.assertEqual(xcode.EscapeXcodeDefine('$(inherited)'), '$(inherited)')
+
+    def test_Escaping(self):
+      self.assertEqual(xcode.EscapeXcodeDefine('a b"c\\'), 'a\\ b\\"c\\\\')
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/gyp/pylib/gyp/input.py b/gyp/pylib/gyp/input.py
new file mode 100644 (file)
index 0000000..bb853a5
--- /dev/null
@@ -0,0 +1,2873 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from compiler.ast import Const
+from compiler.ast import Dict
+from compiler.ast import Discard
+from compiler.ast import List
+from compiler.ast import Module
+from compiler.ast import Node
+from compiler.ast import Stmt
+import compiler
+import gyp.common
+import gyp.simple_copy
+import multiprocessing
+import optparse
+import os.path
+import re
+import shlex
+import signal
+import subprocess
+import sys
+import threading
+import time
+import traceback
+from gyp.common import GypError
+from gyp.common import OrderedSet
+
+
+# A list of types that are treated as linkable.
+linkable_types = ['executable', 'shared_library', 'loadable_module']
+
+# A list of sections that contain links to other targets.
+dependency_sections = ['dependencies', 'export_dependent_settings']
+
+# base_path_sections is a list of sections defined by GYP that contain
+# pathnames.  The generators can provide more keys, the two lists are merged
+# into path_sections, but you should call IsPathSection instead of using either
+# list directly.
+base_path_sections = [
+  'destination',
+  'files',
+  'include_dirs',
+  'inputs',
+  'libraries',
+  'outputs',
+  'sources',
+]
+path_sections = set()
+
+def IsPathSection(section):
+  # If section ends in one of the '=+?!' characters, it's applied to a section
+  # without the trailing characters.  '/' is notably absent from this list,
+  # because there's no way for a regular expression to be treated as a path.
+  while section[-1:] in '=+?!':
+    section = section[:-1]
+
+  if section in path_sections:
+    return True
+
+  # Sections mathing the regexp '_(dir|file|path)s?$' are also
+  # considered PathSections. Using manual string matching since that
+  # is much faster than the regexp and this can be called hundreds of
+  # thousands of times so micro performance matters.
+  if "_" in section:
+    tail = section[-6:]
+    if tail[-1] == 's':
+      tail = tail[:-1]
+    if tail[-5:] in ('_file', '_path'):
+      return True
+    return tail[-4:] == '_dir'
+
+  return False
+
+# base_non_configuration_keys is a list of key names that belong in the target
+# itself and should not be propagated into its configurations.  It is merged
+# with a list that can come from the generator to
+# create non_configuration_keys.
+base_non_configuration_keys = [
+  # Sections that must exist inside targets and not configurations.
+  'actions',
+  'configurations',
+  'copies',
+  'default_configuration',
+  'dependencies',
+  'dependencies_original',
+  'libraries',
+  'postbuilds',
+  'product_dir',
+  'product_extension',
+  'product_name',
+  'product_prefix',
+  'rules',
+  'run_as',
+  'sources',
+  'standalone_static_library',
+  'suppress_wildcard',
+  'target_name',
+  'toolset',
+  'toolsets',
+  'type',
+
+  # Sections that can be found inside targets or configurations, but that
+  # should not be propagated from targets into their configurations.
+  'variables',
+]
+non_configuration_keys = []
+
+# Keys that do not belong inside a configuration dictionary.
+invalid_configuration_keys = [
+  'actions',
+  'all_dependent_settings',
+  'configurations',
+  'dependencies',
+  'direct_dependent_settings',
+  'libraries',
+  'link_settings',
+  'sources',
+  'standalone_static_library',
+  'target_name',
+  'type',
+]
+
+# Controls whether or not the generator supports multiple toolsets.
+multiple_toolsets = False
+
+# Paths for converting filelist paths to output paths: {
+#   toplevel,
+#   qualified_output_dir,
+# }
+generator_filelist_paths = None
+
+def GetIncludedBuildFiles(build_file_path, aux_data, included=None):
+  """Return a list of all build files included into build_file_path.
+
+  The returned list will contain build_file_path as well as all other files
+  that it included, either directly or indirectly.  Note that the list may
+  contain files that were included into a conditional section that evaluated
+  to false and was not merged into build_file_path's dict.
+
+  aux_data is a dict containing a key for each build file or included build
+  file.  Those keys provide access to dicts whose "included" keys contain
+  lists of all other files included by the build file.
+
+  included should be left at its default None value by external callers.  It
+  is used for recursion.
+
+  The returned list will not contain any duplicate entries.  Each build file
+  in the list will be relative to the current directory.
+  """
+
+  if included == None:
+    included = []
+
+  if build_file_path in included:
+    return included
+
+  included.append(build_file_path)
+
+  for included_build_file in aux_data[build_file_path].get('included', []):
+    GetIncludedBuildFiles(included_build_file, aux_data, included)
+
+  return included
+
+
+def CheckedEval(file_contents):
+  """Return the eval of a gyp file.
+
+  The gyp file is restricted to dictionaries and lists only, and
+  repeated keys are not allowed.
+
+  Note that this is slower than eval() is.
+  """
+
+  ast = compiler.parse(file_contents)
+  assert isinstance(ast, Module)
+  c1 = ast.getChildren()
+  assert c1[0] is None
+  assert isinstance(c1[1], Stmt)
+  c2 = c1[1].getChildren()
+  assert isinstance(c2[0], Discard)
+  c3 = c2[0].getChildren()
+  assert len(c3) == 1
+  return CheckNode(c3[0], [])
+
+
+def CheckNode(node, keypath):
+  if isinstance(node, Dict):
+    c = node.getChildren()
+    dict = {}
+    for n in range(0, len(c), 2):
+      assert isinstance(c[n], Const)
+      key = c[n].getChildren()[0]
+      if key in dict:
+        raise GypError("Key '" + key + "' repeated at level " +
+              repr(len(keypath) + 1) + " with key path '" +
+              '.'.join(keypath) + "'")
+      kp = list(keypath)  # Make a copy of the list for descending this node.
+      kp.append(key)
+      dict[key] = CheckNode(c[n + 1], kp)
+    return dict
+  elif isinstance(node, List):
+    c = node.getChildren()
+    children = []
+    for index, child in enumerate(c):
+      kp = list(keypath)  # Copy list.
+      kp.append(repr(index))
+      children.append(CheckNode(child, kp))
+    return children
+  elif isinstance(node, Const):
+    return node.getChildren()[0]
+  else:
+    raise TypeError, "Unknown AST node at key path '" + '.'.join(keypath) + \
+         "': " + repr(node)
+
+
+def LoadOneBuildFile(build_file_path, data, aux_data, includes,
+                     is_target, check):
+  if build_file_path in data:
+    return data[build_file_path]
+
+  if os.path.exists(build_file_path):
+    build_file_contents = open(build_file_path).read()
+  else:
+    raise GypError("%s not found (cwd: %s)" % (build_file_path, os.getcwd()))
+
+  build_file_data = None
+  try:
+    if check:
+      build_file_data = CheckedEval(build_file_contents)
+    else:
+      build_file_data = eval(build_file_contents, {'__builtins__': None},
+                             None)
+  except SyntaxError, e:
+    e.filename = build_file_path
+    raise
+  except Exception, e:
+    gyp.common.ExceptionAppend(e, 'while reading ' + build_file_path)
+    raise
+
+  if type(build_file_data) is not dict:
+    raise GypError("%s does not evaluate to a dictionary." % build_file_path)
+
+  data[build_file_path] = build_file_data
+  aux_data[build_file_path] = {}
+
+  # Scan for includes and merge them in.
+  if ('skip_includes' not in build_file_data or
+      not build_file_data['skip_includes']):
+    try:
+      if is_target:
+        LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
+                                      aux_data, includes, check)
+      else:
+        LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
+                                      aux_data, None, check)
+    except Exception, e:
+      gyp.common.ExceptionAppend(e,
+                                 'while reading includes of ' + build_file_path)
+      raise
+
+  return build_file_data
+
+
+def LoadBuildFileIncludesIntoDict(subdict, subdict_path, data, aux_data,
+                                  includes, check):
+  includes_list = []
+  if includes != None:
+    includes_list.extend(includes)
+  if 'includes' in subdict:
+    for include in subdict['includes']:
+      # "include" is specified relative to subdict_path, so compute the real
+      # path to include by appending the provided "include" to the directory
+      # in which subdict_path resides.
+      relative_include = \
+          os.path.normpath(os.path.join(os.path.dirname(subdict_path), include))
+      includes_list.append(relative_include)
+    # Unhook the includes list, it's no longer needed.
+    del subdict['includes']
+
+  # Merge in the included files.
+  for include in includes_list:
+    if not 'included' in aux_data[subdict_path]:
+      aux_data[subdict_path]['included'] = []
+    aux_data[subdict_path]['included'].append(include)
+
+    gyp.DebugOutput(gyp.DEBUG_INCLUDES, "Loading Included File: '%s'", include)
+
+    MergeDicts(subdict,
+               LoadOneBuildFile(include, data, aux_data, None, False, check),
+               subdict_path, include)
+
+  # Recurse into subdictionaries.
+  for k, v in subdict.iteritems():
+    if type(v) is dict:
+      LoadBuildFileIncludesIntoDict(v, subdict_path, data, aux_data,
+                                    None, check)
+    elif type(v) is list:
+      LoadBuildFileIncludesIntoList(v, subdict_path, data, aux_data,
+                                    check)
+
+
+# This recurses into lists so that it can look for dicts.
+def LoadBuildFileIncludesIntoList(sublist, sublist_path, data, aux_data, check):
+  for item in sublist:
+    if type(item) is dict:
+      LoadBuildFileIncludesIntoDict(item, sublist_path, data, aux_data,
+                                    None, check)
+    elif type(item) is list:
+      LoadBuildFileIncludesIntoList(item, sublist_path, data, aux_data, check)
+
+# Processes toolsets in all the targets. This recurses into condition entries
+# since they can contain toolsets as well.
+def ProcessToolsetsInDict(data):
+  if 'targets' in data:
+    target_list = data['targets']
+    new_target_list = []
+    for target in target_list:
+      # If this target already has an explicit 'toolset', and no 'toolsets'
+      # list, don't modify it further.
+      if 'toolset' in target and 'toolsets' not in target:
+        new_target_list.append(target)
+        continue
+      if multiple_toolsets:
+        toolsets = target.get('toolsets', ['target'])
+      else:
+        toolsets = ['target']
+      # Make sure this 'toolsets' definition is only processed once.
+      if 'toolsets' in target:
+        del target['toolsets']
+      if len(toolsets) > 0:
+        # Optimization: only do copies if more than one toolset is specified.
+        for build in toolsets[1:]:
+          new_target = gyp.simple_copy.deepcopy(target)
+          new_target['toolset'] = build
+          new_target_list.append(new_target)
+        target['toolset'] = toolsets[0]
+        new_target_list.append(target)
+    data['targets'] = new_target_list
+  if 'conditions' in data:
+    for condition in data['conditions']:
+      if type(condition) is list:
+        for condition_dict in condition[1:]:
+          ProcessToolsetsInDict(condition_dict)
+
+
+# TODO(mark): I don't love this name.  It just means that it's going to load
+# a build file that contains targets and is expected to provide a targets dict
+# that contains the targets...
+def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes,
+                        depth, check, load_dependencies):
+  # If depth is set, predefine the DEPTH variable to be a relative path from
+  # this build file's directory to the directory identified by depth.
+  if depth:
+    # TODO(dglazkov) The backslash/forward-slash replacement at the end is a
+    # temporary measure. This should really be addressed by keeping all paths
+    # in POSIX until actual project generation.
+    d = gyp.common.RelativePath(depth, os.path.dirname(build_file_path))
+    if d == '':
+      variables['DEPTH'] = '.'
+    else:
+      variables['DEPTH'] = d.replace('\\', '/')
+
+  if build_file_path in data['target_build_files']:
+    # Already loaded.
+    return False
+  data['target_build_files'].add(build_file_path)
+
+  gyp.DebugOutput(gyp.DEBUG_INCLUDES,
+                  "Loading Target Build File '%s'", build_file_path)
+
+  build_file_data = LoadOneBuildFile(build_file_path, data, aux_data,
+                                     includes, True, check)
+
+  # Store DEPTH for later use in generators.
+  build_file_data['_DEPTH'] = depth
+
+  # Set up the included_files key indicating which .gyp files contributed to
+  # this target dict.
+  if 'included_files' in build_file_data:
+    raise GypError(build_file_path + ' must not contain included_files key')
+
+  included = GetIncludedBuildFiles(build_file_path, aux_data)
+  build_file_data['included_files'] = []
+  for included_file in included:
+    # included_file is relative to the current directory, but it needs to
+    # be made relative to build_file_path's directory.
+    included_relative = \
+        gyp.common.RelativePath(included_file,
+                                os.path.dirname(build_file_path))
+    build_file_data['included_files'].append(included_relative)
+
+  # Do a first round of toolsets expansion so that conditions can be defined
+  # per toolset.
+  ProcessToolsetsInDict(build_file_data)
+
+  # Apply "pre"/"early" variable expansions and condition evaluations.
+  ProcessVariablesAndConditionsInDict(
+      build_file_data, PHASE_EARLY, variables, build_file_path)
+
+  # Since some toolsets might have been defined conditionally, perform
+  # a second round of toolsets expansion now.
+  ProcessToolsetsInDict(build_file_data)
+
+  # Look at each project's target_defaults dict, and merge settings into
+  # targets.
+  if 'target_defaults' in build_file_data:
+    if 'targets' not in build_file_data:
+      raise GypError("Unable to find targets in build file %s" %
+                     build_file_path)
+
+    index = 0
+    while index < len(build_file_data['targets']):
+      # This procedure needs to give the impression that target_defaults is
+      # used as defaults, and the individual targets inherit from that.
+      # The individual targets need to be merged into the defaults.  Make
+      # a deep copy of the defaults for each target, merge the target dict
+      # as found in the input file into that copy, and then hook up the
+      # copy with the target-specific data merged into it as the replacement
+      # target dict.
+      old_target_dict = build_file_data['targets'][index]
+      new_target_dict = gyp.simple_copy.deepcopy(
+        build_file_data['target_defaults'])
+      MergeDicts(new_target_dict, old_target_dict,
+                 build_file_path, build_file_path)
+      build_file_data['targets'][index] = new_target_dict
+      index += 1
+
+    # No longer needed.
+    del build_file_data['target_defaults']
+
+  # Look for dependencies.  This means that dependency resolution occurs
+  # after "pre" conditionals and variable expansion, but before "post" -
+  # in other words, you can't put a "dependencies" section inside a "post"
+  # conditional within a target.
+
+  dependencies = []
+  if 'targets' in build_file_data:
+    for target_dict in build_file_data['targets']:
+      if 'dependencies' not in target_dict:
+        continue
+      for dependency in target_dict['dependencies']:
+        dependencies.append(
+            gyp.common.ResolveTarget(build_file_path, dependency, None)[0])
+
+  if load_dependencies:
+    for dependency in dependencies:
+      try:
+        LoadTargetBuildFile(dependency, data, aux_data, variables,
+                            includes, depth, check, load_dependencies)
+      except Exception, e:
+        gyp.common.ExceptionAppend(
+          e, 'while loading dependencies of %s' % build_file_path)
+        raise
+  else:
+    return (build_file_path, dependencies)
+
+
+def CallLoadTargetBuildFile(global_flags,
+                            build_file_path, data,
+                            aux_data, variables,
+                            includes, depth, check,
+                            generator_input_info):
+  """Wrapper around LoadTargetBuildFile for parallel processing.
+
+     This wrapper is used when LoadTargetBuildFile is executed in
+     a worker process.
+  """
+
+  try:
+    signal.signal(signal.SIGINT, signal.SIG_IGN)
+
+    # Apply globals so that the worker process behaves the same.
+    for key, value in global_flags.iteritems():
+      globals()[key] = value
+
+    # Save the keys so we can return data that changed.
+    data_keys = set(data)
+    aux_data_keys = set(aux_data)
+
+    SetGeneratorGlobals(generator_input_info)
+    result = LoadTargetBuildFile(build_file_path, data,
+                                 aux_data, variables,
+                                 includes, depth, check, False)
+    if not result:
+      return result
+
+    (build_file_path, dependencies) = result
+
+    data_out = {}
+    for key in data:
+      if key == 'target_build_files':
+        continue
+      if key not in data_keys:
+        data_out[key] = data[key]
+    aux_data_out = {}
+    for key in aux_data:
+      if key not in aux_data_keys:
+        aux_data_out[key] = aux_data[key]
+
+    # This gets serialized and sent back to the main process via a pipe.
+    # It's handled in LoadTargetBuildFileCallback.
+    return (build_file_path,
+            data_out,
+            aux_data_out,
+            dependencies)
+  except GypError, e:
+    sys.stderr.write("gyp: %s\n" % e)
+    return None
+  except Exception, e:
+    print >>sys.stderr, 'Exception:', e
+    print >>sys.stderr, traceback.format_exc()
+    return None
+
+
+class ParallelProcessingError(Exception):
+  pass
+
+
+class ParallelState(object):
+  """Class to keep track of state when processing input files in parallel.
+
+  If build files are loaded in parallel, use this to keep track of
+  state during farming out and processing parallel jobs. It's stored
+  in a global so that the callback function can have access to it.
+  """
+
+  def __init__(self):
+    # The multiprocessing pool.
+    self.pool = None
+    # The condition variable used to protect this object and notify
+    # the main loop when there might be more data to process.
+    self.condition = None
+    # The "data" dict that was passed to LoadTargetBuildFileParallel
+    self.data = None
+    # The "aux_data" dict that was passed to LoadTargetBuildFileParallel
+    self.aux_data = None
+    # The number of parallel calls outstanding; decremented when a response
+    # was received.
+    self.pending = 0
+    # The set of all build files that have been scheduled, so we don't
+    # schedule the same one twice.
+    self.scheduled = set()
+    # A list of dependency build file paths that haven't been scheduled yet.
+    self.dependencies = []
+    # Flag to indicate if there was an error in a child process.
+    self.error = False
+
+  def LoadTargetBuildFileCallback(self, result):
+    """Handle the results of running LoadTargetBuildFile in another process.
+    """
+    self.condition.acquire()
+    if not result:
+      self.error = True
+      self.condition.notify()
+      self.condition.release()
+      return
+    (build_file_path0, data0, aux_data0, dependencies0) = result
+    self.data['target_build_files'].add(build_file_path0)
+    for key in data0:
+      self.data[key] = data0[key]
+    for key in aux_data0:
+      self.aux_data[key] = aux_data0[key]
+    for new_dependency in dependencies0:
+      if new_dependency not in self.scheduled:
+        self.scheduled.add(new_dependency)
+        self.dependencies.append(new_dependency)
+    self.pending -= 1
+    self.condition.notify()
+    self.condition.release()
+
+
+def LoadTargetBuildFilesParallel(build_files, data, aux_data,
+                                 variables, includes, depth, check,
+                                 generator_input_info):
+  parallel_state = ParallelState()
+  parallel_state.condition = threading.Condition()
+  # Make copies of the build_files argument that we can modify while working.
+  parallel_state.dependencies = list(build_files)
+  parallel_state.scheduled = set(build_files)
+  parallel_state.pending = 0
+  parallel_state.data = data
+  parallel_state.aux_data = aux_data
+
+  try:
+    parallel_state.condition.acquire()
+    while parallel_state.dependencies or parallel_state.pending:
+      if parallel_state.error:
+        break
+      if not parallel_state.dependencies:
+        parallel_state.condition.wait()
+        continue
+
+      dependency = parallel_state.dependencies.pop()
+
+      parallel_state.pending += 1
+      data_in = {}
+      data_in['target_build_files'] = data['target_build_files']
+      aux_data_in = {}
+      global_flags = {
+        'path_sections': globals()['path_sections'],
+        'non_configuration_keys': globals()['non_configuration_keys'],
+        'multiple_toolsets': globals()['multiple_toolsets']}
+
+      if not parallel_state.pool:
+        parallel_state.pool = multiprocessing.Pool(multiprocessing.cpu_count())
+      parallel_state.pool.apply_async(
+          CallLoadTargetBuildFile,
+          args = (global_flags, dependency,
+                  data_in, aux_data_in,
+                  variables, includes, depth, check, generator_input_info),
+          callback = parallel_state.LoadTargetBuildFileCallback)
+  except KeyboardInterrupt, e:
+    parallel_state.pool.terminate()
+    raise e
+
+  parallel_state.condition.release()
+
+  parallel_state.pool.close()
+  parallel_state.pool.join()
+  parallel_state.pool = None
+
+  if parallel_state.error:
+    sys.exit(1)
+
+# Look for the bracket that matches the first bracket seen in a
+# string, and return the start and end as a tuple.  For example, if
+# the input is something like "<(foo <(bar)) blah", then it would
+# return (1, 13), indicating the entire string except for the leading
+# "<" and trailing " blah".
+LBRACKETS= set('{[(')
+BRACKETS = {'}': '{', ']': '[', ')': '('}
+def FindEnclosingBracketGroup(input_str):
+  stack = []
+  start = -1
+  for index, char in enumerate(input_str):
+    if char in LBRACKETS:
+      stack.append(char)
+      if start == -1:
+        start = index
+    elif char in BRACKETS:
+      if not stack:
+        return (-1, -1)
+      if stack.pop() != BRACKETS[char]:
+        return (-1, -1)
+      if not stack:
+        return (start, index + 1)
+  return (-1, -1)
+
+
+def IsStrCanonicalInt(string):
+  """Returns True if |string| is in its canonical integer form.
+
+  The canonical form is such that str(int(string)) == string.
+  """
+  if type(string) is str:
+    # This function is called a lot so for maximum performance, avoid
+    # involving regexps which would otherwise make the code much
+    # shorter. Regexps would need twice the time of this function.
+    if string:
+      if string == "0":
+        return True
+      if string[0] == "-":
+        string = string[1:]
+        if not string:
+          return False
+      if '1' <= string[0] <= '9':
+        return string.isdigit()
+
+  return False
+
+
+# This matches things like "<(asdf)", "<!(cmd)", "<!@(cmd)", "<|(list)",
+# "<!interpreter(arguments)", "<([list])", and even "<([)" and "<(<())".
+# In the last case, the inner "<()" is captured in match['content'].
+early_variable_re = re.compile(
+    '(?P<replace>(?P<type><(?:(?:!?@?)|\|)?)'
+    '(?P<command_string>[-a-zA-Z0-9_.]+)?'
+    '\((?P<is_array>\s*\[?)'
+    '(?P<content>.*?)(\]?)\))')
+
+# This matches the same as early_variable_re, but with '>' instead of '<'.
+late_variable_re = re.compile(
+    '(?P<replace>(?P<type>>(?:(?:!?@?)|\|)?)'
+    '(?P<command_string>[-a-zA-Z0-9_.]+)?'
+    '\((?P<is_array>\s*\[?)'
+    '(?P<content>.*?)(\]?)\))')
+
+# This matches the same as early_variable_re, but with '^' instead of '<'.
+latelate_variable_re = re.compile(
+    '(?P<replace>(?P<type>[\^](?:(?:!?@?)|\|)?)'
+    '(?P<command_string>[-a-zA-Z0-9_.]+)?'
+    '\((?P<is_array>\s*\[?)'
+    '(?P<content>.*?)(\]?)\))')
+
+# Global cache of results from running commands so they don't have to be run
+# more then once.
+cached_command_results = {}
+
+
+def FixupPlatformCommand(cmd):
+  if sys.platform == 'win32':
+    if type(cmd) is list:
+      cmd = [re.sub('^cat ', 'type ', cmd[0])] + cmd[1:]
+    else:
+      cmd = re.sub('^cat ', 'type ', cmd)
+  return cmd
+
+
+PHASE_EARLY = 0
+PHASE_LATE = 1
+PHASE_LATELATE = 2
+
+
+def ExpandVariables(input, phase, variables, build_file):
+  # Look for the pattern that gets expanded into variables
+  if phase == PHASE_EARLY:
+    variable_re = early_variable_re
+    expansion_symbol = '<'
+  elif phase == PHASE_LATE:
+    variable_re = late_variable_re
+    expansion_symbol = '>'
+  elif phase == PHASE_LATELATE:
+    variable_re = latelate_variable_re
+    expansion_symbol = '^'
+  else:
+    assert False
+
+  input_str = str(input)
+  if IsStrCanonicalInt(input_str):
+    return int(input_str)
+
+  # Do a quick scan to determine if an expensive regex search is warranted.
+  if expansion_symbol not in input_str:
+    return input_str
+
+  # Get the entire list of matches as a list of MatchObject instances.
+  # (using findall here would return strings instead of MatchObjects).
+  matches = list(variable_re.finditer(input_str))
+  if not matches:
+    return input_str
+
+  output = input_str
+  # Reverse the list of matches so that replacements are done right-to-left.
+  # That ensures that earlier replacements won't mess up the string in a
+  # way that causes later calls to find the earlier substituted text instead
+  # of what's intended for replacement.
+  matches.reverse()
+  for match_group in matches:
+    match = match_group.groupdict()
+    gyp.DebugOutput(gyp.DEBUG_VARIABLES, "Matches: %r", match)
+    # match['replace'] is the substring to look for, match['type']
+    # is the character code for the replacement type (< > <! >! <| >| <@
+    # >@ <!@ >!@), match['is_array'] contains a '[' for command
+    # arrays, and match['content'] is the name of the variable (< >)
+    # or command to run (<! >!). match['command_string'] is an optional
+    # command string. Currently, only 'pymod_do_main' is supported.
+
+    # run_command is true if a ! variant is used.
+    run_command = '!' in match['type']
+    command_string = match['command_string']
+
+    # file_list is true if a | variant is used.
+    file_list = '|' in match['type']
+
+    # Capture these now so we can adjust them later.
+    replace_start = match_group.start('replace')
+    replace_end = match_group.end('replace')
+
+    # Find the ending paren, and re-evaluate the contained string.
+    (c_start, c_end) = FindEnclosingBracketGroup(input_str[replace_start:])
+
+    # Adjust the replacement range to match the entire command
+    # found by FindEnclosingBracketGroup (since the variable_re
+    # probably doesn't match the entire command if it contained
+    # nested variables).
+    replace_end = replace_start + c_end
+
+    # Find the "real" replacement, matching the appropriate closing
+    # paren, and adjust the replacement start and end.
+    replacement = input_str[replace_start:replace_end]
+
+    # Figure out what the contents of the variable parens are.
+    contents_start = replace_start + c_start + 1
+    contents_end = replace_end - 1
+    contents = input_str[contents_start:contents_end]
+
+    # Do filter substitution now for <|().
+    # Admittedly, this is different than the evaluation order in other
+    # contexts. However, since filtration has no chance to run on <|(),
+    # this seems like the only obvious way to give them access to filters.
+    if file_list:
+      processed_variables = gyp.simple_copy.deepcopy(variables)
+      ProcessListFiltersInDict(contents, processed_variables)
+      # Recurse to expand variables in the contents
+      contents = ExpandVariables(contents, phase,
+                                 processed_variables, build_file)
+    else:
+      # Recurse to expand variables in the contents
+      contents = ExpandVariables(contents, phase, variables, build_file)
+
+    # Strip off leading/trailing whitespace so that variable matches are
+    # simpler below (and because they are rarely needed).
+    contents = contents.strip()
+
+    # expand_to_list is true if an @ variant is used.  In that case,
+    # the expansion should result in a list.  Note that the caller
+    # is to be expecting a list in return, and not all callers do
+    # because not all are working in list context.  Also, for list
+    # expansions, there can be no other text besides the variable
+    # expansion in the input string.
+    expand_to_list = '@' in match['type'] and input_str == replacement
+
+    if run_command or file_list:
+      # Find the build file's directory, so commands can be run or file lists
+      # generated relative to it.
+      build_file_dir = os.path.dirname(build_file)
+      if build_file_dir == '' and not file_list:
+        # If build_file is just a leaf filename indicating a file in the
+        # current directory, build_file_dir might be an empty string.  Set
+        # it to None to signal to subprocess.Popen that it should run the
+        # command in the current directory.
+        build_file_dir = None
+
+    # Support <|(listfile.txt ...) which generates a file
+    # containing items from a gyp list, generated at gyp time.
+    # This works around actions/rules which have more inputs than will
+    # fit on the command line.
+    if file_list:
+      if type(contents) is list:
+        contents_list = contents
+      else:
+        contents_list = contents.split(' ')
+      replacement = contents_list[0]
+      if os.path.isabs(replacement):
+        raise GypError('| cannot handle absolute paths, got "%s"' % replacement)
+
+      if not generator_filelist_paths:
+        path = os.path.join(build_file_dir, replacement)
+      else:
+        if os.path.isabs(build_file_dir):
+          toplevel = generator_filelist_paths['toplevel']
+          rel_build_file_dir = gyp.common.RelativePath(build_file_dir, toplevel)
+        else:
+          rel_build_file_dir = build_file_dir
+        qualified_out_dir = generator_filelist_paths['qualified_out_dir']
+        path = os.path.join(qualified_out_dir, rel_build_file_dir, replacement)
+        gyp.common.EnsureDirExists(path)
+
+      replacement = gyp.common.RelativePath(path, build_file_dir)
+      f = gyp.common.WriteOnDiff(path)
+      for i in contents_list[1:]:
+        f.write('%s\n' % i)
+      f.close()
+
+    elif run_command:
+      use_shell = True
+      if match['is_array']:
+        contents = eval(contents)
+        use_shell = False
+
+      # Check for a cached value to avoid executing commands, or generating
+      # file lists more than once. The cache key contains the command to be
+      # run as well as the directory to run it from, to account for commands
+      # that depend on their current directory.
+      # TODO(http://code.google.com/p/gyp/issues/detail?id=111): In theory,
+      # someone could author a set of GYP files where each time the command
+      # is invoked it produces different output by design. When the need
+      # arises, the syntax should be extended to support no caching off a
+      # command's output so it is run every time.
+      cache_key = (str(contents), build_file_dir)
+      cached_value = cached_command_results.get(cache_key, None)
+      if cached_value is None:
+        gyp.DebugOutput(gyp.DEBUG_VARIABLES,
+                        "Executing command '%s' in directory '%s'",
+                        contents, build_file_dir)
+
+        replacement = ''
+
+        if command_string == 'pymod_do_main':
+          # <!pymod_do_main(modulename param eters) loads |modulename| as a
+          # python module and then calls that module's DoMain() function,
+          # passing ["param", "eters"] as a single list argument. For modules
+          # that don't load quickly, this can be faster than
+          # <!(python modulename param eters). Do this in |build_file_dir|.
+          oldwd = os.getcwd()  # Python doesn't like os.open('.'): no fchdir.
+          if build_file_dir:  # build_file_dir may be None (see above).
+            os.chdir(build_file_dir)
+          try:
+
+            parsed_contents = shlex.split(contents)
+            try:
+              py_module = __import__(parsed_contents[0])
+            except ImportError as e:
+              raise GypError("Error importing pymod_do_main"
+                             "module (%s): %s" % (parsed_contents[0], e))
+            replacement = str(py_module.DoMain(parsed_contents[1:])).rstrip()
+          finally:
+            os.chdir(oldwd)
+          assert replacement != None
+        elif command_string:
+          raise GypError("Unknown command string '%s' in '%s'." %
+                         (command_string, contents))
+        else:
+          # Fix up command with platform specific workarounds.
+          contents = FixupPlatformCommand(contents)
+          p = subprocess.Popen(contents, shell=use_shell,
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.PIPE,
+                               stdin=subprocess.PIPE,
+                               cwd=build_file_dir)
+
+          p_stdout, p_stderr = p.communicate('')
+
+          if p.wait() != 0 or p_stderr:
+            sys.stderr.write(p_stderr)
+            # Simulate check_call behavior, since check_call only exists
+            # in python 2.5 and later.
+            raise GypError("Call to '%s' returned exit status %d." %
+                           (contents, p.returncode))
+          replacement = p_stdout.rstrip()
+
+        cached_command_results[cache_key] = replacement
+      else:
+        gyp.DebugOutput(gyp.DEBUG_VARIABLES,
+                        "Had cache value for command '%s' in directory '%s'",
+                        contents,build_file_dir)
+        replacement = cached_value
+
+    else:
+      if not contents in variables:
+        if contents[-1] in ['!', '/']:
+          # In order to allow cross-compiles (nacl) to happen more naturally,
+          # we will allow references to >(sources/) etc. to resolve to
+          # and empty list if undefined. This allows actions to:
+          # 'action!': [
+          #   '>@(_sources!)',
+          # ],
+          # 'action/': [
+          #   '>@(_sources/)',
+          # ],
+          replacement = []
+        else:
+          raise GypError('Undefined variable ' + contents +
+                         ' in ' + build_file)
+      else:
+        replacement = variables[contents]
+
+    if type(replacement) is list:
+      for item in replacement:
+        if not contents[-1] == '/' and type(item) not in (str, int):
+          raise GypError('Variable ' + contents +
+                         ' must expand to a string or list of strings; ' +
+                         'list contains a ' +
+                         item.__class__.__name__)
+      # Run through the list and handle variable expansions in it.  Since
+      # the list is guaranteed not to contain dicts, this won't do anything
+      # with conditions sections.
+      ProcessVariablesAndConditionsInList(replacement, phase, variables,
+                                          build_file)
+    elif type(replacement) not in (str, int):
+          raise GypError('Variable ' + contents +
+                         ' must expand to a string or list of strings; ' +
+                         'found a ' + replacement.__class__.__name__)
+
+    if expand_to_list:
+      # Expanding in list context.  It's guaranteed that there's only one
+      # replacement to do in |input_str| and that it's this replacement.  See
+      # above.
+      if type(replacement) is list:
+        # If it's already a list, make a copy.
+        output = replacement[:]
+      else:
+        # Split it the same way sh would split arguments.
+        output = shlex.split(str(replacement))
+    else:
+      # Expanding in string context.
+      encoded_replacement = ''
+      if type(replacement) is list:
+        # When expanding a list into string context, turn the list items
+        # into a string in a way that will work with a subprocess call.
+        #
+        # TODO(mark): This isn't completely correct.  This should
+        # call a generator-provided function that observes the
+        # proper list-to-argument quoting rules on a specific
+        # platform instead of just calling the POSIX encoding
+        # routine.
+        encoded_replacement = gyp.common.EncodePOSIXShellList(replacement)
+      else:
+        encoded_replacement = replacement
+
+      output = output[:replace_start] + str(encoded_replacement) + \
+               output[replace_end:]
+    # Prepare for the next match iteration.
+    input_str = output
+
+  if output == input:
+    gyp.DebugOutput(gyp.DEBUG_VARIABLES,
+                    "Found only identity matches on %r, avoiding infinite "
+                    "recursion.",
+                    output)
+  else:
+    # Look for more matches now that we've replaced some, to deal with
+    # expanding local variables (variables defined in the same
+    # variables block as this one).
+    gyp.DebugOutput(gyp.DEBUG_VARIABLES, "Found output %r, recursing.", output)
+    if type(output) is list:
+      if output and type(output[0]) is list:
+        # Leave output alone if it's a list of lists.
+        # We don't want such lists to be stringified.
+        pass
+      else:
+        new_output = []
+        for item in output:
+          new_output.append(
+              ExpandVariables(item, phase, variables, build_file))
+        output = new_output
+    else:
+      output = ExpandVariables(output, phase, variables, build_file)
+
+  # Convert all strings that are canonically-represented integers into integers.
+  if type(output) is list:
+    for index in xrange(0, len(output)):
+      if IsStrCanonicalInt(output[index]):
+        output[index] = int(output[index])
+  elif IsStrCanonicalInt(output):
+    output = int(output)
+
+  return output
+
+# The same condition is often evaluated over and over again so it
+# makes sense to cache as much as possible between evaluations.
+cached_conditions_asts = {}
+
+def EvalCondition(condition, conditions_key, phase, variables, build_file):
+  """Returns the dict that should be used or None if the result was
+  that nothing should be used."""
+  if type(condition) is not list:
+    raise GypError(conditions_key + ' must be a list')
+  if len(condition) != 2 and len(condition) != 3:
+    # It's possible that condition[0] won't work in which case this
+    # attempt will raise its own IndexError.  That's probably fine.
+    raise GypError(conditions_key + ' ' + condition[0] +
+                   ' must be length 2 or 3, not ' + str(len(condition)))
+
+  [cond_expr, true_dict] = condition[0:2]
+  false_dict = None
+  if len(condition) == 3:
+    false_dict = condition[2]
+
+  # Do expansions on the condition itself.  Since the conditon can naturally
+  # contain variable references without needing to resort to GYP expansion
+  # syntax, this is of dubious value for variables, but someone might want to
+  # use a command expansion directly inside a condition.
+  cond_expr_expanded = ExpandVariables(cond_expr, phase, variables,
+                                       build_file)
+  if type(cond_expr_expanded) not in (str, int):
+    raise ValueError, \
+          'Variable expansion in this context permits str and int ' + \
+            'only, found ' + cond_expr_expanded.__class__.__name__
+
+  try:
+    if cond_expr_expanded in cached_conditions_asts:
+      ast_code = cached_conditions_asts[cond_expr_expanded]
+    else:
+      ast_code = compile(cond_expr_expanded, '<string>', 'eval')
+      cached_conditions_asts[cond_expr_expanded] = ast_code
+    if eval(ast_code, {'__builtins__': None}, variables):
+      return true_dict
+    return false_dict
+  except SyntaxError, e:
+    syntax_error = SyntaxError('%s while evaluating condition \'%s\' in %s '
+                               'at character %d.' %
+                               (str(e.args[0]), e.text, build_file, e.offset),
+                               e.filename, e.lineno, e.offset, e.text)
+    raise syntax_error
+  except NameError, e:
+    gyp.common.ExceptionAppend(e, 'while evaluating condition \'%s\' in %s' %
+                               (cond_expr_expanded, build_file))
+    raise GypError(e)
+
+
+def ProcessConditionsInDict(the_dict, phase, variables, build_file):
+  # Process a 'conditions' or 'target_conditions' section in the_dict,
+  # depending on phase.
+  # early -> conditions
+  # late -> target_conditions
+  # latelate -> no conditions
+  #
+  # Each item in a conditions list consists of cond_expr, a string expression
+  # evaluated as the condition, and true_dict, a dict that will be merged into
+  # the_dict if cond_expr evaluates to true.  Optionally, a third item,
+  # false_dict, may be present.  false_dict is merged into the_dict if
+  # cond_expr evaluates to false.
+  #
+  # Any dict merged into the_dict will be recursively processed for nested
+  # conditionals and other expansions, also according to phase, immediately
+  # prior to being merged.
+
+  if phase == PHASE_EARLY:
+    conditions_key = 'conditions'
+  elif phase == PHASE_LATE:
+    conditions_key = 'target_conditions'
+  elif phase == PHASE_LATELATE:
+    return
+  else:
+    assert False
+
+  if not conditions_key in the_dict:
+    return
+
+  conditions_list = the_dict[conditions_key]
+  # Unhook the conditions list, it's no longer needed.
+  del the_dict[conditions_key]
+
+  for condition in conditions_list:
+    merge_dict = EvalCondition(condition, conditions_key, phase, variables,
+                               build_file)
+
+    if merge_dict != None:
+      # Expand variables and nested conditinals in the merge_dict before
+      # merging it.
+      ProcessVariablesAndConditionsInDict(merge_dict, phase,
+                                          variables, build_file)
+
+      MergeDicts(the_dict, merge_dict, build_file, build_file)
+
+
+def LoadAutomaticVariablesFromDict(variables, the_dict):
+  # Any keys with plain string values in the_dict become automatic variables.
+  # The variable name is the key name with a "_" character prepended.
+  for key, value in the_dict.iteritems():
+    if type(value) in (str, int, list):
+      variables['_' + key] = value
+
+
+def LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key):
+  # Any keys in the_dict's "variables" dict, if it has one, becomes a
+  # variable.  The variable name is the key name in the "variables" dict.
+  # Variables that end with the % character are set only if they are unset in
+  # the variables dict.  the_dict_key is the name of the key that accesses
+  # the_dict in the_dict's parent dict.  If the_dict's parent is not a dict
+  # (it could be a list or it could be parentless because it is a root dict),
+  # the_dict_key will be None.
+  for key, value in the_dict.get('variables', {}).iteritems():
+    if type(value) not in (str, int, list):
+      continue
+
+    if key.endswith('%'):
+      variable_name = key[:-1]
+      if variable_name in variables:
+        # If the variable is already set, don't set it.
+        continue
+      if the_dict_key is 'variables' and variable_name in the_dict:
+        # If the variable is set without a % in the_dict, and the_dict is a
+        # variables dict (making |variables| a varaibles sub-dict of a
+        # variables dict), use the_dict's definition.
+        value = the_dict[variable_name]
+    else:
+      variable_name = key
+
+    variables[variable_name] = value
+
+
+def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in,
+                                        build_file, the_dict_key=None):
+  """Handle all variable and command expansion and conditional evaluation.
+
+  This function is the public entry point for all variable expansions and
+  conditional evaluations.  The variables_in dictionary will not be modified
+  by this function.
+  """
+
+  # Make a copy of the variables_in dict that can be modified during the
+  # loading of automatics and the loading of the variables dict.
+  variables = variables_in.copy()
+  LoadAutomaticVariablesFromDict(variables, the_dict)
+
+  if 'variables' in the_dict:
+    # Make sure all the local variables are added to the variables
+    # list before we process them so that you can reference one
+    # variable from another.  They will be fully expanded by recursion
+    # in ExpandVariables.
+    for key, value in the_dict['variables'].iteritems():
+      variables[key] = value
+
+    # Handle the associated variables dict first, so that any variable
+    # references within can be resolved prior to using them as variables.
+    # Pass a copy of the variables dict to avoid having it be tainted.
+    # Otherwise, it would have extra automatics added for everything that
+    # should just be an ordinary variable in this scope.
+    ProcessVariablesAndConditionsInDict(the_dict['variables'], phase,
+                                        variables, build_file, 'variables')
+
+  LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
+
+  for key, value in the_dict.iteritems():
+    # Skip "variables", which was already processed if present.
+    if key != 'variables' and type(value) is str:
+      expanded = ExpandVariables(value, phase, variables, build_file)
+      if type(expanded) not in (str, int):
+        raise ValueError, \
+              'Variable expansion in this context permits str and int ' + \
+              'only, found ' + expanded.__class__.__name__ + ' for ' + key
+      the_dict[key] = expanded
+
+  # Variable expansion may have resulted in changes to automatics.  Reload.
+  # TODO(mark): Optimization: only reload if no changes were made.
+  variables = variables_in.copy()
+  LoadAutomaticVariablesFromDict(variables, the_dict)
+  LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
+
+  # Process conditions in this dict.  This is done after variable expansion
+  # so that conditions may take advantage of expanded variables.  For example,
+  # if the_dict contains:
+  #   {'type':       '<(library_type)',
+  #    'conditions': [['_type=="static_library"', { ... }]]},
+  # _type, as used in the condition, will only be set to the value of
+  # library_type if variable expansion is performed before condition
+  # processing.  However, condition processing should occur prior to recursion
+  # so that variables (both automatic and "variables" dict type) may be
+  # adjusted by conditions sections, merged into the_dict, and have the
+  # intended impact on contained dicts.
+  #
+  # This arrangement means that a "conditions" section containing a "variables"
+  # section will only have those variables effective in subdicts, not in
+  # the_dict.  The workaround is to put a "conditions" section within a
+  # "variables" section.  For example:
+  #   {'conditions': [['os=="mac"', {'variables': {'define': 'IS_MAC'}}]],
+  #    'defines':    ['<(define)'],
+  #    'my_subdict': {'defines': ['<(define)']}},
+  # will not result in "IS_MAC" being appended to the "defines" list in the
+  # current scope but would result in it being appended to the "defines" list
+  # within "my_subdict".  By comparison:
+  #   {'variables': {'conditions': [['os=="mac"', {'define': 'IS_MAC'}]]},
+  #    'defines':    ['<(define)'],
+  #    'my_subdict': {'defines': ['<(define)']}},
+  # will append "IS_MAC" to both "defines" lists.
+
+  # Evaluate conditions sections, allowing variable expansions within them
+  # as well as nested conditionals.  This will process a 'conditions' or
+  # 'target_conditions' section, perform appropriate merging and recursive
+  # conditional and variable processing, and then remove the conditions section
+  # from the_dict if it is present.
+  ProcessConditionsInDict(the_dict, phase, variables, build_file)
+
+  # Conditional processing may have resulted in changes to automatics or the
+  # variables dict.  Reload.
+  variables = variables_in.copy()
+  LoadAutomaticVariablesFromDict(variables, the_dict)
+  LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
+
+  # Recurse into child dicts, or process child lists which may result in
+  # further recursion into descendant dicts.
+  for key, value in the_dict.iteritems():
+    # Skip "variables" and string values, which were already processed if
+    # present.
+    if key == 'variables' or type(value) is str:
+      continue
+    if type(value) is dict:
+      # Pass a copy of the variables dict so that subdicts can't influence
+      # parents.
+      ProcessVariablesAndConditionsInDict(value, phase, variables,
+                                          build_file, key)
+    elif type(value) is list:
+      # The list itself can't influence the variables dict, and
+      # ProcessVariablesAndConditionsInList will make copies of the variables
+      # dict if it needs to pass it to something that can influence it.  No
+      # copy is necessary here.
+      ProcessVariablesAndConditionsInList(value, phase, variables,
+                                          build_file)
+    elif type(value) is not int:
+      raise TypeError, 'Unknown type ' + value.__class__.__name__ + \
+                       ' for ' + key
+
+
+def ProcessVariablesAndConditionsInList(the_list, phase, variables,
+                                        build_file):
+  # Iterate using an index so that new values can be assigned into the_list.
+  index = 0
+  while index < len(the_list):
+    item = the_list[index]
+    if type(item) is dict:
+      # Make a copy of the variables dict so that it won't influence anything
+      # outside of its own scope.
+      ProcessVariablesAndConditionsInDict(item, phase, variables, build_file)
+    elif type(item) is list:
+      ProcessVariablesAndConditionsInList(item, phase, variables, build_file)
+    elif type(item) is str:
+      expanded = ExpandVariables(item, phase, variables, build_file)
+      if type(expanded) in (str, int):
+        the_list[index] = expanded
+      elif type(expanded) is list:
+        the_list[index:index+1] = expanded
+        index += len(expanded)
+
+        # index now identifies the next item to examine.  Continue right now
+        # without falling into the index increment below.
+        continue
+      else:
+        raise ValueError, \
+              'Variable expansion in this context permits strings and ' + \
+              'lists only, found ' + expanded.__class__.__name__ + ' at ' + \
+              index
+    elif type(item) is not int:
+      raise TypeError, 'Unknown type ' + item.__class__.__name__ + \
+                       ' at index ' + index
+    index = index + 1
+
+
+def BuildTargetsDict(data):
+  """Builds a dict mapping fully-qualified target names to their target dicts.
+
+  |data| is a dict mapping loaded build files by pathname relative to the
+  current directory.  Values in |data| are build file contents.  For each
+  |data| value with a "targets" key, the value of the "targets" key is taken
+  as a list containing target dicts.  Each target's fully-qualified name is
+  constructed from the pathname of the build file (|data| key) and its
+  "target_name" property.  These fully-qualified names are used as the keys
+  in the returned dict.  These keys provide access to the target dicts,
+  the dicts in the "targets" lists.
+  """
+
+  targets = {}
+  for build_file in data['target_build_files']:
+    for target in data[build_file].get('targets', []):
+      target_name = gyp.common.QualifiedTarget(build_file,
+                                               target['target_name'],
+                                               target['toolset'])
+      if target_name in targets:
+        raise GypError('Duplicate target definitions for ' + target_name)
+      targets[target_name] = target
+
+  return targets
+
+
+def QualifyDependencies(targets):
+  """Make dependency links fully-qualified relative to the current directory.
+
+  |targets| is a dict mapping fully-qualified target names to their target
+  dicts.  For each target in this dict, keys known to contain dependency
+  links are examined, and any dependencies referenced will be rewritten
+  so that they are fully-qualified and relative to the current directory.
+  All rewritten dependencies are suitable for use as keys to |targets| or a
+  similar dict.
+  """
+
+  all_dependency_sections = [dep + op
+                             for dep in dependency_sections
+                             for op in ('', '!', '/')]
+
+  for target, target_dict in targets.iteritems():
+    target_build_file = gyp.common.BuildFile(target)
+    toolset = target_dict['toolset']
+    for dependency_key in all_dependency_sections:
+      dependencies = target_dict.get(dependency_key, [])
+      for index in xrange(0, len(dependencies)):
+        dep_file, dep_target, dep_toolset = gyp.common.ResolveTarget(
+            target_build_file, dependencies[index], toolset)
+        if not multiple_toolsets:
+          # Ignore toolset specification in the dependency if it is specified.
+          dep_toolset = toolset
+        dependency = gyp.common.QualifiedTarget(dep_file,
+                                                dep_target,
+                                                dep_toolset)
+        dependencies[index] = dependency
+
+        # Make sure anything appearing in a list other than "dependencies" also
+        # appears in the "dependencies" list.
+        if dependency_key != 'dependencies' and \
+           dependency not in target_dict['dependencies']:
+          raise GypError('Found ' + dependency + ' in ' + dependency_key +
+                         ' of ' + target + ', but not in dependencies')
+
+
+def ExpandWildcardDependencies(targets, data):
+  """Expands dependencies specified as build_file:*.
+
+  For each target in |targets|, examines sections containing links to other
+  targets.  If any such section contains a link of the form build_file:*, it
+  is taken as a wildcard link, and is expanded to list each target in
+  build_file.  The |data| dict provides access to build file dicts.
+
+  Any target that does not wish to be included by wildcard can provide an
+  optional "suppress_wildcard" key in its target dict.  When present and
+  true, a wildcard dependency link will not include such targets.
+
+  All dependency names, including the keys to |targets| and the values in each
+  dependency list, must be qualified when this function is called.
+  """
+
+  for target, target_dict in targets.iteritems():
+    toolset = target_dict['toolset']
+    target_build_file = gyp.common.BuildFile(target)
+    for dependency_key in dependency_sections:
+      dependencies = target_dict.get(dependency_key, [])
+
+      # Loop this way instead of "for dependency in" or "for index in xrange"
+      # because the dependencies list will be modified within the loop body.
+      index = 0
+      while index < len(dependencies):
+        (dependency_build_file, dependency_target, dependency_toolset) = \
+            gyp.common.ParseQualifiedTarget(dependencies[index])
+        if dependency_target != '*' and dependency_toolset != '*':
+          # Not a wildcard.  Keep it moving.
+          index = index + 1
+          continue
+
+        if dependency_build_file == target_build_file:
+          # It's an error for a target to depend on all other targets in
+          # the same file, because a target cannot depend on itself.
+          raise GypError('Found wildcard in ' + dependency_key + ' of ' +
+                         target + ' referring to same build file')
+
+        # Take the wildcard out and adjust the index so that the next
+        # dependency in the list will be processed the next time through the
+        # loop.
+        del dependencies[index]
+        index = index - 1
+
+        # Loop through the targets in the other build file, adding them to
+        # this target's list of dependencies in place of the removed
+        # wildcard.
+        dependency_target_dicts = data[dependency_build_file]['targets']
+        for dependency_target_dict in dependency_target_dicts:
+          if int(dependency_target_dict.get('suppress_wildcard', False)):
+            continue
+          dependency_target_name = dependency_target_dict['target_name']
+          if (dependency_target != '*' and
+              dependency_target != dependency_target_name):
+            continue
+          dependency_target_toolset = dependency_target_dict['toolset']
+          if (dependency_toolset != '*' and
+              dependency_toolset != dependency_target_toolset):
+            continue
+          dependency = gyp.common.QualifiedTarget(dependency_build_file,
+                                                  dependency_target_name,
+                                                  dependency_target_toolset)
+          index = index + 1
+          dependencies.insert(index, dependency)
+
+        index = index + 1
+
+
+def Unify(l):
+  """Removes duplicate elements from l, keeping the first element."""
+  seen = {}
+  return [seen.setdefault(e, e) for e in l if e not in seen]
+
+
+def RemoveDuplicateDependencies(targets):
+  """Makes sure every dependency appears only once in all targets's dependency
+  lists."""
+  for target_name, target_dict in targets.iteritems():
+    for dependency_key in dependency_sections:
+      dependencies = target_dict.get(dependency_key, [])
+      if dependencies:
+        target_dict[dependency_key] = Unify(dependencies)
+
+
+def Filter(l, item):
+  """Removes item from l."""
+  res = {}
+  return [res.setdefault(e, e) for e in l if e != item]
+
+
+def RemoveSelfDependencies(targets):
+  """Remove self dependencies from targets that have the prune_self_dependency
+  variable set."""
+  for target_name, target_dict in targets.iteritems():
+    for dependency_key in dependency_sections:
+      dependencies = target_dict.get(dependency_key, [])
+      if dependencies:
+        for t in dependencies:
+          if t == target_name:
+            if targets[t].get('variables', {}).get('prune_self_dependency', 0):
+              target_dict[dependency_key] = Filter(dependencies, target_name)
+
+
+def RemoveLinkDependenciesFromNoneTargets(targets):
+  """Remove dependencies having the 'link_dependency' attribute from the 'none'
+  targets."""
+  for target_name, target_dict in targets.iteritems():
+    for dependency_key in dependency_sections:
+      dependencies = target_dict.get(dependency_key, [])
+      if dependencies:
+        for t in dependencies:
+          if target_dict.get('type', None) == 'none':
+            if targets[t].get('variables', {}).get('link_dependency', 0):
+              target_dict[dependency_key] = \
+                  Filter(target_dict[dependency_key], t)
+
+
+class DependencyGraphNode(object):
+  """
+
+  Attributes:
+    ref: A reference to an object that this DependencyGraphNode represents.
+    dependencies: List of DependencyGraphNodes on which this one depends.
+    dependents: List of DependencyGraphNodes that depend on this one.
+  """
+
+  class CircularException(GypError):
+    pass
+
+  def __init__(self, ref):
+    self.ref = ref
+    self.dependencies = []
+    self.dependents = []
+
+  def __repr__(self):
+    return '<DependencyGraphNode: %r>' % self.ref
+
+  def FlattenToList(self):
+    # flat_list is the sorted list of dependencies - actually, the list items
+    # are the "ref" attributes of DependencyGraphNodes.  Every target will
+    # appear in flat_list after all of its dependencies, and before all of its
+    # dependents.
+    flat_list = OrderedSet()
+
+    # in_degree_zeros is the list of DependencyGraphNodes that have no
+    # dependencies not in flat_list.  Initially, it is a copy of the children
+    # of this node, because when the graph was built, nodes with no
+    # dependencies were made implicit dependents of the root node.
+    in_degree_zeros = set(self.dependents[:])
+
+    while in_degree_zeros:
+      # Nodes in in_degree_zeros have no dependencies not in flat_list, so they
+      # can be appended to flat_list.  Take these nodes out of in_degree_zeros
+      # as work progresses, so that the next node to process from the list can
+      # always be accessed at a consistent position.
+      node = in_degree_zeros.pop()
+      flat_list.add(node.ref)
+
+      # Look at dependents of the node just added to flat_list.  Some of them
+      # may now belong in in_degree_zeros.
+      for node_dependent in node.dependents:
+        is_in_degree_zero = True
+        # TODO: We want to check through the
+        # node_dependent.dependencies list but if it's long and we
+        # always start at the beginning, then we get O(n^2) behaviour.
+        for node_dependent_dependency in node_dependent.dependencies:
+          if not node_dependent_dependency.ref in flat_list:
+            # The dependent one or more dependencies not in flat_list.  There
+            # will be more chances to add it to flat_list when examining
+            # it again as a dependent of those other dependencies, provided
+            # that there are no cycles.
+            is_in_degree_zero = False
+            break
+
+        if is_in_degree_zero:
+          # All of the dependent's dependencies are already in flat_list.  Add
+          # it to in_degree_zeros where it will be processed in a future
+          # iteration of the outer loop.
+          in_degree_zeros.add(node_dependent)
+
+    return list(flat_list)
+
+  def FindCycles(self, path=None):
+    """
+    Returns a list of cycles in the graph, where each cycle is its own list.
+    """
+    if path is None:
+      path = [self]
+
+    results = []
+    for node in self.dependents:
+      if node in path:
+        cycle = [node]
+        for part in path:
+          cycle.append(part)
+          if part == node:
+            break
+        results.append(tuple(cycle))
+      else:
+        results.extend(node.FindCycles([node] + path))
+
+    return list(set(results))
+
+  def DirectDependencies(self, dependencies=None):
+    """Returns a list of just direct dependencies."""
+    if dependencies == None:
+      dependencies = []
+
+    for dependency in self.dependencies:
+      # Check for None, corresponding to the root node.
+      if dependency.ref != None and dependency.ref not in dependencies:
+        dependencies.append(dependency.ref)
+
+    return dependencies
+
+  def _AddImportedDependencies(self, targets, dependencies=None):
+    """Given a list of direct dependencies, adds indirect dependencies that
+    other dependencies have declared to export their settings.
+
+    This method does not operate on self.  Rather, it operates on the list
+    of dependencies in the |dependencies| argument.  For each dependency in
+    that list, if any declares that it exports the settings of one of its
+    own dependencies, those dependencies whose settings are "passed through"
+    are added to the list.  As new items are added to the list, they too will
+    be processed, so it is possible to import settings through multiple levels
+    of dependencies.
+
+    This method is not terribly useful on its own, it depends on being
+    "primed" with a list of direct dependencies such as one provided by
+    DirectDependencies.  DirectAndImportedDependencies is intended to be the
+    public entry point.
+    """
+
+    if dependencies == None:
+      dependencies = []
+
+    index = 0
+    while index < len(dependencies):
+      dependency = dependencies[index]
+      dependency_dict = targets[dependency]
+      # Add any dependencies whose settings should be imported to the list
+      # if not already present.  Newly-added items will be checked for
+      # their own imports when the list iteration reaches them.
+      # Rather than simply appending new items, insert them after the
+      # dependency that exported them.  This is done to more closely match
+      # the depth-first method used by DeepDependencies.
+      add_index = 1
+      for imported_dependency in \
+          dependency_dict.get('export_dependent_settings', []):
+        if imported_dependency not in dependencies:
+          dependencies.insert(index + add_index, imported_dependency)
+          add_index = add_index + 1
+      index = index + 1
+
+    return dependencies
+
+  def DirectAndImportedDependencies(self, targets, dependencies=None):
+    """Returns a list of a target's direct dependencies and all indirect
+    dependencies that a dependency has advertised settings should be exported
+    through the dependency for.
+    """
+
+    dependencies = self.DirectDependencies(dependencies)
+    return self._AddImportedDependencies(targets, dependencies)
+
+  def DeepDependencies(self, dependencies=None):
+    """Returns an OrderedSet of all of a target's dependencies, recursively."""
+    if dependencies is None:
+      # Using a list to get ordered output and a set to do fast "is it
+      # already added" checks.
+      dependencies = OrderedSet()
+
+    for dependency in self.dependencies:
+      # Check for None, corresponding to the root node.
+      if dependency.ref is None:
+        continue
+      if dependency.ref not in dependencies:
+        dependencies.add(dependency.ref)
+        dependency.DeepDependencies(dependencies)
+
+    return dependencies
+
+  def _LinkDependenciesInternal(self, targets, include_shared_libraries,
+                                dependencies=None, initial=True):
+    """Returns an OrderedSet of dependency targets that are linked
+    into this target.
+
+    This function has a split personality, depending on the setting of
+    |initial|.  Outside callers should always leave |initial| at its default
+    setting.
+
+    When adding a target to the list of dependencies, this function will
+    recurse into itself with |initial| set to False, to collect dependencies
+    that are linked into the linkable target for which the list is being built.
+
+    If |include_shared_libraries| is False, the resulting dependencies will not
+    include shared_library targets that are linked into this target.
+    """
+    if dependencies is None:
+      # Using a list to get ordered output and a set to do fast "is it
+      # already added" checks.
+      dependencies = OrderedSet()
+
+    # Check for None, corresponding to the root node.
+    if self.ref is None:
+      return dependencies
+
+    # It's kind of sucky that |targets| has to be passed into this function,
+    # but that's presently the easiest way to access the target dicts so that
+    # this function can find target types.
+
+    if 'target_name' not in targets[self.ref]:
+      raise GypError("Missing 'target_name' field in target.")
+
+    if 'type' not in targets[self.ref]:
+      raise GypError("Missing 'type' field in target %s" %
+                     targets[self.ref]['target_name'])
+
+    target_type = targets[self.ref]['type']
+
+    is_linkable = target_type in linkable_types
+
+    if initial and not is_linkable:
+      # If this is the first target being examined and it's not linkable,
+      # return an empty list of link dependencies, because the link
+      # dependencies are intended to apply to the target itself (initial is
+      # True) and this target won't be linked.
+      return dependencies
+
+    # Don't traverse 'none' targets if explicitly excluded.
+    if (target_type == 'none' and
+        not targets[self.ref].get('dependencies_traverse', True)):
+      dependencies.add(self.ref)
+      return dependencies
+
+    # Executables and loadable modules are already fully and finally linked.
+    # Nothing else can be a link dependency of them, there can only be
+    # dependencies in the sense that a dependent target might run an
+    # executable or load the loadable_module.
+    if not initial and target_type in ('executable', 'loadable_module'):
+      return dependencies
+
+    # Shared libraries are already fully linked.  They should only be included
+    # in |dependencies| when adjusting static library dependencies (in order to
+    # link against the shared_library's import lib), but should not be included
+    # in |dependencies| when propagating link_settings.
+    # The |include_shared_libraries| flag controls which of these two cases we
+    # are handling.
+    if (not initial and target_type == 'shared_library' and
+        not include_shared_libraries):
+      return dependencies
+
+    # The target is linkable, add it to the list of link dependencies.
+    if self.ref not in dependencies:
+      dependencies.add(self.ref)
+      if initial or not is_linkable:
+        # If this is a subsequent target and it's linkable, don't look any
+        # further for linkable dependencies, as they'll already be linked into
+        # this target linkable.  Always look at dependencies of the initial
+        # target, and always look at dependencies of non-linkables.
+        for dependency in self.dependencies:
+          dependency._LinkDependenciesInternal(targets,
+                                               include_shared_libraries,
+                                               dependencies, False)
+
+    return dependencies
+
+  def DependenciesForLinkSettings(self, targets):
+    """
+    Returns a list of dependency targets whose link_settings should be merged
+    into this target.
+    """
+
+    # TODO(sbaig) Currently, chrome depends on the bug that shared libraries'
+    # link_settings are propagated.  So for now, we will allow it, unless the
+    # 'allow_sharedlib_linksettings_propagation' flag is explicitly set to
+    # False.  Once chrome is fixed, we can remove this flag.
+    include_shared_libraries = \
+        targets[self.ref].get('allow_sharedlib_linksettings_propagation', True)
+    return self._LinkDependenciesInternal(targets, include_shared_libraries)
+
+  def DependenciesToLinkAgainst(self, targets):
+    """
+    Returns a list of dependency targets that are linked into this target.
+    """
+    return self._LinkDependenciesInternal(targets, True)
+
+
+def BuildDependencyList(targets):
+  # Create a DependencyGraphNode for each target.  Put it into a dict for easy
+  # access.
+  dependency_nodes = {}
+  for target, spec in targets.iteritems():
+    if target not in dependency_nodes:
+      dependency_nodes[target] = DependencyGraphNode(target)
+
+  # Set up the dependency links.  Targets that have no dependencies are treated
+  # as dependent on root_node.
+  root_node = DependencyGraphNode(None)
+  for target, spec in targets.iteritems():
+    target_node = dependency_nodes[target]
+    target_build_file = gyp.common.BuildFile(target)
+    dependencies = spec.get('dependencies')
+    if not dependencies:
+      target_node.dependencies = [root_node]
+      root_node.dependents.append(target_node)
+    else:
+      for dependency in dependencies:
+        dependency_node = dependency_nodes.get(dependency)
+        if not dependency_node:
+          raise GypError("Dependency '%s' not found while "
+                         "trying to load target %s" % (dependency, target))
+        target_node.dependencies.append(dependency_node)
+        dependency_node.dependents.append(target_node)
+
+  flat_list = root_node.FlattenToList()
+
+  # If there's anything left unvisited, there must be a circular dependency
+  # (cycle).  If you need to figure out what's wrong, look for elements of
+  # targets that are not in flat_list.
+  if len(flat_list) != len(targets):
+    raise DependencyGraphNode.CircularException(
+        'Some targets not reachable, cycle in dependency graph detected: ' +
+        ' '.join(set(flat_list) ^ set(targets)))
+
+  return [dependency_nodes, flat_list]
+
+
+def VerifyNoGYPFileCircularDependencies(targets):
+  # Create a DependencyGraphNode for each gyp file containing a target.  Put
+  # it into a dict for easy access.
+  dependency_nodes = {}
+  for target in targets.iterkeys():
+    build_file = gyp.common.BuildFile(target)
+    if not build_file in dependency_nodes:
+      dependency_nodes[build_file] = DependencyGraphNode(build_file)
+
+  # Set up the dependency links.
+  for target, spec in targets.iteritems():
+    build_file = gyp.common.BuildFile(target)
+    build_file_node = dependency_nodes[build_file]
+    target_dependencies = spec.get('dependencies', [])
+    for dependency in target_dependencies:
+      try:
+        dependency_build_file = gyp.common.BuildFile(dependency)
+      except GypError, e:
+        gyp.common.ExceptionAppend(
+            e, 'while computing dependencies of .gyp file %s' % build_file)
+        raise
+
+      if dependency_build_file == build_file:
+        # A .gyp file is allowed to refer back to itself.
+        continue
+      dependency_node = dependency_nodes.get(dependency_build_file)
+      if not dependency_node:
+        raise GypError("Dependancy '%s' not found" % dependency_build_file)
+      if dependency_node not in build_file_node.dependencies:
+        build_file_node.dependencies.append(dependency_node)
+        dependency_node.dependents.append(build_file_node)
+
+
+  # Files that have no dependencies are treated as dependent on root_node.
+  root_node = DependencyGraphNode(None)
+  for build_file_node in dependency_nodes.itervalues():
+    if len(build_file_node.dependencies) == 0:
+      build_file_node.dependencies.append(root_node)
+      root_node.dependents.append(build_file_node)
+
+  flat_list = root_node.FlattenToList()
+
+  # If there's anything left unvisited, there must be a circular dependency
+  # (cycle).
+  if len(flat_list) != len(dependency_nodes):
+    bad_files = []
+    for file in dependency_nodes.iterkeys():
+      if not file in flat_list:
+        bad_files.append(file)
+    common_path_prefix = os.path.commonprefix(dependency_nodes)
+    cycles = []
+    for cycle in root_node.FindCycles():
+      simplified_paths = []
+      for node in cycle:
+        assert(node.ref.startswith(common_path_prefix))
+        simplified_paths.append(node.ref[len(common_path_prefix):])
+      cycles.append('Cycle: %s' % ' -> '.join(simplified_paths))
+    raise DependencyGraphNode.CircularException, \
+        'Cycles in .gyp file dependency graph detected:\n' + '\n'.join(cycles)
+
+
+def DoDependentSettings(key, flat_list, targets, dependency_nodes):
+  # key should be one of all_dependent_settings, direct_dependent_settings,
+  # or link_settings.
+
+  for target in flat_list:
+    target_dict = targets[target]
+    build_file = gyp.common.BuildFile(target)
+
+    if key == 'all_dependent_settings':
+      dependencies = dependency_nodes[target].DeepDependencies()
+    elif key == 'direct_dependent_settings':
+      dependencies = \
+          dependency_nodes[target].DirectAndImportedDependencies(targets)
+    elif key == 'link_settings':
+      dependencies = \
+          dependency_nodes[target].DependenciesForLinkSettings(targets)
+    else:
+      raise GypError("DoDependentSettings doesn't know how to determine "
+                      'dependencies for ' + key)
+
+    for dependency in dependencies:
+      dependency_dict = targets[dependency]
+      if not key in dependency_dict:
+        continue
+      dependency_build_file = gyp.common.BuildFile(dependency)
+      MergeDicts(target_dict, dependency_dict[key],
+                 build_file, dependency_build_file)
+
+
+def AdjustStaticLibraryDependencies(flat_list, targets, dependency_nodes,
+                                    sort_dependencies):
+  # Recompute target "dependencies" properties.  For each static library
+  # target, remove "dependencies" entries referring to other static libraries,
+  # unless the dependency has the "hard_dependency" attribute set.  For each
+  # linkable target, add a "dependencies" entry referring to all of the
+  # target's computed list of link dependencies (including static libraries
+  # if no such entry is already present.
+  for target in flat_list:
+    target_dict = targets[target]
+    target_type = target_dict['type']
+
+    if target_type == 'static_library':
+      if not 'dependencies' in target_dict:
+        continue
+
+      target_dict['dependencies_original'] = target_dict.get(
+          'dependencies', [])[:]
+
+      # A static library should not depend on another static library unless
+      # the dependency relationship is "hard," which should only be done when
+      # a dependent relies on some side effect other than just the build
+      # product, like a rule or action output. Further, if a target has a
+      # non-hard dependency, but that dependency exports a hard dependency,
+      # the non-hard dependency can safely be removed, but the exported hard
+      # dependency must be added to the target to keep the same dependency
+      # ordering.
+      dependencies = \
+          dependency_nodes[target].DirectAndImportedDependencies(targets)
+      index = 0
+      while index < len(dependencies):
+        dependency = dependencies[index]
+        dependency_dict = targets[dependency]
+
+        # Remove every non-hard static library dependency and remove every
+        # non-static library dependency that isn't a direct dependency.
+        if (dependency_dict['type'] == 'static_library' and \
+            not dependency_dict.get('hard_dependency', False)) or \
+           (dependency_dict['type'] != 'static_library' and \
+            not dependency in target_dict['dependencies']):
+          # Take the dependency out of the list, and don't increment index
+          # because the next dependency to analyze will shift into the index
+          # formerly occupied by the one being removed.
+          del dependencies[index]
+        else:
+          index = index + 1
+
+      # Update the dependencies. If the dependencies list is empty, it's not
+      # needed, so unhook it.
+      if len(dependencies) > 0:
+        target_dict['dependencies'] = dependencies
+      else:
+        del target_dict['dependencies']
+
+    elif target_type in linkable_types:
+      # Get a list of dependency targets that should be linked into this
+      # target.  Add them to the dependencies list if they're not already
+      # present.
+
+      link_dependencies = \
+          dependency_nodes[target].DependenciesToLinkAgainst(targets)
+      for dependency in link_dependencies:
+        if dependency == target:
+          continue
+        if not 'dependencies' in target_dict:
+          target_dict['dependencies'] = []
+        if not dependency in target_dict['dependencies']:
+          target_dict['dependencies'].append(dependency)
+      # Sort the dependencies list in the order from dependents to dependencies.
+      # e.g. If A and B depend on C and C depends on D, sort them in A, B, C, D.
+      # Note: flat_list is already sorted in the order from dependencies to
+      # dependents.
+      if sort_dependencies and 'dependencies' in target_dict:
+        target_dict['dependencies'] = [dep for dep in reversed(flat_list)
+                                       if dep in target_dict['dependencies']]
+
+
+# Initialize this here to speed up MakePathRelative.
+exception_re = re.compile(r'''["']?[-/$<>^]''')
+
+
+def MakePathRelative(to_file, fro_file, item):
+  # If item is a relative path, it's relative to the build file dict that it's
+  # coming from.  Fix it up to make it relative to the build file dict that
+  # it's going into.
+  # Exception: any |item| that begins with these special characters is
+  # returned without modification.
+  #   /   Used when a path is already absolute (shortcut optimization;
+  #       such paths would be returned as absolute anyway)
+  #   $   Used for build environment variables
+  #   -   Used for some build environment flags (such as -lapr-1 in a
+  #       "libraries" section)
+  #   <   Used for our own variable and command expansions (see ExpandVariables)
+  #   >   Used for our own variable and command expansions (see ExpandVariables)
+  #   ^   Used for our own variable and command expansions (see ExpandVariables)
+  #
+  #   "/' Used when a value is quoted.  If these are present, then we
+  #       check the second character instead.
+  #
+  if to_file == fro_file or exception_re.match(item):
+    return item
+  else:
+    # TODO(dglazkov) The backslash/forward-slash replacement at the end is a
+    # temporary measure. This should really be addressed by keeping all paths
+    # in POSIX until actual project generation.
+    ret = os.path.normpath(os.path.join(
+        gyp.common.RelativePath(os.path.dirname(fro_file),
+                                os.path.dirname(to_file)),
+                                item)).replace('\\', '/')
+    if item[-1] == '/':
+      ret += '/'
+    return ret
+
+def MergeLists(to, fro, to_file, fro_file, is_paths=False, append=True):
+  # Python documentation recommends objects which do not support hash
+  # set this value to None. Python library objects follow this rule.
+  is_hashable = lambda val: val.__hash__
+
+  # If x is hashable, returns whether x is in s. Else returns whether x is in l.
+  def is_in_set_or_list(x, s, l):
+    if is_hashable(x):
+      return x in s
+    return x in l
+
+  prepend_index = 0
+
+  # Make membership testing of hashables in |to| (in particular, strings)
+  # faster.
+  hashable_to_set = set(x for x in to if is_hashable(x))
+  for item in fro:
+    singleton = False
+    if type(item) in (str, int):
+      # The cheap and easy case.
+      if is_paths:
+        to_item = MakePathRelative(to_file, fro_file, item)
+      else:
+        to_item = item
+
+      if not (type(item) is str and item.startswith('-')):
+        # Any string that doesn't begin with a "-" is a singleton - it can
+        # only appear once in a list, to be enforced by the list merge append
+        # or prepend.
+        singleton = True
+    elif type(item) is dict:
+      # Make a copy of the dictionary, continuing to look for paths to fix.
+      # The other intelligent aspects of merge processing won't apply because
+      # item is being merged into an empty dict.
+      to_item = {}
+      MergeDicts(to_item, item, to_file, fro_file)
+    elif type(item) is list:
+      # Recurse, making a copy of the list.  If the list contains any
+      # descendant dicts, path fixing will occur.  Note that here, custom
+      # values for is_paths and append are dropped; those are only to be
+      # applied to |to| and |fro|, not sublists of |fro|.  append shouldn't
+      # matter anyway because the new |to_item| list is empty.
+      to_item = []
+      MergeLists(to_item, item, to_file, fro_file)
+    else:
+      raise TypeError, \
+          'Attempt to merge list item of unsupported type ' + \
+          item.__class__.__name__
+
+    if append:
+      # If appending a singleton that's already in the list, don't append.
+      # This ensures that the earliest occurrence of the item will stay put.
+      if not singleton or not is_in_set_or_list(to_item, hashable_to_set, to):
+        to.append(to_item)
+        if is_hashable(to_item):
+          hashable_to_set.add(to_item)
+    else:
+      # If prepending a singleton that's already in the list, remove the
+      # existing instance and proceed with the prepend.  This ensures that the
+      # item appears at the earliest possible position in the list.
+      while singleton and to_item in to:
+        to.remove(to_item)
+
+      # Don't just insert everything at index 0.  That would prepend the new
+      # items to the list in reverse order, which would be an unwelcome
+      # surprise.
+      to.insert(prepend_index, to_item)
+      if is_hashable(to_item):
+        hashable_to_set.add(to_item)
+      prepend_index = prepend_index + 1
+
+
+def MergeDicts(to, fro, to_file, fro_file):
+  # I wanted to name the parameter "from" but it's a Python keyword...
+  for k, v in fro.iteritems():
+    # It would be nice to do "if not k in to: to[k] = v" but that wouldn't give
+    # copy semantics.  Something else may want to merge from the |fro| dict
+    # later, and having the same dict ref pointed to twice in the tree isn't
+    # what anyone wants considering that the dicts may subsequently be
+    # modified.
+    if k in to:
+      bad_merge = False
+      if type(v) in (str, int):
+        if type(to[k]) not in (str, int):
+          bad_merge = True
+      elif type(v) is not type(to[k]):
+        bad_merge = True
+
+      if bad_merge:
+        raise TypeError, \
+            'Attempt to merge dict value of type ' + v.__class__.__name__ + \
+            ' into incompatible type ' + to[k].__class__.__name__ + \
+            ' for key ' + k
+    if type(v) in (str, int):
+      # Overwrite the existing value, if any.  Cheap and easy.
+      is_path = IsPathSection(k)
+      if is_path:
+        to[k] = MakePathRelative(to_file, fro_file, v)
+      else:
+        to[k] = v
+    elif type(v) is dict:
+      # Recurse, guaranteeing copies will be made of objects that require it.
+      if not k in to:
+        to[k] = {}
+      MergeDicts(to[k], v, to_file, fro_file)
+    elif type(v) is list:
+      # Lists in dicts can be merged with different policies, depending on
+      # how the key in the "from" dict (k, the from-key) is written.
+      #
+      # If the from-key has          ...the to-list will have this action
+      # this character appended:...     applied when receiving the from-list:
+      #                           =  replace
+      #                           +  prepend
+      #                           ?  set, only if to-list does not yet exist
+      #                      (none)  append
+      #
+      # This logic is list-specific, but since it relies on the associated
+      # dict key, it's checked in this dict-oriented function.
+      ext = k[-1]
+      append = True
+      if ext == '=':
+        list_base = k[:-1]
+        lists_incompatible = [list_base, list_base + '?']
+        to[list_base] = []
+      elif ext == '+':
+        list_base = k[:-1]
+        lists_incompatible = [list_base + '=', list_base + '?']
+        append = False
+      elif ext == '?':
+        list_base = k[:-1]
+        lists_incompatible = [list_base, list_base + '=', list_base + '+']
+      else:
+        list_base = k
+        lists_incompatible = [list_base + '=', list_base + '?']
+
+      # Some combinations of merge policies appearing together are meaningless.
+      # It's stupid to replace and append simultaneously, for example.  Append
+      # and prepend are the only policies that can coexist.
+      for list_incompatible in lists_incompatible:
+        if list_incompatible in fro:
+          raise GypError('Incompatible list policies ' + k + ' and ' +
+                         list_incompatible)
+
+      if list_base in to:
+        if ext == '?':
+          # If the key ends in "?", the list will only be merged if it doesn't
+          # already exist.
+          continue
+        elif type(to[list_base]) is not list:
+          # This may not have been checked above if merging in a list with an
+          # extension character.
+          raise TypeError, \
+              'Attempt to merge dict value of type ' + v.__class__.__name__ + \
+              ' into incompatible type ' + to[list_base].__class__.__name__ + \
+              ' for key ' + list_base + '(' + k + ')'
+      else:
+        to[list_base] = []
+
+      # Call MergeLists, which will make copies of objects that require it.
+      # MergeLists can recurse back into MergeDicts, although this will be
+      # to make copies of dicts (with paths fixed), there will be no
+      # subsequent dict "merging" once entering a list because lists are
+      # always replaced, appended to, or prepended to.
+      is_paths = IsPathSection(list_base)
+      MergeLists(to[list_base], v, to_file, fro_file, is_paths, append)
+    else:
+      raise TypeError, \
+          'Attempt to merge dict value of unsupported type ' + \
+          v.__class__.__name__ + ' for key ' + k
+
+
+def MergeConfigWithInheritance(new_configuration_dict, build_file,
+                               target_dict, configuration, visited):
+  # Skip if previously visted.
+  if configuration in visited:
+    return
+
+  # Look at this configuration.
+  configuration_dict = target_dict['configurations'][configuration]
+
+  # Merge in parents.
+  for parent in configuration_dict.get('inherit_from', []):
+    MergeConfigWithInheritance(new_configuration_dict, build_file,
+                               target_dict, parent, visited + [configuration])
+
+  # Merge it into the new config.
+  MergeDicts(new_configuration_dict, configuration_dict,
+             build_file, build_file)
+
+  # Drop abstract.
+  if 'abstract' in new_configuration_dict:
+    del new_configuration_dict['abstract']
+
+
+def SetUpConfigurations(target, target_dict):
+  # key_suffixes is a list of key suffixes that might appear on key names.
+  # These suffixes are handled in conditional evaluations (for =, +, and ?)
+  # and rules/exclude processing (for ! and /).  Keys with these suffixes
+  # should be treated the same as keys without.
+  key_suffixes = ['=', '+', '?', '!', '/']
+
+  build_file = gyp.common.BuildFile(target)
+
+  # Provide a single configuration by default if none exists.
+  # TODO(mark): Signal an error if default_configurations exists but
+  # configurations does not.
+  if not 'configurations' in target_dict:
+    target_dict['configurations'] = {'Default': {}}
+  if not 'default_configuration' in target_dict:
+    concrete = [i for (i, config) in target_dict['configurations'].iteritems()
+                if not config.get('abstract')]
+    target_dict['default_configuration'] = sorted(concrete)[0]
+
+  merged_configurations = {}
+  configs = target_dict['configurations']
+  for (configuration, old_configuration_dict) in configs.iteritems():
+    # Skip abstract configurations (saves work only).
+    if old_configuration_dict.get('abstract'):
+      continue
+    # Configurations inherit (most) settings from the enclosing target scope.
+    # Get the inheritance relationship right by making a copy of the target
+    # dict.
+    new_configuration_dict = {}
+    for (key, target_val) in target_dict.iteritems():
+      key_ext = key[-1:]
+      if key_ext in key_suffixes:
+        key_base = key[:-1]
+      else:
+        key_base = key
+      if not key_base in non_configuration_keys:
+        new_configuration_dict[key] = gyp.simple_copy.deepcopy(target_val)
+
+    # Merge in configuration (with all its parents first).
+    MergeConfigWithInheritance(new_configuration_dict, build_file,
+                               target_dict, configuration, [])
+
+    merged_configurations[configuration] = new_configuration_dict
+
+  # Put the new configurations back into the target dict as a configuration.
+  for configuration in merged_configurations.keys():
+    target_dict['configurations'][configuration] = (
+        merged_configurations[configuration])
+
+  # Now drop all the abstract ones.
+  for configuration in target_dict['configurations'].keys():
+    old_configuration_dict = target_dict['configurations'][configuration]
+    if old_configuration_dict.get('abstract'):
+      del target_dict['configurations'][configuration]
+
+  # Now that all of the target's configurations have been built, go through
+  # the target dict's keys and remove everything that's been moved into a
+  # "configurations" section.
+  delete_keys = []
+  for key in target_dict:
+    key_ext = key[-1:]
+    if key_ext in key_suffixes:
+      key_base = key[:-1]
+    else:
+      key_base = key
+    if not key_base in non_configuration_keys:
+      delete_keys.append(key)
+  for key in delete_keys:
+    del target_dict[key]
+
+  # Check the configurations to see if they contain invalid keys.
+  for configuration in target_dict['configurations'].keys():
+    configuration_dict = target_dict['configurations'][configuration]
+    for key in configuration_dict.keys():
+      if key in invalid_configuration_keys:
+        raise GypError('%s not allowed in the %s configuration, found in '
+                       'target %s' % (key, configuration, target))
+
+
+
+def ProcessListFiltersInDict(name, the_dict):
+  """Process regular expression and exclusion-based filters on lists.
+
+  An exclusion list is in a dict key named with a trailing "!", like
+  "sources!".  Every item in such a list is removed from the associated
+  main list, which in this example, would be "sources".  Removed items are
+  placed into a "sources_excluded" list in the dict.
+
+  Regular expression (regex) filters are contained in dict keys named with a
+  trailing "/", such as "sources/" to operate on the "sources" list.  Regex
+  filters in a dict take the form:
+    'sources/': [ ['exclude', '_(linux|mac|win)\\.cc$'],
+                  ['include', '_mac\\.cc$'] ],
+  The first filter says to exclude all files ending in _linux.cc, _mac.cc, and
+  _win.cc.  The second filter then includes all files ending in _mac.cc that
+  are now or were once in the "sources" list.  Items matching an "exclude"
+  filter are subject to the same processing as would occur if they were listed
+  by name in an exclusion list (ending in "!").  Items matching an "include"
+  filter are brought back into the main list if previously excluded by an
+  exclusion list or exclusion regex filter.  Subsequent matching "exclude"
+  patterns can still cause items to be excluded after matching an "include".
+  """
+
+  # Look through the dictionary for any lists whose keys end in "!" or "/".
+  # These are lists that will be treated as exclude lists and regular
+  # expression-based exclude/include lists.  Collect the lists that are
+  # needed first, looking for the lists that they operate on, and assemble
+  # then into |lists|.  This is done in a separate loop up front, because
+  # the _included and _excluded keys need to be added to the_dict, and that
+  # can't be done while iterating through it.
+
+  lists = []
+  del_lists = []
+  for key, value in the_dict.iteritems():
+    operation = key[-1]
+    if operation != '!' and operation != '/':
+      continue
+
+    if type(value) is not list:
+      raise ValueError, name + ' key ' + key + ' must be list, not ' + \
+                        value.__class__.__name__
+
+    list_key = key[:-1]
+    if list_key not in the_dict:
+      # This happens when there's a list like "sources!" but no corresponding
+      # "sources" list.  Since there's nothing for it to operate on, queue up
+      # the "sources!" list for deletion now.
+      del_lists.append(key)
+      continue
+
+    if type(the_dict[list_key]) is not list:
+      value = the_dict[list_key]
+      raise ValueError, name + ' key ' + list_key + \
+                        ' must be list, not ' + \
+                        value.__class__.__name__ + ' when applying ' + \
+                        {'!': 'exclusion', '/': 'regex'}[operation]
+
+    if not list_key in lists:
+      lists.append(list_key)
+
+  # Delete the lists that are known to be unneeded at this point.
+  for del_list in del_lists:
+    del the_dict[del_list]
+
+  for list_key in lists:
+    the_list = the_dict[list_key]
+
+    # Initialize the list_actions list, which is parallel to the_list.  Each
+    # item in list_actions identifies whether the corresponding item in
+    # the_list should be excluded, unconditionally preserved (included), or
+    # whether no exclusion or inclusion has been applied.  Items for which
+    # no exclusion or inclusion has been applied (yet) have value -1, items
+    # excluded have value 0, and items included have value 1.  Includes and
+    # excludes override previous actions.  All items in list_actions are
+    # initialized to -1 because no excludes or includes have been processed
+    # yet.
+    list_actions = list((-1,) * len(the_list))
+
+    exclude_key = list_key + '!'
+    if exclude_key in the_dict:
+      for exclude_item in the_dict[exclude_key]:
+        for index in xrange(0, len(the_list)):
+          if exclude_item == the_list[index]:
+            # This item matches the exclude_item, so set its action to 0
+            # (exclude).
+            list_actions[index] = 0
+
+      # The "whatever!" list is no longer needed, dump it.
+      del the_dict[exclude_key]
+
+    regex_key = list_key + '/'
+    if regex_key in the_dict:
+      for regex_item in the_dict[regex_key]:
+        [action, pattern] = regex_item
+        pattern_re = re.compile(pattern)
+
+        if action == 'exclude':
+          # This item matches an exclude regex, so set its value to 0 (exclude).
+          action_value = 0
+        elif action == 'include':
+          # This item matches an include regex, so set its value to 1 (include).
+          action_value = 1
+        else:
+          # This is an action that doesn't make any sense.
+          raise ValueError, 'Unrecognized action ' + action + ' in ' + name + \
+                            ' key ' + regex_key
+
+        for index in xrange(0, len(the_list)):
+          list_item = the_list[index]
+          if list_actions[index] == action_value:
+            # Even if the regex matches, nothing will change so continue (regex
+            # searches are expensive).
+            continue
+          if pattern_re.search(list_item):
+            # Regular expression match.
+            list_actions[index] = action_value
+
+      # The "whatever/" list is no longer needed, dump it.
+      del the_dict[regex_key]
+
+    # Add excluded items to the excluded list.
+    #
+    # Note that exclude_key ("sources!") is different from excluded_key
+    # ("sources_excluded").  The exclude_key list is input and it was already
+    # processed and deleted; the excluded_key list is output and it's about
+    # to be created.
+    excluded_key = list_key + '_excluded'
+    if excluded_key in the_dict:
+      raise GypError(name + ' key ' + excluded_key +
+                     ' must not be present prior '
+                     ' to applying exclusion/regex filters for ' + list_key)
+
+    excluded_list = []
+
+    # Go backwards through the list_actions list so that as items are deleted,
+    # the indices of items that haven't been seen yet don't shift.  That means
+    # that things need to be prepended to excluded_list to maintain them in the
+    # same order that they existed in the_list.
+    for index in xrange(len(list_actions) - 1, -1, -1):
+      if list_actions[index] == 0:
+        # Dump anything with action 0 (exclude).  Keep anything with action 1
+        # (include) or -1 (no include or exclude seen for the item).
+        excluded_list.insert(0, the_list[index])
+        del the_list[index]
+
+    # If anything was excluded, put the excluded list into the_dict at
+    # excluded_key.
+    if len(excluded_list) > 0:
+      the_dict[excluded_key] = excluded_list
+
+  # Now recurse into subdicts and lists that may contain dicts.
+  for key, value in the_dict.iteritems():
+    if type(value) is dict:
+      ProcessListFiltersInDict(key, value)
+    elif type(value) is list:
+      ProcessListFiltersInList(key, value)
+
+
+def ProcessListFiltersInList(name, the_list):
+  for item in the_list:
+    if type(item) is dict:
+      ProcessListFiltersInDict(name, item)
+    elif type(item) is list:
+      ProcessListFiltersInList(name, item)
+
+
+def ValidateTargetType(target, target_dict):
+  """Ensures the 'type' field on the target is one of the known types.
+
+  Arguments:
+    target: string, name of target.
+    target_dict: dict, target spec.
+
+  Raises an exception on error.
+  """
+  VALID_TARGET_TYPES = ('executable', 'loadable_module',
+                        'static_library', 'shared_library',
+                        'none')
+  target_type = target_dict.get('type', None)
+  if target_type not in VALID_TARGET_TYPES:
+    raise GypError("Target %s has an invalid target type '%s'.  "
+                   "Must be one of %s." %
+                   (target, target_type, '/'.join(VALID_TARGET_TYPES)))
+  if (target_dict.get('standalone_static_library', 0) and
+      not target_type == 'static_library'):
+    raise GypError('Target %s has type %s but standalone_static_library flag is'
+                   ' only valid for static_library type.' % (target,
+                                                             target_type))
+
+
+def ValidateSourcesInTarget(target, target_dict, build_file,
+                            duplicate_basename_check):
+  if not duplicate_basename_check:
+    return
+  # TODO: Check if MSVC allows this for loadable_module targets.
+  if target_dict.get('type', None) not in ('static_library', 'shared_library'):
+    return
+  sources = target_dict.get('sources', [])
+  basenames = {}
+  for source in sources:
+    name, ext = os.path.splitext(source)
+    is_compiled_file = ext in [
+        '.c', '.cc', '.cpp', '.cxx', '.m', '.mm', '.s', '.S']
+    if not is_compiled_file:
+      continue
+    basename = os.path.basename(name)  # Don't include extension.
+    basenames.setdefault(basename, []).append(source)
+
+  error = ''
+  for basename, files in basenames.iteritems():
+    if len(files) > 1:
+      error += '  %s: %s\n' % (basename, ' '.join(files))
+
+  if error:
+    print('static library %s has several files with the same basename:\n' %
+          target + error + 'Some build systems, e.g. MSVC08 and Make generator '
+          'for Mac, cannot handle that. Use --no-duplicate-basename-check to'
+          'disable this validation.')
+    raise GypError('Duplicate basenames in sources section, see list above')
+
+
+def ValidateRulesInTarget(target, target_dict, extra_sources_for_rules):
+  """Ensures that the rules sections in target_dict are valid and consistent,
+  and determines which sources they apply to.
+
+  Arguments:
+    target: string, name of target.
+    target_dict: dict, target spec containing "rules" and "sources" lists.
+    extra_sources_for_rules: a list of keys to scan for rule matches in
+        addition to 'sources'.
+  """
+
+  # Dicts to map between values found in rules' 'rule_name' and 'extension'
+  # keys and the rule dicts themselves.
+  rule_names = {}
+  rule_extensions = {}
+
+  rules = target_dict.get('rules', [])
+  for rule in rules:
+    # Make sure that there's no conflict among rule names and extensions.
+    rule_name = rule['rule_name']
+    if rule_name in rule_names:
+      raise GypError('rule %s exists in duplicate, target %s' %
+                     (rule_name, target))
+    rule_names[rule_name] = rule
+
+    rule_extension = rule['extension']
+    if rule_extension.startswith('.'):
+      rule_extension = rule_extension[1:]
+    if rule_extension in rule_extensions:
+      raise GypError(('extension %s associated with multiple rules, ' +
+                      'target %s rules %s and %s') %
+                     (rule_extension, target,
+                      rule_extensions[rule_extension]['rule_name'],
+                      rule_name))
+    rule_extensions[rule_extension] = rule
+
+    # Make sure rule_sources isn't already there.  It's going to be
+    # created below if needed.
+    if 'rule_sources' in rule:
+      raise GypError(
+            'rule_sources must not exist in input, target %s rule %s' %
+            (target, rule_name))
+
+    rule_sources = []
+    source_keys = ['sources']
+    source_keys.extend(extra_sources_for_rules)
+    for source_key in source_keys:
+      for source in target_dict.get(source_key, []):
+        (source_root, source_extension) = os.path.splitext(source)
+        if source_extension.startswith('.'):
+          source_extension = source_extension[1:]
+        if source_extension == rule_extension:
+          rule_sources.append(source)
+
+    if len(rule_sources) > 0:
+      rule['rule_sources'] = rule_sources
+
+
+def ValidateRunAsInTarget(target, target_dict, build_file):
+  target_name = target_dict.get('target_name')
+  run_as = target_dict.get('run_as')
+  if not run_as:
+    return
+  if type(run_as) is not dict:
+    raise GypError("The 'run_as' in target %s from file %s should be a "
+                   "dictionary." %
+                   (target_name, build_file))
+  action = run_as.get('action')
+  if not action:
+    raise GypError("The 'run_as' in target %s from file %s must have an "
+                   "'action' section." %
+                   (target_name, build_file))
+  if type(action) is not list:
+    raise GypError("The 'action' for 'run_as' in target %s from file %s "
+                   "must be a list." %
+                   (target_name, build_file))
+  working_directory = run_as.get('working_directory')
+  if working_directory and type(working_directory) is not str:
+    raise GypError("The 'working_directory' for 'run_as' in target %s "
+                   "in file %s should be a string." %
+                   (target_name, build_file))
+  environment = run_as.get('environment')
+  if environment and type(environment) is not dict:
+    raise GypError("The 'environment' for 'run_as' in target %s "
+                   "in file %s should be a dictionary." %
+                   (target_name, build_file))
+
+
+def ValidateActionsInTarget(target, target_dict, build_file):
+  '''Validates the inputs to the actions in a target.'''
+  target_name = target_dict.get('target_name')
+  actions = target_dict.get('actions', [])
+  for action in actions:
+    action_name = action.get('action_name')
+    if not action_name:
+      raise GypError("Anonymous action in target %s.  "
+                     "An action must have an 'action_name' field." %
+                     target_name)
+    inputs = action.get('inputs', None)
+    if inputs is None:
+      raise GypError('Action in target %s has no inputs.' % target_name)
+    action_command = action.get('action')
+    if action_command and not action_command[0]:
+      raise GypError("Empty action as command in target %s." % target_name)
+
+
+def TurnIntIntoStrInDict(the_dict):
+  """Given dict the_dict, recursively converts all integers into strings.
+  """
+  # Use items instead of iteritems because there's no need to try to look at
+  # reinserted keys and their associated values.
+  for k, v in the_dict.items():
+    if type(v) is int:
+      v = str(v)
+      the_dict[k] = v
+    elif type(v) is dict:
+      TurnIntIntoStrInDict(v)
+    elif type(v) is list:
+      TurnIntIntoStrInList(v)
+
+    if type(k) is int:
+      del the_dict[k]
+      the_dict[str(k)] = v
+
+
+def TurnIntIntoStrInList(the_list):
+  """Given list the_list, recursively converts all integers into strings.
+  """
+  for index in xrange(0, len(the_list)):
+    item = the_list[index]
+    if type(item) is int:
+      the_list[index] = str(item)
+    elif type(item) is dict:
+      TurnIntIntoStrInDict(item)
+    elif type(item) is list:
+      TurnIntIntoStrInList(item)
+
+
+def PruneUnwantedTargets(targets, flat_list, dependency_nodes, root_targets,
+                         data):
+  """Return only the targets that are deep dependencies of |root_targets|."""
+  qualified_root_targets = []
+  for target in root_targets:
+    target = target.strip()
+    qualified_targets = gyp.common.FindQualifiedTargets(target, flat_list)
+    if not qualified_targets:
+      raise GypError("Could not find target %s" % target)
+    qualified_root_targets.extend(qualified_targets)
+
+  wanted_targets = {}
+  for target in qualified_root_targets:
+    wanted_targets[target] = targets[target]
+    for dependency in dependency_nodes[target].DeepDependencies():
+      wanted_targets[dependency] = targets[dependency]
+
+  wanted_flat_list = [t for t in flat_list if t in wanted_targets]
+
+  # Prune unwanted targets from each build_file's data dict.
+  for build_file in data['target_build_files']:
+    if not 'targets' in data[build_file]:
+      continue
+    new_targets = []
+    for target in data[build_file]['targets']:
+      qualified_name = gyp.common.QualifiedTarget(build_file,
+                                                  target['target_name'],
+                                                  target['toolset'])
+      if qualified_name in wanted_targets:
+        new_targets.append(target)
+    data[build_file]['targets'] = new_targets
+
+  return wanted_targets, wanted_flat_list
+
+
+def VerifyNoCollidingTargets(targets):
+  """Verify that no two targets in the same directory share the same name.
+
+  Arguments:
+    targets: A list of targets in the form 'path/to/file.gyp:target_name'.
+  """
+  # Keep a dict going from 'subdirectory:target_name' to 'foo.gyp'.
+  used = {}
+  for target in targets:
+    # Separate out 'path/to/file.gyp, 'target_name' from
+    # 'path/to/file.gyp:target_name'.
+    path, name = target.rsplit(':', 1)
+    # Separate out 'path/to', 'file.gyp' from 'path/to/file.gyp'.
+    subdir, gyp = os.path.split(path)
+    # Use '.' for the current directory '', so that the error messages make
+    # more sense.
+    if not subdir:
+      subdir = '.'
+    # Prepare a key like 'path/to:target_name'.
+    key = subdir + ':' + name
+    if key in used:
+      # Complain if this target is already used.
+      raise GypError('Duplicate target name "%s" in directory "%s" used both '
+                     'in "%s" and "%s".' % (name, subdir, gyp, used[key]))
+    used[key] = gyp
+
+
+def SetGeneratorGlobals(generator_input_info):
+  # Set up path_sections and non_configuration_keys with the default data plus
+  # the generator-specific data.
+  global path_sections
+  path_sections = set(base_path_sections)
+  path_sections.update(generator_input_info['path_sections'])
+
+  global non_configuration_keys
+  non_configuration_keys = base_non_configuration_keys[:]
+  non_configuration_keys.extend(generator_input_info['non_configuration_keys'])
+
+  global multiple_toolsets
+  multiple_toolsets = generator_input_info[
+      'generator_supports_multiple_toolsets']
+
+  global generator_filelist_paths
+  generator_filelist_paths = generator_input_info['generator_filelist_paths']
+
+
+def Load(build_files, variables, includes, depth, generator_input_info, check,
+         circular_check, duplicate_basename_check, parallel, root_targets):
+  SetGeneratorGlobals(generator_input_info)
+  # A generator can have other lists (in addition to sources) be processed
+  # for rules.
+  extra_sources_for_rules = generator_input_info['extra_sources_for_rules']
+
+  # Load build files.  This loads every target-containing build file into
+  # the |data| dictionary such that the keys to |data| are build file names,
+  # and the values are the entire build file contents after "early" or "pre"
+  # processing has been done and includes have been resolved.
+  # NOTE: data contains both "target" files (.gyp) and "includes" (.gypi), as
+  # well as meta-data (e.g. 'included_files' key). 'target_build_files' keeps
+  # track of the keys corresponding to "target" files.
+  data = {'target_build_files': set()}
+  aux_data = {}
+  # Normalize paths everywhere.  This is important because paths will be
+  # used as keys to the data dict and for references between input files.
+  build_files = set(map(os.path.normpath, build_files))
+  if parallel:
+    LoadTargetBuildFilesParallel(build_files, data, aux_data,
+                                 variables, includes, depth, check,
+                                 generator_input_info)
+  else:
+    for build_file in build_files:
+      try:
+        LoadTargetBuildFile(build_file, data, aux_data,
+                            variables, includes, depth, check, True)
+      except Exception, e:
+        gyp.common.ExceptionAppend(e, 'while trying to load %s' % build_file)
+        raise
+
+  # Build a dict to access each target's subdict by qualified name.
+  targets = BuildTargetsDict(data)
+
+  # Fully qualify all dependency links.
+  QualifyDependencies(targets)
+
+  # Remove self-dependencies from targets that have 'prune_self_dependencies'
+  # set to 1.
+  RemoveSelfDependencies(targets)
+
+  # Expand dependencies specified as build_file:*.
+  ExpandWildcardDependencies(targets, data)
+
+  # Remove all dependencies marked as 'link_dependency' from the targets of
+  # type 'none'.
+  RemoveLinkDependenciesFromNoneTargets(targets)
+
+  # Apply exclude (!) and regex (/) list filters only for dependency_sections.
+  for target_name, target_dict in targets.iteritems():
+    tmp_dict = {}
+    for key_base in dependency_sections:
+      for op in ('', '!', '/'):
+        key = key_base + op
+        if key in target_dict:
+          tmp_dict[key] = target_dict[key]
+          del target_dict[key]
+    ProcessListFiltersInDict(target_name, tmp_dict)
+    # Write the results back to |target_dict|.
+    for key in tmp_dict:
+      target_dict[key] = tmp_dict[key]
+
+  # Make sure every dependency appears at most once.
+  RemoveDuplicateDependencies(targets)
+
+  if circular_check:
+    # Make sure that any targets in a.gyp don't contain dependencies in other
+    # .gyp files that further depend on a.gyp.
+    VerifyNoGYPFileCircularDependencies(targets)
+
+  [dependency_nodes, flat_list] = BuildDependencyList(targets)
+
+  if root_targets:
+    # Remove, from |targets| and |flat_list|, the targets that are not deep
+    # dependencies of the targets specified in |root_targets|.
+    targets, flat_list = PruneUnwantedTargets(
+        targets, flat_list, dependency_nodes, root_targets, data)
+
+  # Check that no two targets in the same directory have the same name.
+  VerifyNoCollidingTargets(flat_list)
+
+  # Handle dependent settings of various types.
+  for settings_type in ['all_dependent_settings',
+                        'direct_dependent_settings',
+                        'link_settings']:
+    DoDependentSettings(settings_type, flat_list, targets, dependency_nodes)
+
+    # Take out the dependent settings now that they've been published to all
+    # of the targets that require them.
+    for target in flat_list:
+      if settings_type in targets[target]:
+        del targets[target][settings_type]
+
+  # Make sure static libraries don't declare dependencies on other static
+  # libraries, but that linkables depend on all unlinked static libraries
+  # that they need so that their link steps will be correct.
+  gii = generator_input_info
+  if gii['generator_wants_static_library_dependencies_adjusted']:
+    AdjustStaticLibraryDependencies(flat_list, targets, dependency_nodes,
+                                    gii['generator_wants_sorted_dependencies'])
+
+  # Apply "post"/"late"/"target" variable expansions and condition evaluations.
+  for target in flat_list:
+    target_dict = targets[target]
+    build_file = gyp.common.BuildFile(target)
+    ProcessVariablesAndConditionsInDict(
+        target_dict, PHASE_LATE, variables, build_file)
+
+  # Move everything that can go into a "configurations" section into one.
+  for target in flat_list:
+    target_dict = targets[target]
+    SetUpConfigurations(target, target_dict)
+
+  # Apply exclude (!) and regex (/) list filters.
+  for target in flat_list:
+    target_dict = targets[target]
+    ProcessListFiltersInDict(target, target_dict)
+
+  # Apply "latelate" variable expansions and condition evaluations.
+  for target in flat_list:
+    target_dict = targets[target]
+    build_file = gyp.common.BuildFile(target)
+    ProcessVariablesAndConditionsInDict(
+        target_dict, PHASE_LATELATE, variables, build_file)
+
+  # TODO(thakis): Get vpx_scale/arm/scalesystemdependent.c to be renamed to
+  #               scalesystemdependent_arm_additions.c or similar.
+  if 'arm' in variables.get('target_arch', ''):
+    duplicate_basename_check = False
+
+  # Make sure that the rules make sense, and build up rule_sources lists as
+  # needed.  Not all generators will need to use the rule_sources lists, but
+  # some may, and it seems best to build the list in a common spot.
+  # Also validate actions and run_as elements in targets.
+  for target in flat_list:
+    target_dict = targets[target]
+    build_file = gyp.common.BuildFile(target)
+    ValidateTargetType(target, target_dict)
+    ValidateSourcesInTarget(target, target_dict, build_file,
+                            duplicate_basename_check)
+    ValidateRulesInTarget(target, target_dict, extra_sources_for_rules)
+    ValidateRunAsInTarget(target, target_dict, build_file)
+    ValidateActionsInTarget(target, target_dict, build_file)
+
+  # Generators might not expect ints.  Turn them into strs.
+  TurnIntIntoStrInDict(data)
+
+  # TODO(mark): Return |data| for now because the generator needs a list of
+  # build files that came in.  In the future, maybe it should just accept
+  # a list, and not the whole data dict.
+  return [flat_list, targets, data]
diff --git a/gyp/pylib/gyp/input_test.py b/gyp/pylib/gyp/input_test.py
new file mode 100755 (executable)
index 0000000..cdbf6b2
--- /dev/null
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+# Copyright 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unit tests for the input.py file."""
+
+import gyp.input
+import unittest
+import sys
+
+
+class TestFindCycles(unittest.TestCase):
+  def setUp(self):
+    self.nodes = {}
+    for x in ('a', 'b', 'c', 'd', 'e'):
+      self.nodes[x] = gyp.input.DependencyGraphNode(x)
+
+  def _create_dependency(self, dependent, dependency):
+    dependent.dependencies.append(dependency)
+    dependency.dependents.append(dependent)
+
+  def test_no_cycle_empty_graph(self):
+    for label, node in self.nodes.iteritems():
+      self.assertEquals([], node.FindCycles())
+
+  def test_no_cycle_line(self):
+    self._create_dependency(self.nodes['a'], self.nodes['b'])
+    self._create_dependency(self.nodes['b'], self.nodes['c'])
+    self._create_dependency(self.nodes['c'], self.nodes['d'])
+
+    for label, node in self.nodes.iteritems():
+      self.assertEquals([], node.FindCycles())
+
+  def test_no_cycle_dag(self):
+    self._create_dependency(self.nodes['a'], self.nodes['b'])
+    self._create_dependency(self.nodes['a'], self.nodes['c'])
+    self._create_dependency(self.nodes['b'], self.nodes['c'])
+
+    for label, node in self.nodes.iteritems():
+      self.assertEquals([], node.FindCycles())
+
+  def test_cycle_self_reference(self):
+    self._create_dependency(self.nodes['a'], self.nodes['a'])
+
+    self.assertEquals([(self.nodes['a'], self.nodes['a'])],
+                      self.nodes['a'].FindCycles())
+
+  def test_cycle_two_nodes(self):
+    self._create_dependency(self.nodes['a'], self.nodes['b'])
+    self._create_dependency(self.nodes['b'], self.nodes['a'])
+
+    self.assertEquals([(self.nodes['a'], self.nodes['b'], self.nodes['a'])],
+                      self.nodes['a'].FindCycles())
+    self.assertEquals([(self.nodes['b'], self.nodes['a'], self.nodes['b'])],
+                      self.nodes['b'].FindCycles())
+
+  def test_two_cycles(self):
+    self._create_dependency(self.nodes['a'], self.nodes['b'])
+    self._create_dependency(self.nodes['b'], self.nodes['a'])
+
+    self._create_dependency(self.nodes['b'], self.nodes['c'])
+    self._create_dependency(self.nodes['c'], self.nodes['b'])
+
+    cycles = self.nodes['a'].FindCycles()
+    self.assertTrue(
+       (self.nodes['a'], self.nodes['b'], self.nodes['a']) in cycles)
+    self.assertTrue(
+       (self.nodes['b'], self.nodes['c'], self.nodes['b']) in cycles)
+    self.assertEquals(2, len(cycles))
+
+  def test_big_cycle(self):
+    self._create_dependency(self.nodes['a'], self.nodes['b'])
+    self._create_dependency(self.nodes['b'], self.nodes['c'])
+    self._create_dependency(self.nodes['c'], self.nodes['d'])
+    self._create_dependency(self.nodes['d'], self.nodes['e'])
+    self._create_dependency(self.nodes['e'], self.nodes['a'])
+
+    self.assertEquals([(self.nodes['a'],
+                        self.nodes['b'],
+                        self.nodes['c'],
+                        self.nodes['d'],
+                        self.nodes['e'],
+                        self.nodes['a'])],
+                      self.nodes['a'].FindCycles())
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/gyp/pylib/gyp/mac_tool.py b/gyp/pylib/gyp/mac_tool.py
new file mode 100755 (executable)
index 0000000..821e291
--- /dev/null
@@ -0,0 +1,514 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Utility functions to perform Xcode-style build steps.
+
+These functions are executed via gyp-mac-tool when using the Makefile generator.
+"""
+
+import fcntl
+import fnmatch
+import glob
+import json
+import os
+import plistlib
+import re
+import shutil
+import string
+import subprocess
+import sys
+import tempfile
+
+
+def main(args):
+  executor = MacTool()
+  exit_code = executor.Dispatch(args)
+  if exit_code is not None:
+    sys.exit(exit_code)
+
+
+class MacTool(object):
+  """This class performs all the Mac tooling steps. The methods can either be
+  executed directly, or dispatched from an argument list."""
+
+  def Dispatch(self, args):
+    """Dispatches a string command to a method."""
+    if len(args) < 1:
+      raise Exception("Not enough arguments")
+
+    method = "Exec%s" % self._CommandifyName(args[0])
+    return getattr(self, method)(*args[1:])
+
+  def _CommandifyName(self, name_string):
+    """Transforms a tool name like copy-info-plist to CopyInfoPlist"""
+    return name_string.title().replace('-', '')
+
+  def ExecCopyBundleResource(self, source, dest):
+    """Copies a resource file to the bundle/Resources directory, performing any
+    necessary compilation on each resource."""
+    extension = os.path.splitext(source)[1].lower()
+    if os.path.isdir(source):
+      # Copy tree.
+      # TODO(thakis): This copies file attributes like mtime, while the
+      # single-file branch below doesn't. This should probably be changed to
+      # be consistent with the single-file branch.
+      if os.path.exists(dest):
+        shutil.rmtree(dest)
+      shutil.copytree(source, dest)
+    elif extension == '.xib':
+      return self._CopyXIBFile(source, dest)
+    elif extension == '.storyboard':
+      return self._CopyXIBFile(source, dest)
+    elif extension == '.strings':
+      self._CopyStringsFile(source, dest)
+    else:
+      shutil.copy(source, dest)
+
+  def _CopyXIBFile(self, source, dest):
+    """Compiles a XIB file with ibtool into a binary plist in the bundle."""
+
+    # ibtool sometimes crashes with relative paths. See crbug.com/314728.
+    base = os.path.dirname(os.path.realpath(__file__))
+    if os.path.relpath(source):
+      source = os.path.join(base, source)
+    if os.path.relpath(dest):
+      dest = os.path.join(base, dest)
+
+    args = ['xcrun', 'ibtool', '--errors', '--warnings', '--notices',
+        '--output-format', 'human-readable-text', '--compile', dest, source]
+    ibtool_section_re = re.compile(r'/\*.*\*/')
+    ibtool_re = re.compile(r'.*note:.*is clipping its content')
+    ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE)
+    current_section_header = None
+    for line in ibtoolout.stdout:
+      if ibtool_section_re.match(line):
+        current_section_header = line
+      elif not ibtool_re.match(line):
+        if current_section_header:
+          sys.stdout.write(current_section_header)
+          current_section_header = None
+        sys.stdout.write(line)
+    return ibtoolout.returncode
+
+  def _CopyStringsFile(self, source, dest):
+    """Copies a .strings file using iconv to reconvert the input into UTF-16."""
+    input_code = self._DetectInputEncoding(source) or "UTF-8"
+
+    # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call
+    # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints
+    #     CFPropertyListCreateFromXMLData(): Old-style plist parser: missing
+    #     semicolon in dictionary.
+    # on invalid files. Do the same kind of validation.
+    import CoreFoundation
+    s = open(source, 'rb').read()
+    d = CoreFoundation.CFDataCreate(None, s, len(s))
+    _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None)
+    if error:
+      return
+
+    fp = open(dest, 'wb')
+    fp.write(s.decode(input_code).encode('UTF-16'))
+    fp.close()
+
+  def _DetectInputEncoding(self, file_name):
+    """Reads the first few bytes from file_name and tries to guess the text
+    encoding. Returns None as a guess if it can't detect it."""
+    fp = open(file_name, 'rb')
+    try:
+      header = fp.read(3)
+    except e:
+      fp.close()
+      return None
+    fp.close()
+    if header.startswith("\xFE\xFF"):
+      return "UTF-16"
+    elif header.startswith("\xFF\xFE"):
+      return "UTF-16"
+    elif header.startswith("\xEF\xBB\xBF"):
+      return "UTF-8"
+    else:
+      return None
+
+  def ExecCopyInfoPlist(self, source, dest, *keys):
+    """Copies the |source| Info.plist to the destination directory |dest|."""
+    # Read the source Info.plist into memory.
+    fd = open(source, 'r')
+    lines = fd.read()
+    fd.close()
+
+    # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild).
+    plist = plistlib.readPlistFromString(lines)
+    if keys:
+      plist = dict(plist.items() + json.loads(keys[0]).items())
+    lines = plistlib.writePlistToString(plist)
+
+    # Go through all the environment variables and replace them as variables in
+    # the file.
+    IDENT_RE = re.compile('[/\s]')
+    for key in os.environ:
+      if key.startswith('_'):
+        continue
+      evar = '${%s}' % key
+      evalue = os.environ[key]
+      lines = string.replace(lines, evar, evalue)
+
+      # Xcode supports various suffices on environment variables, which are
+      # all undocumented. :rfc1034identifier is used in the standard project
+      # template these days, and :identifier was used earlier. They are used to
+      # convert non-url characters into things that look like valid urls --
+      # except that the replacement character for :identifier, '_' isn't valid
+      # in a URL either -- oops, hence :rfc1034identifier was born.
+      evar = '${%s:identifier}' % key
+      evalue = IDENT_RE.sub('_', os.environ[key])
+      lines = string.replace(lines, evar, evalue)
+
+      evar = '${%s:rfc1034identifier}' % key
+      evalue = IDENT_RE.sub('-', os.environ[key])
+      lines = string.replace(lines, evar, evalue)
+
+    # Remove any keys with values that haven't been replaced.
+    lines = lines.split('\n')
+    for i in range(len(lines)):
+      if lines[i].strip().startswith("<string>${"):
+        lines[i] = None
+        lines[i - 1] = None
+    lines = '\n'.join(filter(lambda x: x is not None, lines))
+
+    # Write out the file with variables replaced.
+    fd = open(dest, 'w')
+    fd.write(lines)
+    fd.close()
+
+    # Now write out PkgInfo file now that the Info.plist file has been
+    # "compiled".
+    self._WritePkgInfo(dest)
+
+  def _WritePkgInfo(self, info_plist):
+    """This writes the PkgInfo file from the data stored in Info.plist."""
+    plist = plistlib.readPlist(info_plist)
+    if not plist:
+      return
+
+    # Only create PkgInfo for executable types.
+    package_type = plist['CFBundlePackageType']
+    if package_type != 'APPL':
+      return
+
+    # The format of PkgInfo is eight characters, representing the bundle type
+    # and bundle signature, each four characters. If that is missing, four
+    # '?' characters are used instead.
+    signature_code = plist.get('CFBundleSignature', '????')
+    if len(signature_code) != 4:  # Wrong length resets everything, too.
+      signature_code = '?' * 4
+
+    dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo')
+    fp = open(dest, 'w')
+    fp.write('%s%s' % (package_type, signature_code))
+    fp.close()
+
+  def ExecFlock(self, lockfile, *cmd_list):
+    """Emulates the most basic behavior of Linux's flock(1)."""
+    # Rely on exception handling to report errors.
+    fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666)
+    fcntl.flock(fd, fcntl.LOCK_EX)
+    return subprocess.call(cmd_list)
+
+  def ExecFilterLibtool(self, *cmd_list):
+    """Calls libtool and filters out '/path/to/libtool: file: foo.o has no
+    symbols'."""
+    libtool_re = re.compile(r'^.*libtool: file: .* has no symbols$')
+    libtool_re5 = re.compile(
+        r'^.*libtool: warning for library: ' +
+        r'.* the table of contents is empty ' +
+        r'\(no object file members in the library define global symbols\)$')
+    libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE)
+    _, err = libtoolout.communicate()
+    for line in err.splitlines():
+      if not libtool_re.match(line) and not libtool_re5.match(line):
+        print >>sys.stderr, line
+    return libtoolout.returncode
+
+  def ExecPackageFramework(self, framework, version):
+    """Takes a path to Something.framework and the Current version of that and
+    sets up all the symlinks."""
+    # Find the name of the binary based on the part before the ".framework".
+    binary = os.path.basename(framework).split('.')[0]
+
+    CURRENT = 'Current'
+    RESOURCES = 'Resources'
+    VERSIONS = 'Versions'
+
+    if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)):
+      # Binary-less frameworks don't seem to contain symlinks (see e.g.
+      # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle).
+      return
+
+    # Move into the framework directory to set the symlinks correctly.
+    pwd = os.getcwd()
+    os.chdir(framework)
+
+    # Set up the Current version.
+    self._Relink(version, os.path.join(VERSIONS, CURRENT))
+
+    # Set up the root symlinks.
+    self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary)
+    self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES)
+
+    # Back to where we were before!
+    os.chdir(pwd)
+
+  def _Relink(self, dest, link):
+    """Creates a symlink to |dest| named |link|. If |link| already exists,
+    it is overwritten."""
+    if os.path.lexists(link):
+      os.remove(link)
+    os.symlink(dest, link)
+
+  def ExecCodeSignBundle(self, key, resource_rules, entitlements, provisioning):
+    """Code sign a bundle.
+
+    This function tries to code sign an iOS bundle, following the same
+    algorithm as Xcode:
+      1. copy ResourceRules.plist from the user or the SDK into the bundle,
+      2. pick the provisioning profile that best match the bundle identifier,
+         and copy it into the bundle as embedded.mobileprovision,
+      3. copy Entitlements.plist from user or SDK next to the bundle,
+      4. code sign the bundle.
+    """
+    resource_rules_path = self._InstallResourceRules(resource_rules)
+    substitutions, overrides = self._InstallProvisioningProfile(
+        provisioning, self._GetCFBundleIdentifier())
+    entitlements_path = self._InstallEntitlements(
+        entitlements, substitutions, overrides)
+    subprocess.check_call([
+        'codesign', '--force', '--sign', key, '--resource-rules',
+        resource_rules_path, '--entitlements', entitlements_path,
+        os.path.join(
+            os.environ['TARGET_BUILD_DIR'],
+            os.environ['FULL_PRODUCT_NAME'])])
+
+  def _InstallResourceRules(self, resource_rules):
+    """Installs ResourceRules.plist from user or SDK into the bundle.
+
+    Args:
+      resource_rules: string, optional, path to the ResourceRules.plist file
+        to use, default to "${SDKROOT}/ResourceRules.plist"
+
+    Returns:
+      Path to the copy of ResourceRules.plist into the bundle.
+    """
+    source_path = resource_rules
+    target_path = os.path.join(
+        os.environ['BUILT_PRODUCTS_DIR'],
+        os.environ['CONTENTS_FOLDER_PATH'],
+        'ResourceRules.plist')
+    if not source_path:
+      source_path = os.path.join(
+          os.environ['SDKROOT'], 'ResourceRules.plist')
+    shutil.copy2(source_path, target_path)
+    return target_path
+
+  def _InstallProvisioningProfile(self, profile, bundle_identifier):
+    """Installs embedded.mobileprovision into the bundle.
+
+    Args:
+      profile: string, optional, short name of the .mobileprovision file
+        to use, if empty or the file is missing, the best file installed
+        will be used
+      bundle_identifier: string, value of CFBundleIdentifier from Info.plist
+
+    Returns:
+      A tuple containing two dictionary: variables substitutions and values
+      to overrides when generating the entitlements file.
+    """
+    source_path, provisioning_data, team_id = self._FindProvisioningProfile(
+        profile, bundle_identifier)
+    target_path = os.path.join(
+        os.environ['BUILT_PRODUCTS_DIR'],
+        os.environ['CONTENTS_FOLDER_PATH'],
+        'embedded.mobileprovision')
+    shutil.copy2(source_path, target_path)
+    substitutions = self._GetSubstitutions(bundle_identifier, team_id + '.')
+    return substitutions, provisioning_data['Entitlements']
+
+  def _FindProvisioningProfile(self, profile, bundle_identifier):
+    """Finds the .mobileprovision file to use for signing the bundle.
+
+    Checks all the installed provisioning profiles (or if the user specified
+    the PROVISIONING_PROFILE variable, only consult it) and select the most
+    specific that correspond to the bundle identifier.
+
+    Args:
+      profile: string, optional, short name of the .mobileprovision file
+        to use, if empty or the file is missing, the best file installed
+        will be used
+      bundle_identifier: string, value of CFBundleIdentifier from Info.plist
+
+    Returns:
+      A tuple of the path to the selected provisioning profile, the data of
+      the embedded plist in the provisioning profile and the team identifier
+      to use for code signing.
+
+    Raises:
+      SystemExit: if no .mobileprovision can be used to sign the bundle.
+    """
+    profiles_dir = os.path.join(
+        os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles')
+    if not os.path.isdir(profiles_dir):
+      print >>sys.stderr, (
+          'cannot find mobile provisioning for %s' % bundle_identifier)
+      sys.exit(1)
+    provisioning_profiles = None
+    if profile:
+      profile_path = os.path.join(profiles_dir, profile + '.mobileprovision')
+      if os.path.exists(profile_path):
+        provisioning_profiles = [profile_path]
+    if not provisioning_profiles:
+      provisioning_profiles = glob.glob(
+          os.path.join(profiles_dir, '*.mobileprovision'))
+    valid_provisioning_profiles = {}
+    for profile_path in provisioning_profiles:
+      profile_data = self._LoadProvisioningProfile(profile_path)
+      app_id_pattern = profile_data.get(
+          'Entitlements', {}).get('application-identifier', '')
+      for team_identifier in profile_data.get('TeamIdentifier', []):
+        app_id = '%s.%s' % (team_identifier, bundle_identifier)
+        if fnmatch.fnmatch(app_id, app_id_pattern):
+          valid_provisioning_profiles[app_id_pattern] = (
+              profile_path, profile_data, team_identifier)
+    if not valid_provisioning_profiles:
+      print >>sys.stderr, (
+          'cannot find mobile provisioning for %s' % bundle_identifier)
+      sys.exit(1)
+    # If the user has multiple provisioning profiles installed that can be
+    # used for ${bundle_identifier}, pick the most specific one (ie. the
+    # provisioning profile whose pattern is the longest).
+    selected_key = max(valid_provisioning_profiles, key=lambda v: len(v))
+    return valid_provisioning_profiles[selected_key]
+
+  def _LoadProvisioningProfile(self, profile_path):
+    """Extracts the plist embedded in a provisioning profile.
+
+    Args:
+      profile_path: string, path to the .mobileprovision file
+
+    Returns:
+      Content of the plist embedded in the provisioning profile as a dictionary.
+    """
+    with tempfile.NamedTemporaryFile() as temp:
+      subprocess.check_call([
+          'security', 'cms', '-D', '-i', profile_path, '-o', temp.name])
+      return self._LoadPlistMaybeBinary(temp.name)
+
+  def _LoadPlistMaybeBinary(self, plist_path):
+    """Loads into a memory a plist possibly encoded in binary format.
+
+    This is a wrapper around plistlib.readPlist that tries to convert the
+    plist to the XML format if it can't be parsed (assuming that it is in
+    the binary format).
+
+    Args:
+      plist_path: string, path to a plist file, in XML or binary format
+
+    Returns:
+      Content of the plist as a dictionary.
+    """
+    try:
+      # First, try to read the file using plistlib that only supports XML,
+      # and if an exception is raised, convert a temporary copy to XML and
+      # load that copy.
+      return plistlib.readPlist(plist_path)
+    except:
+      pass
+    with tempfile.NamedTemporaryFile() as temp:
+      shutil.copy2(plist_path, temp.name)
+      subprocess.check_call(['plutil', '-convert', 'xml1', temp.name])
+      return plistlib.readPlist(temp.name)
+
+  def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix):
+    """Constructs a dictionary of variable substitutions for Entitlements.plist.
+
+    Args:
+      bundle_identifier: string, value of CFBundleIdentifier from Info.plist
+      app_identifier_prefix: string, value for AppIdentifierPrefix
+
+    Returns:
+      Dictionary of substitutions to apply when generating Entitlements.plist.
+    """
+    return {
+      'CFBundleIdentifier': bundle_identifier,
+      'AppIdentifierPrefix': app_identifier_prefix,
+    }
+
+  def _GetCFBundleIdentifier(self):
+    """Extracts CFBundleIdentifier value from Info.plist in the bundle.
+
+    Returns:
+      Value of CFBundleIdentifier in the Info.plist located in the bundle.
+    """
+    info_plist_path = os.path.join(
+        os.environ['TARGET_BUILD_DIR'],
+        os.environ['INFOPLIST_PATH'])
+    info_plist_data = self._LoadPlistMaybeBinary(info_plist_path)
+    return info_plist_data['CFBundleIdentifier']
+
+  def _InstallEntitlements(self, entitlements, substitutions, overrides):
+    """Generates and install the ${BundleName}.xcent entitlements file.
+
+    Expands variables "$(variable)" pattern in the source entitlements file,
+    add extra entitlements defined in the .mobileprovision file and the copy
+    the generated plist to "${BundlePath}.xcent".
+
+    Args:
+      entitlements: string, optional, path to the Entitlements.plist template
+        to use, defaults to "${SDKROOT}/Entitlements.plist"
+      substitutions: dictionary, variable substitutions
+      overrides: dictionary, values to add to the entitlements
+
+    Returns:
+      Path to the generated entitlements file.
+    """
+    source_path = entitlements
+    target_path = os.path.join(
+        os.environ['BUILT_PRODUCTS_DIR'],
+        os.environ['PRODUCT_NAME'] + '.xcent')
+    if not source_path:
+      source_path = os.path.join(
+          os.environ['SDKROOT'],
+          'Entitlements.plist')
+    shutil.copy2(source_path, target_path)
+    data = self._LoadPlistMaybeBinary(target_path)
+    data = self._ExpandVariables(data, substitutions)
+    if overrides:
+      for key in overrides:
+        if key not in data:
+          data[key] = overrides[key]
+    plistlib.writePlist(data, target_path)
+    return target_path
+
+  def _ExpandVariables(self, data, substitutions):
+    """Expands variables "$(variable)" in data.
+
+    Args:
+      data: object, can be either string, list or dictionary
+      substitutions: dictionary, variable substitutions to perform
+
+    Returns:
+      Copy of data where each references to "$(variable)" has been replaced
+      by the corresponding value found in substitutions, or left intact if
+      the key was not found.
+    """
+    if isinstance(data, str):
+      for key, value in substitutions.iteritems():
+        data = data.replace('$(%s)' % key, value)
+      return data
+    if isinstance(data, list):
+      return [self._ExpandVariables(v, substitutions) for v in data]
+    if isinstance(data, dict):
+      return {k: self._ExpandVariables(data[k], substitutions) for k in data}
+    return data
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/gyp/pylib/gyp/msvs_emulation.py b/gyp/pylib/gyp/msvs_emulation.py
new file mode 100644 (file)
index 0000000..5f71e9e
--- /dev/null
@@ -0,0 +1,1025 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+This module helps emulate Visual Studio 2008 behavior on top of other
+build systems, primarily ninja.
+"""
+
+import os
+import re
+import subprocess
+import sys
+
+from gyp.common import OrderedSet
+import gyp.MSVSVersion
+
+windows_quoter_regex = re.compile(r'(\\*)"')
+
+def QuoteForRspFile(arg):
+  """Quote a command line argument so that it appears as one argument when
+  processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for
+  Windows programs)."""
+  # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment
+  # threads. This is actually the quoting rules for CommandLineToArgvW, not
+  # for the shell, because the shell doesn't do anything in Windows. This
+  # works more or less because most programs (including the compiler, etc.)
+  # use that function to handle command line arguments.
+
+  # For a literal quote, CommandLineToArgvW requires 2n+1 backslashes
+  # preceding it, and results in n backslashes + the quote. So we substitute
+  # in 2* what we match, +1 more, plus the quote.
+  arg = windows_quoter_regex.sub(lambda mo: 2 * mo.group(1) + '\\"', arg)
+
+  # %'s also need to be doubled otherwise they're interpreted as batch
+  # positional arguments. Also make sure to escape the % so that they're
+  # passed literally through escaping so they can be singled to just the
+  # original %. Otherwise, trying to pass the literal representation that
+  # looks like an environment variable to the shell (e.g. %PATH%) would fail.
+  arg = arg.replace('%', '%%')
+
+  # These commands are used in rsp files, so no escaping for the shell (via ^)
+  # is necessary.
+
+  # Finally, wrap the whole thing in quotes so that the above quote rule
+  # applies and whitespace isn't a word break.
+  return '"' + arg + '"'
+
+
+def EncodeRspFileList(args):
+  """Process a list of arguments using QuoteCmdExeArgument."""
+  # Note that the first argument is assumed to be the command. Don't add
+  # quotes around it because then built-ins like 'echo', etc. won't work.
+  # Take care to normpath only the path in the case of 'call ../x.bat' because
+  # otherwise the whole thing is incorrectly interpreted as a path and not
+  # normalized correctly.
+  if not args: return ''
+  if args[0].startswith('call '):
+    call, program = args[0].split(' ', 1)
+    program = call + ' ' + os.path.normpath(program)
+  else:
+    program = os.path.normpath(args[0])
+  return program + ' ' + ' '.join(QuoteForRspFile(arg) for arg in args[1:])
+
+
+def _GenericRetrieve(root, default, path):
+  """Given a list of dictionary keys |path| and a tree of dicts |root|, find
+  value at path, or return |default| if any of the path doesn't exist."""
+  if not root:
+    return default
+  if not path:
+    return root
+  return _GenericRetrieve(root.get(path[0]), default, path[1:])
+
+
+def _AddPrefix(element, prefix):
+  """Add |prefix| to |element| or each subelement if element is iterable."""
+  if element is None:
+    return element
+  # Note, not Iterable because we don't want to handle strings like that.
+  if isinstance(element, list) or isinstance(element, tuple):
+    return [prefix + e for e in element]
+  else:
+    return prefix + element
+
+
+def _DoRemapping(element, map):
+  """If |element| then remap it through |map|. If |element| is iterable then
+  each item will be remapped. Any elements not found will be removed."""
+  if map is not None and element is not None:
+    if not callable(map):
+      map = map.get # Assume it's a dict, otherwise a callable to do the remap.
+    if isinstance(element, list) or isinstance(element, tuple):
+      element = filter(None, [map(elem) for elem in element])
+    else:
+      element = map(element)
+  return element
+
+
+def _AppendOrReturn(append, element):
+  """If |append| is None, simply return |element|. If |append| is not None,
+  then add |element| to it, adding each item in |element| if it's a list or
+  tuple."""
+  if append is not None and element is not None:
+    if isinstance(element, list) or isinstance(element, tuple):
+      append.extend(element)
+    else:
+      append.append(element)
+  else:
+    return element
+
+
+def _FindDirectXInstallation():
+  """Try to find an installation location for the DirectX SDK. Check for the
+  standard environment variable, and if that doesn't exist, try to find
+  via the registry. May return None if not found in either location."""
+  # Return previously calculated value, if there is one
+  if hasattr(_FindDirectXInstallation, 'dxsdk_dir'):
+    return _FindDirectXInstallation.dxsdk_dir
+
+  dxsdk_dir = os.environ.get('DXSDK_DIR')
+  if not dxsdk_dir:
+    # Setup params to pass to and attempt to launch reg.exe.
+    cmd = ['reg.exe', 'query', r'HKLM\Software\Microsoft\DirectX', '/s']
+    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    for line in p.communicate()[0].splitlines():
+      if 'InstallPath' in line:
+        dxsdk_dir = line.split('    ')[3] + "\\"
+
+  # Cache return value
+  _FindDirectXInstallation.dxsdk_dir = dxsdk_dir
+  return dxsdk_dir
+
+
+def GetGlobalVSMacroEnv(vs_version):
+  """Get a dict of variables mapping internal VS macro names to their gyp
+  equivalents. Returns all variables that are independent of the target."""
+  env = {}
+  # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when
+  # Visual Studio is actually installed.
+  if vs_version.Path():
+    env['$(VSInstallDir)'] = vs_version.Path()
+    env['$(VCInstallDir)'] = os.path.join(vs_version.Path(), 'VC') + '\\'
+  # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be
+  # set. This happens when the SDK is sync'd via src-internal, rather than
+  # by typical end-user installation of the SDK. If it's not set, we don't
+  # want to leave the unexpanded variable in the path, so simply strip it.
+  dxsdk_dir = _FindDirectXInstallation()
+  env['$(DXSDK_DIR)'] = dxsdk_dir if dxsdk_dir else ''
+  # Try to find an installation location for the Windows DDK by checking
+  # the WDK_DIR environment variable, may be None.
+  env['$(WDK_DIR)'] = os.environ.get('WDK_DIR', '')
+  return env
+
+def ExtractSharedMSVSSystemIncludes(configs, generator_flags):
+  """Finds msvs_system_include_dirs that are common to all targets, removes
+  them from all targets, and returns an OrderedSet containing them."""
+  all_system_includes = OrderedSet(
+      configs[0].get('msvs_system_include_dirs', []))
+  for config in configs[1:]:
+    system_includes = config.get('msvs_system_include_dirs', [])
+    all_system_includes = all_system_includes & OrderedSet(system_includes)
+  if not all_system_includes:
+    return None
+  # Expand macros in all_system_includes.
+  env = GetGlobalVSMacroEnv(GetVSVersion(generator_flags))
+  expanded_system_includes = OrderedSet([ExpandMacros(include, env)
+                                         for include in all_system_includes])
+  if any(['$' in include for include in expanded_system_includes]):
+    # Some path relies on target-specific variables, bail.
+    return None
+
+  # Remove system includes shared by all targets from the targets.
+  for config in configs:
+    includes = config.get('msvs_system_include_dirs', [])
+    if includes:  # Don't insert a msvs_system_include_dirs key if not needed.
+      # This must check the unexpanded includes list:
+      new_includes = [i for i in includes if i not in all_system_includes]
+      config['msvs_system_include_dirs'] = new_includes
+  return expanded_system_includes
+
+
+class MsvsSettings(object):
+  """A class that understands the gyp 'msvs_...' values (especially the
+  msvs_settings field). They largely correpond to the VS2008 IDE DOM. This
+  class helps map those settings to command line options."""
+
+  def __init__(self, spec, generator_flags):
+    self.spec = spec
+    self.vs_version = GetVSVersion(generator_flags)
+
+    supported_fields = [
+        ('msvs_configuration_attributes', dict),
+        ('msvs_settings', dict),
+        ('msvs_system_include_dirs', list),
+        ('msvs_disabled_warnings', list),
+        ('msvs_precompiled_header', str),
+        ('msvs_precompiled_source', str),
+        ('msvs_configuration_platform', str),
+        ('msvs_target_platform', str),
+        ]
+    configs = spec['configurations']
+    for field, default in supported_fields:
+      setattr(self, field, {})
+      for configname, config in configs.iteritems():
+        getattr(self, field)[configname] = config.get(field, default())
+
+    self.msvs_cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])
+
+    unsupported_fields = [
+        'msvs_prebuild',
+        'msvs_postbuild',
+    ]
+    unsupported = []
+    for field in unsupported_fields:
+      for config in configs.values():
+        if field in config:
+          unsupported += ["%s not supported (target %s)." %
+                          (field, spec['target_name'])]
+    if unsupported:
+      raise Exception('\n'.join(unsupported))
+
+  def GetVSMacroEnv(self, base_to_build=None, config=None):
+    """Get a dict of variables mapping internal VS macro names to their gyp
+    equivalents."""
+    target_platform = 'Win32' if self.GetArch(config) == 'x86' else 'x64'
+    target_name = self.spec.get('product_prefix', '') + \
+        self.spec.get('product_name', self.spec['target_name'])
+    target_dir = base_to_build + '\\' if base_to_build else ''
+    replacements = {
+        '$(OutDir)\\': target_dir,
+        '$(TargetDir)\\': target_dir,
+        '$(IntDir)': '$!INTERMEDIATE_DIR',
+        '$(InputPath)': '${source}',
+        '$(InputName)': '${root}',
+        '$(ProjectName)': self.spec['target_name'],
+        '$(TargetName)': target_name,
+        '$(PlatformName)': target_platform,
+        '$(ProjectDir)\\': '',
+    }
+    replacements.update(GetGlobalVSMacroEnv(self.vs_version))
+    return replacements
+
+  def ConvertVSMacros(self, s, base_to_build=None, config=None):
+    """Convert from VS macro names to something equivalent."""
+    env = self.GetVSMacroEnv(base_to_build, config=config)
+    return ExpandMacros(s, env)
+
+  def AdjustLibraries(self, libraries):
+    """Strip -l from library if it's specified with that."""
+    libs = [lib[2:] if lib.startswith('-l') else lib for lib in libraries]
+    return [lib + '.lib' if not lib.endswith('.lib') else lib for lib in libs]
+
+  def _GetAndMunge(self, field, path, default, prefix, append, map):
+    """Retrieve a value from |field| at |path| or return |default|. If
+    |append| is specified, and the item is found, it will be appended to that
+    object instead of returned. If |map| is specified, results will be
+    remapped through |map| before being returned or appended."""
+    result = _GenericRetrieve(field, default, path)
+    result = _DoRemapping(result, map)
+    result = _AddPrefix(result, prefix)
+    return _AppendOrReturn(append, result)
+
+  class _GetWrapper(object):
+    def __init__(self, parent, field, base_path, append=None):
+      self.parent = parent
+      self.field = field
+      self.base_path = [base_path]
+      self.append = append
+    def __call__(self, name, map=None, prefix='', default=None):
+      return self.parent._GetAndMunge(self.field, self.base_path + [name],
+          default=default, prefix=prefix, append=self.append, map=map)
+
+  def GetArch(self, config):
+    """Get architecture based on msvs_configuration_platform and
+    msvs_target_platform. Returns either 'x86' or 'x64'."""
+    configuration_platform = self.msvs_configuration_platform.get(config, '')
+    platform = self.msvs_target_platform.get(config, '')
+    if not platform: # If no specific override, use the configuration's.
+      platform = configuration_platform
+    # Map from platform to architecture.
+    return {'Win32': 'x86', 'x64': 'x64'}.get(platform, 'x86')
+
+  def _TargetConfig(self, config):
+    """Returns the target-specific configuration."""
+    # There's two levels of architecture/platform specification in VS. The
+    # first level is globally for the configuration (this is what we consider
+    # "the" config at the gyp level, which will be something like 'Debug' or
+    # 'Release_x64'), and a second target-specific configuration, which is an
+    # override for the global one. |config| is remapped here to take into
+    # account the local target-specific overrides to the global configuration.
+    arch = self.GetArch(config)
+    if arch == 'x64' and not config.endswith('_x64'):
+      config += '_x64'
+    if arch == 'x86' and config.endswith('_x64'):
+      config = config.rsplit('_', 1)[0]
+    return config
+
+  def _Setting(self, path, config,
+              default=None, prefix='', append=None, map=None):
+    """_GetAndMunge for msvs_settings."""
+    return self._GetAndMunge(
+        self.msvs_settings[config], path, default, prefix, append, map)
+
+  def _ConfigAttrib(self, path, config,
+                   default=None, prefix='', append=None, map=None):
+    """_GetAndMunge for msvs_configuration_attributes."""
+    return self._GetAndMunge(
+        self.msvs_configuration_attributes[config],
+        path, default, prefix, append, map)
+
+  def AdjustIncludeDirs(self, include_dirs, config):
+    """Updates include_dirs to expand VS specific paths, and adds the system
+    include dirs used for platform SDK and similar."""
+    config = self._TargetConfig(config)
+    includes = include_dirs + self.msvs_system_include_dirs[config]
+    includes.extend(self._Setting(
+      ('VCCLCompilerTool', 'AdditionalIncludeDirectories'), config, default=[]))
+    return [self.ConvertVSMacros(p, config=config) for p in includes]
+
+  def GetComputedDefines(self, config):
+    """Returns the set of defines that are injected to the defines list based
+    on other VS settings."""
+    config = self._TargetConfig(config)
+    defines = []
+    if self._ConfigAttrib(['CharacterSet'], config) == '1':
+      defines.extend(('_UNICODE', 'UNICODE'))
+    if self._ConfigAttrib(['CharacterSet'], config) == '2':
+      defines.append('_MBCS')
+    defines.extend(self._Setting(
+        ('VCCLCompilerTool', 'PreprocessorDefinitions'), config, default=[]))
+    return defines
+
+  def GetCompilerPdbName(self, config, expand_special):
+    """Get the pdb file name that should be used for compiler invocations, or
+    None if there's no explicit name specified."""
+    config = self._TargetConfig(config)
+    pdbname = self._Setting(
+        ('VCCLCompilerTool', 'ProgramDataBaseFileName'), config)
+    if pdbname:
+      pdbname = expand_special(self.ConvertVSMacros(pdbname))
+    return pdbname
+
+  def GetMapFileName(self, config, expand_special):
+    """Gets the explicitly overriden map file name for a target or returns None
+    if it's not set."""
+    config = self._TargetConfig(config)
+    map_file = self._Setting(('VCLinkerTool', 'MapFileName'), config)
+    if map_file:
+      map_file = expand_special(self.ConvertVSMacros(map_file, config=config))
+    return map_file
+
+  def GetOutputName(self, config, expand_special):
+    """Gets the explicitly overridden output name for a target or returns None
+    if it's not overridden."""
+    config = self._TargetConfig(config)
+    type = self.spec['type']
+    root = 'VCLibrarianTool' if type == 'static_library' else 'VCLinkerTool'
+    # TODO(scottmg): Handle OutputDirectory without OutputFile.
+    output_file = self._Setting((root, 'OutputFile'), config)
+    if output_file:
+      output_file = expand_special(self.ConvertVSMacros(
+          output_file, config=config))
+    return output_file
+
+  def GetPDBName(self, config, expand_special, default):
+    """Gets the explicitly overridden pdb name for a target or returns
+    default if it's not overridden, or if no pdb will be generated."""
+    config = self._TargetConfig(config)
+    output_file = self._Setting(('VCLinkerTool', 'ProgramDatabaseFile'), config)
+    generate_debug_info = self._Setting(
+        ('VCLinkerTool', 'GenerateDebugInformation'), config)
+    if generate_debug_info:
+      if output_file:
+        return expand_special(self.ConvertVSMacros(output_file, config=config))
+      else:
+        return default
+    else:
+      return None
+
+  def GetAsmflags(self, config):
+    """Returns the flags that need to be added to ml invocations."""
+    config = self._TargetConfig(config)
+    asmflags = []
+    safeseh = self._Setting(('MASM', 'UseSafeExceptionHandlers'), config)
+    if safeseh == 'true':
+      asmflags.append('/safeseh')
+    return asmflags
+
+  def GetCflags(self, config):
+    """Returns the flags that need to be added to .c and .cc compilations."""
+    config = self._TargetConfig(config)
+    cflags = []
+    cflags.extend(['/wd' + w for w in self.msvs_disabled_warnings[config]])
+    cl = self._GetWrapper(self, self.msvs_settings[config],
+                          'VCCLCompilerTool', append=cflags)
+    cl('Optimization',
+       map={'0': 'd', '1': '1', '2': '2', '3': 'x'}, prefix='/O', default='2')
+    cl('InlineFunctionExpansion', prefix='/Ob')
+    cl('DisableSpecificWarnings', prefix='/wd')
+    cl('StringPooling', map={'true': '/GF'})
+    cl('EnableFiberSafeOptimizations', map={'true': '/GT'})
+    cl('OmitFramePointers', map={'false': '-', 'true': ''}, prefix='/Oy')
+    cl('EnableIntrinsicFunctions', map={'false': '-', 'true': ''}, prefix='/Oi')
+    cl('FavorSizeOrSpeed', map={'1': 't', '2': 's'}, prefix='/O')
+    cl('WholeProgramOptimization', map={'true': '/GL'})
+    cl('WarningLevel', prefix='/W')
+    cl('WarnAsError', map={'true': '/WX'})
+    cl('DebugInformationFormat',
+        map={'1': '7', '3': 'i', '4': 'I'}, prefix='/Z')
+    cl('RuntimeTypeInfo', map={'true': '/GR', 'false': '/GR-'})
+    cl('EnableFunctionLevelLinking', map={'true': '/Gy', 'false': '/Gy-'})
+    cl('MinimalRebuild', map={'true': '/Gm'})
+    cl('BufferSecurityCheck', map={'true': '/GS', 'false': '/GS-'})
+    cl('BasicRuntimeChecks', map={'1': 's', '2': 'u', '3': '1'}, prefix='/RTC')
+    cl('RuntimeLibrary',
+        map={'0': 'T', '1': 'Td', '2': 'D', '3': 'Dd'}, prefix='/M')
+    cl('ExceptionHandling', map={'1': 'sc','2': 'a'}, prefix='/EH')
+    cl('DefaultCharIsUnsigned', map={'true': '/J'})
+    cl('TreatWChar_tAsBuiltInType',
+        map={'false': '-', 'true': ''}, prefix='/Zc:wchar_t')
+    cl('EnablePREfast', map={'true': '/analyze'})
+    cl('AdditionalOptions', prefix='')
+    cl('EnableEnhancedInstructionSet',
+       map={'1': 'SSE', '2': 'SSE2', '3': 'AVX', '4': 'IA32'}, prefix='/arch:')
+    cflags.extend(['/FI' + f for f in self._Setting(
+        ('VCCLCompilerTool', 'ForcedIncludeFiles'), config, default=[])])
+    if self.vs_version.short_name in ('2013', '2013e'):
+      # New flag required in 2013 to maintain previous PDB behavior.
+      cflags.append('/FS')
+    # ninja handles parallelism by itself, don't have the compiler do it too.
+    cflags = filter(lambda x: not x.startswith('/MP'), cflags)
+    return cflags
+
+  def _GetPchFlags(self, config, extension):
+    """Get the flags to be added to the cflags for precompiled header support.
+    """
+    config = self._TargetConfig(config)
+    # The PCH is only built once by a particular source file. Usage of PCH must
+    # only be for the same language (i.e. C vs. C++), so only include the pch
+    # flags when the language matches.
+    if self.msvs_precompiled_header[config]:
+      source_ext = os.path.splitext(self.msvs_precompiled_source[config])[1]
+      if _LanguageMatchesForPch(source_ext, extension):
+        pch = os.path.split(self.msvs_precompiled_header[config])[1]
+        return ['/Yu' + pch, '/FI' + pch, '/Fp${pchprefix}.' + pch + '.pch']
+    return  []
+
+  def GetCflagsC(self, config):
+    """Returns the flags that need to be added to .c compilations."""
+    config = self._TargetConfig(config)
+    return self._GetPchFlags(config, '.c')
+
+  def GetCflagsCC(self, config):
+    """Returns the flags that need to be added to .cc compilations."""
+    config = self._TargetConfig(config)
+    return ['/TP'] + self._GetPchFlags(config, '.cc')
+
+  def _GetAdditionalLibraryDirectories(self, root, config, gyp_to_build_path):
+    """Get and normalize the list of paths in AdditionalLibraryDirectories
+    setting."""
+    config = self._TargetConfig(config)
+    libpaths = self._Setting((root, 'AdditionalLibraryDirectories'),
+                             config, default=[])
+    libpaths = [os.path.normpath(
+                    gyp_to_build_path(self.ConvertVSMacros(p, config=config)))
+                for p in libpaths]
+    return ['/LIBPATH:"' + p + '"' for p in libpaths]
+
+  def GetLibFlags(self, config, gyp_to_build_path):
+    """Returns the flags that need to be added to lib commands."""
+    config = self._TargetConfig(config)
+    libflags = []
+    lib = self._GetWrapper(self, self.msvs_settings[config],
+                          'VCLibrarianTool', append=libflags)
+    libflags.extend(self._GetAdditionalLibraryDirectories(
+        'VCLibrarianTool', config, gyp_to_build_path))
+    lib('LinkTimeCodeGeneration', map={'true': '/LTCG'})
+    lib('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:')
+    lib('AdditionalOptions')
+    return libflags
+
+  def GetDefFile(self, gyp_to_build_path):
+    """Returns the .def file from sources, if any.  Otherwise returns None."""
+    spec = self.spec
+    if spec['type'] in ('shared_library', 'loadable_module', 'executable'):
+      def_files = [s for s in spec.get('sources', []) if s.endswith('.def')]
+      if len(def_files) == 1:
+        return gyp_to_build_path(def_files[0])
+      elif len(def_files) > 1:
+        raise Exception("Multiple .def files")
+    return None
+
+  def _GetDefFileAsLdflags(self, ldflags, gyp_to_build_path):
+    """.def files get implicitly converted to a ModuleDefinitionFile for the
+    linker in the VS generator. Emulate that behaviour here."""
+    def_file = self.GetDefFile(gyp_to_build_path)
+    if def_file:
+      ldflags.append('/DEF:"%s"' % def_file)
+
+  def GetPGDName(self, config, expand_special):
+    """Gets the explicitly overridden pgd name for a target or returns None
+    if it's not overridden."""
+    config = self._TargetConfig(config)
+    output_file = self._Setting(
+        ('VCLinkerTool', 'ProfileGuidedDatabase'), config)
+    if output_file:
+      output_file = expand_special(self.ConvertVSMacros(
+          output_file, config=config))
+    return output_file
+
+  def GetLdflags(self, config, gyp_to_build_path, expand_special,
+                 manifest_base_name, output_name, is_executable, build_dir):
+    """Returns the flags that need to be added to link commands, and the
+    manifest files."""
+    config = self._TargetConfig(config)
+    ldflags = []
+    ld = self._GetWrapper(self, self.msvs_settings[config],
+                          'VCLinkerTool', append=ldflags)
+    self._GetDefFileAsLdflags(ldflags, gyp_to_build_path)
+    ld('GenerateDebugInformation', map={'true': '/DEBUG'})
+    ld('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:')
+    ldflags.extend(self._GetAdditionalLibraryDirectories(
+        'VCLinkerTool', config, gyp_to_build_path))
+    ld('DelayLoadDLLs', prefix='/DELAYLOAD:')
+    ld('TreatLinkerWarningAsErrors', prefix='/WX',
+       map={'true': '', 'false': ':NO'})
+    out = self.GetOutputName(config, expand_special)
+    if out:
+      ldflags.append('/OUT:' + out)
+    pdb = self.GetPDBName(config, expand_special, output_name + '.pdb')
+    if pdb:
+      ldflags.append('/PDB:' + pdb)
+    pgd = self.GetPGDName(config, expand_special)
+    if pgd:
+      ldflags.append('/PGD:' + pgd)
+    map_file = self.GetMapFileName(config, expand_special)
+    ld('GenerateMapFile', map={'true': '/MAP:' + map_file if map_file
+        else '/MAP'})
+    ld('MapExports', map={'true': '/MAPINFO:EXPORTS'})
+    ld('AdditionalOptions', prefix='')
+
+    minimum_required_version = self._Setting(
+        ('VCLinkerTool', 'MinimumRequiredVersion'), config, default='')
+    if minimum_required_version:
+      minimum_required_version = ',' + minimum_required_version
+    ld('SubSystem',
+       map={'1': 'CONSOLE%s' % minimum_required_version,
+            '2': 'WINDOWS%s' % minimum_required_version},
+       prefix='/SUBSYSTEM:')
+
+    ld('TerminalServerAware', map={'1': ':NO', '2': ''}, prefix='/TSAWARE')
+    ld('LinkIncremental', map={'1': ':NO', '2': ''}, prefix='/INCREMENTAL')
+    ld('BaseAddress', prefix='/BASE:')
+    ld('FixedBaseAddress', map={'1': ':NO', '2': ''}, prefix='/FIXED')
+    ld('RandomizedBaseAddress',
+        map={'1': ':NO', '2': ''}, prefix='/DYNAMICBASE')
+    ld('DataExecutionPrevention',
+        map={'1': ':NO', '2': ''}, prefix='/NXCOMPAT')
+    ld('OptimizeReferences', map={'1': 'NOREF', '2': 'REF'}, prefix='/OPT:')
+    ld('ForceSymbolReferences', prefix='/INCLUDE:')
+    ld('EnableCOMDATFolding', map={'1': 'NOICF', '2': 'ICF'}, prefix='/OPT:')
+    ld('LinkTimeCodeGeneration',
+        map={'1': '', '2': ':PGINSTRUMENT', '3': ':PGOPTIMIZE',
+             '4': ':PGUPDATE'},
+        prefix='/LTCG')
+    ld('IgnoreDefaultLibraryNames', prefix='/NODEFAULTLIB:')
+    ld('ResourceOnlyDLL', map={'true': '/NOENTRY'})
+    ld('EntryPointSymbol', prefix='/ENTRY:')
+    ld('Profile', map={'true': '/PROFILE'})
+    ld('LargeAddressAware',
+        map={'1': ':NO', '2': ''}, prefix='/LARGEADDRESSAWARE')
+    ld('ImageHasSafeExceptionHandlers', map={'true': '/SAFESEH'})
+    # TODO(scottmg): This should sort of be somewhere else (not really a flag).
+    ld('AdditionalDependencies', prefix='')
+
+    # If the base address is not specifically controlled, DYNAMICBASE should
+    # be on by default.
+    base_flags = filter(lambda x: 'DYNAMICBASE' in x or x == '/FIXED',
+                        ldflags)
+    if not base_flags:
+      ldflags.append('/DYNAMICBASE')
+
+    # If the NXCOMPAT flag has not been specified, default to on. Despite the
+    # documentation that says this only defaults to on when the subsystem is
+    # Vista or greater (which applies to the linker), the IDE defaults it on
+    # unless it's explicitly off.
+    if not filter(lambda x: 'NXCOMPAT' in x, ldflags):
+      ldflags.append('/NXCOMPAT')
+
+    have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags)
+    manifest_flags, intermediate_manifest, manifest_files = \
+        self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path,
+                                 is_executable and not have_def_file, build_dir)
+    ldflags.extend(manifest_flags)
+    return ldflags, intermediate_manifest, manifest_files
+
+  def _GetLdManifestFlags(self, config, name, gyp_to_build_path,
+                          allow_isolation, build_dir):
+    """Returns a 3-tuple:
+    - the set of flags that need to be added to the link to generate
+      a default manifest
+    - the intermediate manifest that the linker will generate that should be
+      used to assert it doesn't add anything to the merged one.
+    - the list of all the manifest files to be merged by the manifest tool and
+      included into the link."""
+    generate_manifest = self._Setting(('VCLinkerTool', 'GenerateManifest'),
+                                      config,
+                                      default='true')
+    if generate_manifest != 'true':
+      # This means not only that the linker should not generate the intermediate
+      # manifest but also that the manifest tool should do nothing even when
+      # additional manifests are specified.
+      return ['/MANIFEST:NO'], [], []
+
+    output_name = name + '.intermediate.manifest'
+    flags = [
+      '/MANIFEST',
+      '/ManifestFile:' + output_name,
+    ]
+
+    # Instead of using the MANIFESTUAC flags, we generate a .manifest to
+    # include into the list of manifests. This allows us to avoid the need to
+    # do two passes during linking. The /MANIFEST flag and /ManifestFile are
+    # still used, and the intermediate manifest is used to assert that the
+    # final manifest we get from merging all the additional manifest files
+    # (plus the one we generate here) isn't modified by merging the
+    # intermediate into it.
+
+    # Always NO, because we generate a manifest file that has what we want.
+    flags.append('/MANIFESTUAC:NO')
+
+    config = self._TargetConfig(config)
+    enable_uac = self._Setting(('VCLinkerTool', 'EnableUAC'), config,
+                               default='true')
+    manifest_files = []
+    generated_manifest_outer = \
+"<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" \
+"<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>%s" \
+"</assembly>"
+    if enable_uac == 'true':
+      execution_level = self._Setting(('VCLinkerTool', 'UACExecutionLevel'),
+                                      config, default='0')
+      execution_level_map = {
+        '0': 'asInvoker',
+        '1': 'highestAvailable',
+        '2': 'requireAdministrator'
+      }
+
+      ui_access = self._Setting(('VCLinkerTool', 'UACUIAccess'), config,
+                                default='false')
+
+      inner = '''
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+  <security>
+    <requestedPrivileges>
+      <requestedExecutionLevel level='%s' uiAccess='%s' />
+    </requestedPrivileges>
+  </security>
+</trustInfo>''' % (execution_level_map[execution_level], ui_access)
+    else:
+      inner = ''
+
+    generated_manifest_contents = generated_manifest_outer % inner
+    generated_name = name + '.generated.manifest'
+    # Need to join with the build_dir here as we're writing it during
+    # generation time, but we return the un-joined version because the build
+    # will occur in that directory. We only write the file if the contents
+    # have changed so that simply regenerating the project files doesn't
+    # cause a relink.
+    build_dir_generated_name = os.path.join(build_dir, generated_name)
+    gyp.common.EnsureDirExists(build_dir_generated_name)
+    f = gyp.common.WriteOnDiff(build_dir_generated_name)
+    f.write(generated_manifest_contents)
+    f.close()
+    manifest_files = [generated_name]
+
+    if allow_isolation:
+      flags.append('/ALLOWISOLATION')
+
+    manifest_files += self._GetAdditionalManifestFiles(config,
+                                                       gyp_to_build_path)
+    return flags, output_name, manifest_files
+
+  def _GetAdditionalManifestFiles(self, config, gyp_to_build_path):
+    """Gets additional manifest files that are added to the default one
+    generated by the linker."""
+    files = self._Setting(('VCManifestTool', 'AdditionalManifestFiles'), config,
+                          default=[])
+    if isinstance(files, str):
+      files = files.split(';')
+    return [os.path.normpath(
+                gyp_to_build_path(self.ConvertVSMacros(f, config=config)))
+            for f in files]
+
+  def IsUseLibraryDependencyInputs(self, config):
+    """Returns whether the target should be linked via Use Library Dependency
+    Inputs (using component .objs of a given .lib)."""
+    config = self._TargetConfig(config)
+    uldi = self._Setting(('VCLinkerTool', 'UseLibraryDependencyInputs'), config)
+    return uldi == 'true'
+
+  def IsEmbedManifest(self, config):
+    """Returns whether manifest should be linked into binary."""
+    config = self._TargetConfig(config)
+    embed = self._Setting(('VCManifestTool', 'EmbedManifest'), config,
+                          default='true')
+    return embed == 'true'
+
+  def IsLinkIncremental(self, config):
+    """Returns whether the target should be linked incrementally."""
+    config = self._TargetConfig(config)
+    link_inc = self._Setting(('VCLinkerTool', 'LinkIncremental'), config)
+    return link_inc != '1'
+
+  def GetRcflags(self, config, gyp_to_ninja_path):
+    """Returns the flags that need to be added to invocations of the resource
+    compiler."""
+    config = self._TargetConfig(config)
+    rcflags = []
+    rc = self._GetWrapper(self, self.msvs_settings[config],
+        'VCResourceCompilerTool', append=rcflags)
+    rc('AdditionalIncludeDirectories', map=gyp_to_ninja_path, prefix='/I')
+    rcflags.append('/I' + gyp_to_ninja_path('.'))
+    rc('PreprocessorDefinitions', prefix='/d')
+    # /l arg must be in hex without leading '0x'
+    rc('Culture', prefix='/l', map=lambda x: hex(int(x))[2:])
+    return rcflags
+
+  def BuildCygwinBashCommandLine(self, args, path_to_base):
+    """Build a command line that runs args via cygwin bash. We assume that all
+    incoming paths are in Windows normpath'd form, so they need to be
+    converted to posix style for the part of the command line that's passed to
+    bash. We also have to do some Visual Studio macro emulation here because
+    various rules use magic VS names for things. Also note that rules that
+    contain ninja variables cannot be fixed here (for example ${source}), so
+    the outer generator needs to make sure that the paths that are written out
+    are in posix style, if the command line will be used here."""
+    cygwin_dir = os.path.normpath(
+        os.path.join(path_to_base, self.msvs_cygwin_dirs[0]))
+    cd = ('cd %s' % path_to_base).replace('\\', '/')
+    args = [a.replace('\\', '/').replace('"', '\\"') for a in args]
+    args = ["'%s'" % a.replace("'", "'\\''") for a in args]
+    bash_cmd = ' '.join(args)
+    cmd = (
+        'call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir +
+        'bash -c "%s ; %s"' % (cd, bash_cmd))
+    return cmd
+
+  def IsRuleRunUnderCygwin(self, rule):
+    """Determine if an action should be run under cygwin. If the variable is
+    unset, or set to 1 we use cygwin."""
+    return int(rule.get('msvs_cygwin_shell',
+                        self.spec.get('msvs_cygwin_shell', 1))) != 0
+
+  def _HasExplicitRuleForExtension(self, spec, extension):
+    """Determine if there's an explicit rule for a particular extension."""
+    for rule in spec.get('rules', []):
+      if rule['extension'] == extension:
+        return True
+    return False
+
+  def _HasExplicitIdlActions(self, spec):
+    """Determine if an action should not run midl for .idl files."""
+    return any([action.get('explicit_idl_action', 0)
+                for action in spec.get('actions', [])])
+
+  def HasExplicitIdlRulesOrActions(self, spec):
+    """Determine if there's an explicit rule or action for idl files. When
+    there isn't we need to generate implicit rules to build MIDL .idl files."""
+    return (self._HasExplicitRuleForExtension(spec, 'idl') or
+            self._HasExplicitIdlActions(spec))
+
+  def HasExplicitAsmRules(self, spec):
+    """Determine if there's an explicit rule for asm files. When there isn't we
+    need to generate implicit rules to assemble .asm files."""
+    return self._HasExplicitRuleForExtension(spec, 'asm')
+
+  def GetIdlBuildData(self, source, config):
+    """Determine the implicit outputs for an idl file. Returns output
+    directory, outputs, and variables and flags that are required."""
+    config = self._TargetConfig(config)
+    midl_get = self._GetWrapper(self, self.msvs_settings[config], 'VCMIDLTool')
+    def midl(name, default=None):
+      return self.ConvertVSMacros(midl_get(name, default=default),
+                                  config=config)
+    tlb = midl('TypeLibraryName', default='${root}.tlb')
+    header = midl('HeaderFileName', default='${root}.h')
+    dlldata = midl('DLLDataFileName', default='dlldata.c')
+    iid = midl('InterfaceIdentifierFileName', default='${root}_i.c')
+    proxy = midl('ProxyFileName', default='${root}_p.c')
+    # Note that .tlb is not included in the outputs as it is not always
+    # generated depending on the content of the input idl file.
+    outdir = midl('OutputDirectory', default='')
+    output = [header, dlldata, iid, proxy]
+    variables = [('tlb', tlb),
+                 ('h', header),
+                 ('dlldata', dlldata),
+                 ('iid', iid),
+                 ('proxy', proxy)]
+    # TODO(scottmg): Are there configuration settings to set these flags?
+    target_platform = 'win32' if self.GetArch(config) == 'x86' else 'x64'
+    flags = ['/char', 'signed', '/env', target_platform, '/Oicf']
+    return outdir, output, variables, flags
+
+
+def _LanguageMatchesForPch(source_ext, pch_source_ext):
+  c_exts = ('.c',)
+  cc_exts = ('.cc', '.cxx', '.cpp')
+  return ((source_ext in c_exts and pch_source_ext in c_exts) or
+          (source_ext in cc_exts and pch_source_ext in cc_exts))
+
+
+class PrecompiledHeader(object):
+  """Helper to generate dependencies and build rules to handle generation of
+  precompiled headers. Interface matches the GCH handler in xcode_emulation.py.
+  """
+  def __init__(
+      self, settings, config, gyp_to_build_path, gyp_to_unique_output, obj_ext):
+    self.settings = settings
+    self.config = config
+    pch_source = self.settings.msvs_precompiled_source[self.config]
+    self.pch_source = gyp_to_build_path(pch_source)
+    filename, _ = os.path.splitext(pch_source)
+    self.output_obj = gyp_to_unique_output(filename + obj_ext).lower()
+
+  def _PchHeader(self):
+    """Get the header that will appear in an #include line for all source
+    files."""
+    return os.path.split(self.settings.msvs_precompiled_header[self.config])[1]
+
+  def GetObjDependencies(self, sources, objs, arch):
+    """Given a list of sources files and the corresponding object files,
+    returns a list of the pch files that should be depended upon. The
+    additional wrapping in the return value is for interface compatibility
+    with make.py on Mac, and xcode_emulation.py."""
+    assert arch is None
+    if not self._PchHeader():
+      return []
+    pch_ext = os.path.splitext(self.pch_source)[1]
+    for source in sources:
+      if _LanguageMatchesForPch(os.path.splitext(source)[1], pch_ext):
+        return [(None, None, self.output_obj)]
+    return []
+
+  def GetPchBuildCommands(self, arch):
+    """Not used on Windows as there are no additional build steps required
+    (instead, existing steps are modified in GetFlagsModifications below)."""
+    return []
+
+  def GetFlagsModifications(self, input, output, implicit, command,
+                            cflags_c, cflags_cc, expand_special):
+    """Get the modified cflags and implicit dependencies that should be used
+    for the pch compilation step."""
+    if input == self.pch_source:
+      pch_output = ['/Yc' + self._PchHeader()]
+      if command == 'cxx':
+        return ([('cflags_cc', map(expand_special, cflags_cc + pch_output))],
+                self.output_obj, [])
+      elif command == 'cc':
+        return ([('cflags_c', map(expand_special, cflags_c + pch_output))],
+                self.output_obj, [])
+    return [], output, implicit
+
+
+vs_version = None
+def GetVSVersion(generator_flags):
+  global vs_version
+  if not vs_version:
+    vs_version = gyp.MSVSVersion.SelectVisualStudioVersion(
+        generator_flags.get('msvs_version', 'auto'))
+  return vs_version
+
+def _GetVsvarsSetupArgs(generator_flags, arch):
+  vs = GetVSVersion(generator_flags)
+  return vs.SetupScript()
+
+def ExpandMacros(string, expansions):
+  """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv
+  for the canonical way to retrieve a suitable dict."""
+  if '$' in string:
+    for old, new in expansions.iteritems():
+      assert '$(' not in new, new
+      string = string.replace(old, new)
+  return string
+
+def _ExtractImportantEnvironment(output_of_set):
+  """Extracts environment variables required for the toolchain to run from
+  a textual dump output by the cmd.exe 'set' command."""
+  envvars_to_save = (
+      'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
+      'include',
+      'lib',
+      'libpath',
+      'path',
+      'pathext',
+      'systemroot',
+      'temp',
+      'tmp',
+      )
+  env = {}
+  for line in output_of_set.splitlines():
+    for envvar in envvars_to_save:
+      if re.match(envvar + '=', line.lower()):
+        var, setting = line.split('=', 1)
+        if envvar == 'path':
+          # Our own rules (for running gyp-win-tool) and other actions in
+          # Chromium rely on python being in the path. Add the path to this
+          # python here so that if it's not in the path when ninja is run
+          # later, python will still be found.
+          setting = os.path.dirname(sys.executable) + os.pathsep + setting
+        env[var.upper()] = setting
+        break
+  for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
+    if required not in env:
+      raise Exception('Environment variable "%s" '
+                      'required to be set to valid path' % required)
+  return env
+
+def _FormatAsEnvironmentBlock(envvar_dict):
+  """Format as an 'environment block' directly suitable for CreateProcess.
+  Briefly this is a list of key=value\0, terminated by an additional \0. See
+  CreateProcess documentation for more details."""
+  block = ''
+  nul = '\0'
+  for key, value in envvar_dict.iteritems():
+    block += key + '=' + value + nul
+  block += nul
+  return block
+
+def _ExtractCLPath(output_of_where):
+  """Gets the path to cl.exe based on the output of calling the environment
+  setup batch file, followed by the equivalent of `where`."""
+  # Take the first line, as that's the first found in the PATH.
+  for line in output_of_where.strip().splitlines():
+    if line.startswith('LOC:'):
+      return line[len('LOC:'):].strip()
+
+def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags,
+                             system_includes, open_out):
+  """It's not sufficient to have the absolute path to the compiler, linker,
+  etc. on Windows, as those tools rely on .dlls being in the PATH. We also
+  need to support both x86 and x64 compilers within the same build (to support
+  msvs_target_platform hackery). Different architectures require a different
+  compiler binary, and different supporting environment variables (INCLUDE,
+  LIB, LIBPATH). So, we extract the environment here, wrap all invocations
+  of compiler tools (cl, link, lib, rc, midl, etc.) via win_tool.py which
+  sets up the environment, and then we do not prefix the compiler with
+  an absolute path, instead preferring something like "cl.exe" in the rule
+  which will then run whichever the environment setup has put in the path.
+  When the following procedure to generate environment files does not
+  meet your requirement (e.g. for custom toolchains), you can pass
+  "-G ninja_use_custom_environment_files" to the gyp to suppress file
+  generation and use custom environment files prepared by yourself."""
+  archs = ('x86', 'x64')
+  if generator_flags.get('ninja_use_custom_environment_files', 0):
+    cl_paths = {}
+    for arch in archs:
+      cl_paths[arch] = 'cl.exe'
+    return cl_paths
+  vs = GetVSVersion(generator_flags)
+  cl_paths = {}
+  for arch in archs:
+    # Extract environment variables for subprocesses.
+    args = vs.SetupScript(arch)
+    args.extend(('&&', 'set'))
+    popen = subprocess.Popen(
+        args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    variables, _ = popen.communicate()
+    env = _ExtractImportantEnvironment(variables)
+
+    # Inject system includes from gyp files into INCLUDE.
+    if system_includes:
+      system_includes = system_includes | OrderedSet(
+                                              env.get('INCLUDE', '').split(';'))
+      env['INCLUDE'] = ';'.join(system_includes)
+
+    env_block = _FormatAsEnvironmentBlock(env)
+    f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb')
+    f.write(env_block)
+    f.close()
+
+    # Find cl.exe location for this architecture.
+    args = vs.SetupScript(arch)
+    args.extend(('&&',
+      'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i'))
+    popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE)
+    output, _ = popen.communicate()
+    cl_paths[arch] = _ExtractCLPath(output)
+  return cl_paths
+
+def VerifyMissingSources(sources, build_dir, generator_flags, gyp_to_ninja):
+  """Emulate behavior of msvs_error_on_missing_sources present in the msvs
+  generator: Check that all regular source files, i.e. not created at run time,
+  exist on disk. Missing files cause needless recompilation when building via
+  VS, and we want this check to match for people/bots that build using ninja,
+  so they're not surprised when the VS build fails."""
+  if int(generator_flags.get('msvs_error_on_missing_sources', 0)):
+    no_specials = filter(lambda x: '$' not in x, sources)
+    relative = [os.path.join(build_dir, gyp_to_ninja(s)) for s in no_specials]
+    missing = filter(lambda x: not os.path.exists(x), relative)
+    if missing:
+      # They'll look like out\Release\..\..\stuff\things.cc, so normalize the
+      # path for a slightly less crazy looking output.
+      cleaned_up = [os.path.normpath(x) for x in missing]
+      raise Exception('Missing input files:\n%s' % '\n'.join(cleaned_up))
+
+# Sets some values in default_variables, which are required for many
+# generators, run on Windows.
+def CalculateCommonVariables(default_variables, params):
+  generator_flags = params.get('generator_flags', {})
+
+  # Set a variable so conditions can be based on msvs_version.
+  msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags)
+  default_variables['MSVS_VERSION'] = msvs_version.ShortName()
+
+  # To determine processor word size on Windows, in addition to checking
+  # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
+  # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which
+  # contains the actual word size of the system when running thru WOW64).
+  if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or
+      '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')):
+    default_variables['MSVS_OS_BITS'] = 64
+  else:
+    default_variables['MSVS_OS_BITS'] = 32
diff --git a/gyp/pylib/gyp/ninja_syntax.py b/gyp/pylib/gyp/ninja_syntax.py
new file mode 100644 (file)
index 0000000..d2948f0
--- /dev/null
@@ -0,0 +1,160 @@
+# This file comes from
+#   https://github.com/martine/ninja/blob/master/misc/ninja_syntax.py
+# Do not edit!  Edit the upstream one instead.
+
+"""Python module for generating .ninja files.
+
+Note that this is emphatically not a required piece of Ninja; it's
+just a helpful utility for build-file-generation systems that already
+use Python.
+"""
+
+import textwrap
+import re
+
+def escape_path(word):
+    return word.replace('$ ','$$ ').replace(' ','$ ').replace(':', '$:')
+
+class Writer(object):
+    def __init__(self, output, width=78):
+        self.output = output
+        self.width = width
+
+    def newline(self):
+        self.output.write('\n')
+
+    def comment(self, text):
+        for line in textwrap.wrap(text, self.width - 2):
+            self.output.write('# ' + line + '\n')
+
+    def variable(self, key, value, indent=0):
+        if value is None:
+            return
+        if isinstance(value, list):
+            value = ' '.join(filter(None, value))  # Filter out empty strings.
+        self._line('%s = %s' % (key, value), indent)
+
+    def pool(self, name, depth):
+        self._line('pool %s' % name)
+        self.variable('depth', depth, indent=1)
+
+    def rule(self, name, command, description=None, depfile=None,
+             generator=False, pool=None, restat=False, rspfile=None,
+             rspfile_content=None, deps=None):
+        self._line('rule %s' % name)
+        self.variable('command', command, indent=1)
+        if description:
+            self.variable('description', description, indent=1)
+        if depfile:
+            self.variable('depfile', depfile, indent=1)
+        if generator:
+            self.variable('generator', '1', indent=1)
+        if pool:
+            self.variable('pool', pool, indent=1)
+        if restat:
+            self.variable('restat', '1', indent=1)
+        if rspfile:
+            self.variable('rspfile', rspfile, indent=1)
+        if rspfile_content:
+            self.variable('rspfile_content', rspfile_content, indent=1)
+        if deps:
+            self.variable('deps', deps, indent=1)
+
+    def build(self, outputs, rule, inputs=None, implicit=None, order_only=None,
+              variables=None):
+        outputs = self._as_list(outputs)
+        all_inputs = self._as_list(inputs)[:]
+        out_outputs = list(map(escape_path, outputs))
+        all_inputs = list(map(escape_path, all_inputs))
+
+        if implicit:
+            implicit = map(escape_path, self._as_list(implicit))
+            all_inputs.append('|')
+            all_inputs.extend(implicit)
+        if order_only:
+            order_only = map(escape_path, self._as_list(order_only))
+            all_inputs.append('||')
+            all_inputs.extend(order_only)
+
+        self._line('build %s: %s' % (' '.join(out_outputs),
+                                        ' '.join([rule] + all_inputs)))
+
+        if variables:
+            if isinstance(variables, dict):
+                iterator = iter(variables.items())
+            else:
+                iterator = iter(variables)
+
+            for key, val in iterator:
+                self.variable(key, val, indent=1)
+
+        return outputs
+
+    def include(self, path):
+        self._line('include %s' % path)
+
+    def subninja(self, path):
+        self._line('subninja %s' % path)
+
+    def default(self, paths):
+        self._line('default %s' % ' '.join(self._as_list(paths)))
+
+    def _count_dollars_before_index(self, s, i):
+      """Returns the number of '$' characters right in front of s[i]."""
+      dollar_count = 0
+      dollar_index = i - 1
+      while dollar_index > 0 and s[dollar_index] == '$':
+        dollar_count += 1
+        dollar_index -= 1
+      return dollar_count
+
+    def _line(self, text, indent=0):
+        """Write 'text' word-wrapped at self.width characters."""
+        leading_space = '  ' * indent
+        while len(leading_space) + len(text) > self.width:
+            # The text is too wide; wrap if possible.
+
+            # Find the rightmost space that would obey our width constraint and
+            # that's not an escaped space.
+            available_space = self.width - len(leading_space) - len(' $')
+            space = available_space
+            while True:
+              space = text.rfind(' ', 0, space)
+              if space < 0 or \
+                 self._count_dollars_before_index(text, space) % 2 == 0:
+                break
+
+            if space < 0:
+                # No such space; just use the first unescaped space we can find.
+                space = available_space - 1
+                while True:
+                  space = text.find(' ', space + 1)
+                  if space < 0 or \
+                     self._count_dollars_before_index(text, space) % 2 == 0:
+                    break
+            if space < 0:
+                # Give up on breaking.
+                break
+
+            self.output.write(leading_space + text[0:space] + ' $\n')
+            text = text[space+1:]
+
+            # Subsequent lines are continuations, so indent them.
+            leading_space = '  ' * (indent+2)
+
+        self.output.write(leading_space + text + '\n')
+
+    def _as_list(self, input):
+        if input is None:
+            return []
+        if isinstance(input, list):
+            return input
+        return [input]
+
+
+def escape(string):
+    """Escape a string such that it can be embedded into a Ninja file without
+    further interpretation."""
+    assert '\n' not in string, 'Ninja syntax does not allow newlines'
+    # We only have one special metacharacter: '$'.
+    return string.replace('$', '$$')
diff --git a/gyp/pylib/gyp/ordered_dict.py b/gyp/pylib/gyp/ordered_dict.py
new file mode 100644 (file)
index 0000000..a1e89f9
--- /dev/null
@@ -0,0 +1,289 @@
+# Unmodified from http://code.activestate.com/recipes/576693/
+# other than to add MIT license header (as specified on page, but not in code).
+# Linked from Python documentation here:
+# http://docs.python.org/2/library/collections.html#collections.OrderedDict
+#
+# This should be deleted once Py2.7 is available on all bots, see
+# http://crbug.com/241769.
+#
+# Copyright (c) 2009 Raymond Hettinger.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
+# Passes Python2.7's test suite and incorporates all the latest updates.
+
+try:
+    from thread import get_ident as _get_ident
+except ImportError:
+    from dummy_thread import get_ident as _get_ident
+
+try:
+    from _abcoll import KeysView, ValuesView, ItemsView
+except ImportError:
+    pass
+
+
+class OrderedDict(dict):
+    'Dictionary that remembers insertion order'
+    # An inherited dict maps keys to values.
+    # The inherited dict provides __getitem__, __len__, __contains__, and get.
+    # The remaining methods are order-aware.
+    # Big-O running times for all methods are the same as for regular dictionaries.
+
+    # The internal self.__map dictionary maps keys to links in a doubly linked list.
+    # The circular doubly linked list starts and ends with a sentinel element.
+    # The sentinel element never gets deleted (this simplifies the algorithm).
+    # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
+
+    def __init__(self, *args, **kwds):
+        '''Initialize an ordered dictionary.  Signature is the same as for
+        regular dictionaries, but keyword arguments are not recommended
+        because their insertion order is arbitrary.
+
+        '''
+        if len(args) > 1:
+            raise TypeError('expected at most 1 arguments, got %d' % len(args))
+        try:
+            self.__root
+        except AttributeError:
+            self.__root = root = []                     # sentinel node
+            root[:] = [root, root, None]
+            self.__map = {}
+        self.__update(*args, **kwds)
+
+    def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
+        'od.__setitem__(i, y) <==> od[i]=y'
+        # Setting a new item creates a new link which goes at the end of the linked
+        # list, and the inherited dictionary is updated with the new key/value pair.
+        if key not in self:
+            root = self.__root
+            last = root[0]
+            last[1] = root[0] = self.__map[key] = [last, root, key]
+        dict_setitem(self, key, value)
+
+    def __delitem__(self, key, dict_delitem=dict.__delitem__):
+        'od.__delitem__(y) <==> del od[y]'
+        # Deleting an existing item uses self.__map to find the link which is
+        # then removed by updating the links in the predecessor and successor nodes.
+        dict_delitem(self, key)
+        link_prev, link_next, key = self.__map.pop(key)
+        link_prev[1] = link_next
+        link_next[0] = link_prev
+
+    def __iter__(self):
+        'od.__iter__() <==> iter(od)'
+        root = self.__root
+        curr = root[1]
+        while curr is not root:
+            yield curr[2]
+            curr = curr[1]
+
+    def __reversed__(self):
+        'od.__reversed__() <==> reversed(od)'
+        root = self.__root
+        curr = root[0]
+        while curr is not root:
+            yield curr[2]
+            curr = curr[0]
+
+    def clear(self):
+        'od.clear() -> None.  Remove all items from od.'
+        try:
+            for node in self.__map.itervalues():
+                del node[:]
+            root = self.__root
+            root[:] = [root, root, None]
+            self.__map.clear()
+        except AttributeError:
+            pass
+        dict.clear(self)
+
+    def popitem(self, last=True):
+        '''od.popitem() -> (k, v), return and remove a (key, value) pair.
+        Pairs are returned in LIFO order if last is true or FIFO order if false.
+
+        '''
+        if not self:
+            raise KeyError('dictionary is empty')
+        root = self.__root
+        if last:
+            link = root[0]
+            link_prev = link[0]
+            link_prev[1] = root
+            root[0] = link_prev
+        else:
+            link = root[1]
+            link_next = link[1]
+            root[1] = link_next
+            link_next[0] = root
+        key = link[2]
+        del self.__map[key]
+        value = dict.pop(self, key)
+        return key, value
+
+    # -- the following methods do not depend on the internal structure --
+
+    def keys(self):
+        'od.keys() -> list of keys in od'
+        return list(self)
+
+    def values(self):
+        'od.values() -> list of values in od'
+        return [self[key] for key in self]
+
+    def items(self):
+        'od.items() -> list of (key, value) pairs in od'
+        return [(key, self[key]) for key in self]
+
+    def iterkeys(self):
+        'od.iterkeys() -> an iterator over the keys in od'
+        return iter(self)
+
+    def itervalues(self):
+        'od.itervalues -> an iterator over the values in od'
+        for k in self:
+            yield self[k]
+
+    def iteritems(self):
+        'od.iteritems -> an iterator over the (key, value) items in od'
+        for k in self:
+            yield (k, self[k])
+
+    # Suppress 'OrderedDict.update: Method has no argument':
+    # pylint: disable=E0211
+    def update(*args, **kwds):
+        '''od.update(E, **F) -> None.  Update od from dict/iterable E and F.
+
+        If E is a dict instance, does:           for k in E: od[k] = E[k]
+        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
+        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
+        In either case, this is followed by:     for k, v in F.items(): od[k] = v
+
+        '''
+        if len(args) > 2:
+            raise TypeError('update() takes at most 2 positional '
+                            'arguments (%d given)' % (len(args),))
+        elif not args:
+            raise TypeError('update() takes at least 1 argument (0 given)')
+        self = args[0]
+        # Make progressively weaker assumptions about "other"
+        other = ()
+        if len(args) == 2:
+            other = args[1]
+        if isinstance(other, dict):
+            for key in other:
+                self[key] = other[key]
+        elif hasattr(other, 'keys'):
+            for key in other.keys():
+                self[key] = other[key]
+        else:
+            for key, value in other:
+                self[key] = value
+        for key, value in kwds.items():
+            self[key] = value
+
+    __update = update  # let subclasses override update without breaking __init__
+
+    __marker = object()
+
+    def pop(self, key, default=__marker):
+        '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
+        If key is not found, d is returned if given, otherwise KeyError is raised.
+
+        '''
+        if key in self:
+            result = self[key]
+            del self[key]
+            return result
+        if default is self.__marker:
+            raise KeyError(key)
+        return default
+
+    def setdefault(self, key, default=None):
+        'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
+        if key in self:
+            return self[key]
+        self[key] = default
+        return default
+
+    def __repr__(self, _repr_running={}):
+        'od.__repr__() <==> repr(od)'
+        call_key = id(self), _get_ident()
+        if call_key in _repr_running:
+            return '...'
+        _repr_running[call_key] = 1
+        try:
+            if not self:
+                return '%s()' % (self.__class__.__name__,)
+            return '%s(%r)' % (self.__class__.__name__, self.items())
+        finally:
+            del _repr_running[call_key]
+
+    def __reduce__(self):
+        'Return state information for pickling'
+        items = [[k, self[k]] for k in self]
+        inst_dict = vars(self).copy()
+        for k in vars(OrderedDict()):
+            inst_dict.pop(k, None)
+        if inst_dict:
+            return (self.__class__, (items,), inst_dict)
+        return self.__class__, (items,)
+
+    def copy(self):
+        'od.copy() -> a shallow copy of od'
+        return self.__class__(self)
+
+    @classmethod
+    def fromkeys(cls, iterable, value=None):
+        '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
+        and values equal to v (which defaults to None).
+
+        '''
+        d = cls()
+        for key in iterable:
+            d[key] = value
+        return d
+
+    def __eq__(self, other):
+        '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
+        while comparison to a regular mapping is order-insensitive.
+
+        '''
+        if isinstance(other, OrderedDict):
+            return len(self)==len(other) and self.items() == other.items()
+        return dict.__eq__(self, other)
+
+    def __ne__(self, other):
+        return not self == other
+
+    # -- the following methods are only used in Python 2.7 --
+
+    def viewkeys(self):
+        "od.viewkeys() -> a set-like object providing a view on od's keys"
+        return KeysView(self)
+
+    def viewvalues(self):
+        "od.viewvalues() -> an object providing a view on od's values"
+        return ValuesView(self)
+
+    def viewitems(self):
+        "od.viewitems() -> a set-like object providing a view on od's items"
+        return ItemsView(self)
+
diff --git a/gyp/pylib/gyp/simple_copy.py b/gyp/pylib/gyp/simple_copy.py
new file mode 100644 (file)
index 0000000..74c98c5
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A clone of the default copy.deepcopy that doesn't handle cyclic
+structures or complex types except for dicts and lists. This is
+because gyp copies so large structure that small copy overhead ends up
+taking seconds in a project the size of Chromium."""
+
+class Error(Exception):
+  pass
+
+__all__ = ["Error", "deepcopy"]
+
+def deepcopy(x):
+  """Deep copy operation on gyp objects such as strings, ints, dicts
+  and lists. More than twice as fast as copy.deepcopy but much less
+  generic."""
+
+  try:
+    return _deepcopy_dispatch[type(x)](x)
+  except KeyError:
+    raise Error('Unsupported type %s for deepcopy. Use copy.deepcopy ' +
+                'or expand simple_copy support.' % type(x))
+
+_deepcopy_dispatch = d = {}
+
+def _deepcopy_atomic(x):
+  return x
+
+for x in (type(None), int, long, float,
+          bool, str, unicode, type):
+  d[x] = _deepcopy_atomic
+
+def _deepcopy_list(x):
+  return [deepcopy(a) for a in x]
+d[list] = _deepcopy_list
+
+def _deepcopy_dict(x):
+  y = {}
+  for key, value in x.iteritems():
+    y[deepcopy(key)] = deepcopy(value)
+  return y
+d[dict] = _deepcopy_dict
+
+del d
diff --git a/gyp/pylib/gyp/win_tool.py b/gyp/pylib/gyp/win_tool.py
new file mode 100755 (executable)
index 0000000..44e1b07
--- /dev/null
@@ -0,0 +1,315 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Utility functions for Windows builds.
+
+These functions are executed via gyp-win-tool when using the ninja generator.
+"""
+
+import os
+import re
+import shutil
+import subprocess
+import stat
+import string
+import sys
+
+BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+
+# A regex matching an argument corresponding to the output filename passed to
+# link.exe.
+_LINK_EXE_OUT_ARG = re.compile('/OUT:(?P<out>.+)$', re.IGNORECASE)
+
+def main(args):
+  executor = WinTool()
+  exit_code = executor.Dispatch(args)
+  if exit_code is not None:
+    sys.exit(exit_code)
+
+
+class WinTool(object):
+  """This class performs all the Windows tooling steps. The methods can either
+  be executed directly, or dispatched from an argument list."""
+
+  def _UseSeparateMspdbsrv(self, env, args):
+    """Allows to use a unique instance of mspdbsrv.exe per linker instead of a
+    shared one."""
+    if len(args) < 1:
+      raise Exception("Not enough arguments")
+
+    if args[0] != 'link.exe':
+      return
+
+    # Use the output filename passed to the linker to generate an endpoint name
+    # for mspdbsrv.exe.
+    endpoint_name = None
+    for arg in args:
+      m = _LINK_EXE_OUT_ARG.match(arg)
+      if m:
+        endpoint_name = re.sub(r'\W+', '',
+            '%s_%d' % (m.group('out'), os.getpid()))
+        break
+
+    if endpoint_name is None:
+      return
+
+    # Adds the appropriate environment variable. This will be read by link.exe
+    # to know which instance of mspdbsrv.exe it should connect to (if it's
+    # not set then the default endpoint is used).
+    env['_MSPDBSRV_ENDPOINT_'] = endpoint_name
+
+  def Dispatch(self, args):
+    """Dispatches a string command to a method."""
+    if len(args) < 1:
+      raise Exception("Not enough arguments")
+
+    method = "Exec%s" % self._CommandifyName(args[0])
+    return getattr(self, method)(*args[1:])
+
+  def _CommandifyName(self, name_string):
+    """Transforms a tool name like recursive-mirror to RecursiveMirror."""
+    return name_string.title().replace('-', '')
+
+  def _GetEnv(self, arch):
+    """Gets the saved environment from a file for a given architecture."""
+    # The environment is saved as an "environment block" (see CreateProcess
+    # and msvs_emulation for details). We convert to a dict here.
+    # Drop last 2 NULs, one for list terminator, one for trailing vs. separator.
+    pairs = open(arch).read()[:-2].split('\0')
+    kvs = [item.split('=', 1) for item in pairs]
+    return dict(kvs)
+
+  def ExecStamp(self, path):
+    """Simple stamp command."""
+    open(path, 'w').close()
+
+  def ExecRecursiveMirror(self, source, dest):
+    """Emulation of rm -rf out && cp -af in out."""
+    if os.path.exists(dest):
+      if os.path.isdir(dest):
+        def _on_error(fn, path, excinfo):
+          # The operation failed, possibly because the file is set to
+          # read-only. If that's why, make it writable and try the op again.
+          if not os.access(path, os.W_OK):
+            os.chmod(path, stat.S_IWRITE)
+          fn(path)
+        shutil.rmtree(dest, onerror=_on_error)
+      else:
+        if not os.access(dest, os.W_OK):
+          # Attempt to make the file writable before deleting it.
+          os.chmod(dest, stat.S_IWRITE)
+        os.unlink(dest)
+
+    if os.path.isdir(source):
+      shutil.copytree(source, dest)
+    else:
+      shutil.copy2(source, dest)
+
+  def ExecLinkWrapper(self, arch, use_separate_mspdbsrv, *args):
+    """Filter diagnostic output from link that looks like:
+    '   Creating library ui.dll.lib and object ui.dll.exp'
+    This happens when there are exports from the dll or exe.
+    """
+    env = self._GetEnv(arch)
+    if use_separate_mspdbsrv == 'True':
+      self._UseSeparateMspdbsrv(env, args)
+    link = subprocess.Popen(args,
+                            shell=True,
+                            env=env,
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.STDOUT)
+    out, _ = link.communicate()
+    for line in out.splitlines():
+      if not line.startswith('   Creating library '):
+        print line
+    return link.returncode
+
+  def ExecLinkWithManifests(self, arch, embed_manifest, out, ldcmd, resname,
+                            mt, rc, intermediate_manifest, *manifests):
+    """A wrapper for handling creating a manifest resource and then executing
+    a link command."""
+    # The 'normal' way to do manifests is to have link generate a manifest
+    # based on gathering dependencies from the object files, then merge that
+    # manifest with other manifests supplied as sources, convert the merged
+    # manifest to a resource, and then *relink*, including the compiled
+    # version of the manifest resource. This breaks incremental linking, and
+    # is generally overly complicated. Instead, we merge all the manifests
+    # provided (along with one that includes what would normally be in the
+    # linker-generated one, see msvs_emulation.py), and include that into the
+    # first and only link. We still tell link to generate a manifest, but we
+    # only use that to assert that our simpler process did not miss anything.
+    variables = {
+      'python': sys.executable,
+      'arch': arch,
+      'out': out,
+      'ldcmd': ldcmd,
+      'resname': resname,
+      'mt': mt,
+      'rc': rc,
+      'intermediate_manifest': intermediate_manifest,
+      'manifests': ' '.join(manifests),
+    }
+    add_to_ld = ''
+    if manifests:
+      subprocess.check_call(
+          '%(python)s gyp-win-tool manifest-wrapper %(arch)s %(mt)s -nologo '
+          '-manifest %(manifests)s -out:%(out)s.manifest' % variables)
+      if embed_manifest == 'True':
+        subprocess.check_call(
+            '%(python)s gyp-win-tool manifest-to-rc %(arch)s %(out)s.manifest'
+          ' %(out)s.manifest.rc %(resname)s' % variables)
+        subprocess.check_call(
+            '%(python)s gyp-win-tool rc-wrapper %(arch)s %(rc)s '
+            '%(out)s.manifest.rc' % variables)
+        add_to_ld = ' %(out)s.manifest.res' % variables
+    subprocess.check_call(ldcmd + add_to_ld)
+
+    # Run mt.exe on the theoretically complete manifest we generated, merging
+    # it with the one the linker generated to confirm that the linker
+    # generated one does not add anything. This is strictly unnecessary for
+    # correctness, it's only to verify that e.g. /MANIFESTDEPENDENCY was not
+    # used in a #pragma comment.
+    if manifests:
+      # Merge the intermediate one with ours to .assert.manifest, then check
+      # that .assert.manifest is identical to ours.
+      subprocess.check_call(
+          '%(python)s gyp-win-tool manifest-wrapper %(arch)s %(mt)s -nologo '
+          '-manifest %(out)s.manifest %(intermediate_manifest)s '
+          '-out:%(out)s.assert.manifest' % variables)
+      assert_manifest = '%(out)s.assert.manifest' % variables
+      our_manifest = '%(out)s.manifest' % variables
+      # Load and normalize the manifests. mt.exe sometimes removes whitespace,
+      # and sometimes doesn't unfortunately.
+      with open(our_manifest, 'rb') as our_f:
+        with open(assert_manifest, 'rb') as assert_f:
+          our_data = our_f.read().translate(None, string.whitespace)
+          assert_data = assert_f.read().translate(None, string.whitespace)
+      if our_data != assert_data:
+        os.unlink(out)
+        def dump(filename):
+          sys.stderr.write('%s\n-----\n' % filename)
+          with open(filename, 'rb') as f:
+            sys.stderr.write(f.read() + '\n-----\n')
+        dump(intermediate_manifest)
+        dump(our_manifest)
+        dump(assert_manifest)
+        sys.stderr.write(
+            'Linker generated manifest "%s" added to final manifest "%s" '
+            '(result in "%s"). '
+            'Were /MANIFEST switches used in #pragma statements? ' % (
+              intermediate_manifest, our_manifest, assert_manifest))
+        return 1
+
+  def ExecManifestWrapper(self, arch, *args):
+    """Run manifest tool with environment set. Strip out undesirable warning
+    (some XML blocks are recognized by the OS loader, but not the manifest
+    tool)."""
+    env = self._GetEnv(arch)
+    popen = subprocess.Popen(args, shell=True, env=env,
+                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    out, _ = popen.communicate()
+    for line in out.splitlines():
+      if line and 'manifest authoring warning 81010002' not in line:
+        print line
+    return popen.returncode
+
+  def ExecManifestToRc(self, arch, *args):
+    """Creates a resource file pointing a SxS assembly manifest.
+    |args| is tuple containing path to resource file, path to manifest file
+    and resource name which can be "1" (for executables) or "2" (for DLLs)."""
+    manifest_path, resource_path, resource_name = args
+    with open(resource_path, 'wb') as output:
+      output.write('#include <windows.h>\n%s RT_MANIFEST "%s"' % (
+        resource_name,
+        os.path.abspath(manifest_path).replace('\\', '/')))
+
+  def ExecMidlWrapper(self, arch, outdir, tlb, h, dlldata, iid, proxy, idl,
+                      *flags):
+    """Filter noisy filenames output from MIDL compile step that isn't
+    quietable via command line flags.
+    """
+    args = ['midl', '/nologo'] + list(flags) + [
+        '/out', outdir,
+        '/tlb', tlb,
+        '/h', h,
+        '/dlldata', dlldata,
+        '/iid', iid,
+        '/proxy', proxy,
+        idl]
+    env = self._GetEnv(arch)
+    popen = subprocess.Popen(args, shell=True, env=env,
+                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    out, _ = popen.communicate()
+    # Filter junk out of stdout, and write filtered versions. Output we want
+    # to filter is pairs of lines that look like this:
+    # Processing C:\Program Files (x86)\Microsoft SDKs\...\include\objidl.idl
+    # objidl.idl
+    lines = out.splitlines()
+    prefixes = ('Processing ', '64 bit Processing ')
+    processing = set(os.path.basename(x)
+                     for x in lines if x.startswith(prefixes))
+    for line in lines:
+      if not line.startswith(prefixes) and line not in processing:
+        print line
+    return popen.returncode
+
+  def ExecAsmWrapper(self, arch, *args):
+    """Filter logo banner from invocations of asm.exe."""
+    env = self._GetEnv(arch)
+    # MSVS doesn't assemble x64 asm files.
+    if arch == 'environment.x64':
+      return 0
+    popen = subprocess.Popen(args, shell=True, env=env,
+                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    out, _ = popen.communicate()
+    for line in out.splitlines():
+      if (not line.startswith('Copyright (C) Microsoft Corporation') and
+          not line.startswith('Microsoft (R) Macro Assembler') and
+          not line.startswith(' Assembling: ') and
+          line):
+        print line
+    return popen.returncode
+
+  def ExecRcWrapper(self, arch, *args):
+    """Filter logo banner from invocations of rc.exe. Older versions of RC
+    don't support the /nologo flag."""
+    env = self._GetEnv(arch)
+    popen = subprocess.Popen(args, shell=True, env=env,
+                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    out, _ = popen.communicate()
+    for line in out.splitlines():
+      if (not line.startswith('Microsoft (R) Windows (R) Resource Compiler') and
+          not line.startswith('Copyright (C) Microsoft Corporation') and
+          line):
+        print line
+    return popen.returncode
+
+  def ExecActionWrapper(self, arch, rspfile, *dir):
+    """Runs an action command line from a response file using the environment
+    for |arch|. If |dir| is supplied, use that as the working directory."""
+    env = self._GetEnv(arch)
+    # TODO(scottmg): This is a temporary hack to get some specific variables
+    # through to actions that are set after gyp-time. http://crbug.com/333738.
+    for k, v in os.environ.iteritems():
+      if k not in env:
+        env[k] = v
+    args = open(rspfile).read()
+    dir = dir[0] if dir else None
+    return subprocess.call(args, shell=True, env=env, cwd=dir)
+
+  def ExecClCompile(self, project_dir, selected_files):
+    """Executed by msvs-ninja projects when the 'ClCompile' target is used to
+    build selected C/C++ files."""
+    project_dir = os.path.relpath(project_dir, BASE_DIR)
+    selected_files = selected_files.split(';')
+    ninja_targets = [os.path.join(project_dir, filename) + '^^'
+        for filename in selected_files]
+    cmd = ['ninja.exe']
+    cmd.extend(ninja_targets)
+    return subprocess.call(cmd, shell=True, cwd=BASE_DIR)
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/gyp/pylib/gyp/xcode_emulation.py b/gyp/pylib/gyp/xcode_emulation.py
new file mode 100644 (file)
index 0000000..2f34bc6
--- /dev/null
@@ -0,0 +1,1581 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+This module contains classes that help to emulate xcodebuild behavior on top of
+other build systems, such as make and ninja.
+"""
+
+import copy
+import gyp.common
+import os
+import os.path
+import re
+import shlex
+import subprocess
+import sys
+import tempfile
+from gyp.common import GypError
+
+# Populated lazily by XcodeVersion, for efficiency, and to fix an issue when
+# "xcodebuild" is called too quickly (it has been found to return incorrect
+# version number).
+XCODE_VERSION_CACHE = None
+
+# Populated lazily by GetXcodeArchsDefault, to an |XcodeArchsDefault| instance
+# corresponding to the installed version of Xcode.
+XCODE_ARCHS_DEFAULT_CACHE = None
+
+
+def XcodeArchsVariableMapping(archs, archs_including_64_bit=None):
+  """Constructs a dictionary with expansion for $(ARCHS_STANDARD) variable,
+  and optionally for $(ARCHS_STANDARD_INCLUDING_64_BIT)."""
+  mapping = {'$(ARCHS_STANDARD)': archs}
+  if archs_including_64_bit:
+    mapping['$(ARCHS_STANDARD_INCLUDING_64_BIT)'] = archs_including_64_bit
+  return mapping
+
+class XcodeArchsDefault(object):
+  """A class to resolve ARCHS variable from xcode_settings, resolving Xcode
+  macros and implementing filtering by VALID_ARCHS. The expansion of macros
+  depends on the SDKROOT used ("macosx", "iphoneos", "iphonesimulator") and
+  on the version of Xcode.
+  """
+
+  # Match variable like $(ARCHS_STANDARD).
+  variable_pattern = re.compile(r'\$\([a-zA-Z_][a-zA-Z0-9_]*\)$')
+
+  def __init__(self, default, mac, iphonesimulator, iphoneos):
+    self._default = (default,)
+    self._archs = {'mac': mac, 'ios': iphoneos, 'iossim': iphonesimulator}
+
+  def _VariableMapping(self, sdkroot):
+    """Returns the dictionary of variable mapping depending on the SDKROOT."""
+    sdkroot = sdkroot.lower()
+    if 'iphoneos' in sdkroot:
+      return self._archs['ios']
+    elif 'iphonesimulator' in sdkroot:
+      return self._archs['iossim']
+    else:
+      return self._archs['mac']
+
+  def _ExpandArchs(self, archs, sdkroot):
+    """Expands variables references in ARCHS, and remove duplicates."""
+    variable_mapping = self._VariableMapping(sdkroot)
+    expanded_archs = []
+    for arch in archs:
+      if self.variable_pattern.match(arch):
+        variable = arch
+        try:
+          variable_expansion = variable_mapping[variable]
+          for arch in variable_expansion:
+            if arch not in expanded_archs:
+              expanded_archs.append(arch)
+        except KeyError as e:
+          print 'Warning: Ignoring unsupported variable "%s".' % variable
+      elif arch not in expanded_archs:
+        expanded_archs.append(arch)
+    return expanded_archs
+
+  def ActiveArchs(self, archs, valid_archs, sdkroot):
+    """Expands variables references in ARCHS, and filter by VALID_ARCHS if it
+    is defined (if not set, Xcode accept any value in ARCHS, otherwise, only
+    values present in VALID_ARCHS are kept)."""
+    expanded_archs = self._ExpandArchs(archs or self._default, sdkroot or '')
+    if valid_archs:
+      filtered_archs = []
+      for arch in expanded_archs:
+        if arch in valid_archs:
+          filtered_archs.append(arch)
+      expanded_archs = filtered_archs
+    return expanded_archs
+
+
+def GetXcodeArchsDefault():
+  """Returns the |XcodeArchsDefault| object to use to expand ARCHS for the
+  installed version of Xcode. The default values used by Xcode for ARCHS
+  and the expansion of the variables depends on the version of Xcode used.
+
+  For all version anterior to Xcode 5.0 or posterior to Xcode 5.1 included
+  uses $(ARCHS_STANDARD) if ARCHS is unset, while Xcode 5.0 to 5.0.2 uses
+  $(ARCHS_STANDARD_INCLUDING_64_BIT). This variable was added to Xcode 5.0
+  and deprecated with Xcode 5.1.
+
+  For "macosx" SDKROOT, all version starting with Xcode 5.0 includes 64-bit
+  architecture as part of $(ARCHS_STANDARD) and default to only building it.
+
+  For "iphoneos" and "iphonesimulator" SDKROOT, 64-bit architectures are part
+  of $(ARCHS_STANDARD_INCLUDING_64_BIT) from Xcode 5.0. From Xcode 5.1, they
+  are also part of $(ARCHS_STANDARD).
+
+  All thoses rules are coded in the construction of the |XcodeArchsDefault|
+  object to use depending on the version of Xcode detected. The object is
+  for performance reason."""
+  global XCODE_ARCHS_DEFAULT_CACHE
+  if XCODE_ARCHS_DEFAULT_CACHE:
+    return XCODE_ARCHS_DEFAULT_CACHE
+  xcode_version, _ = XcodeVersion()
+  if xcode_version < '0500':
+    XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
+        '$(ARCHS_STANDARD)',
+        XcodeArchsVariableMapping(['i386']),
+        XcodeArchsVariableMapping(['i386']),
+        XcodeArchsVariableMapping(['armv7']))
+  elif xcode_version < '0510':
+    XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
+        '$(ARCHS_STANDARD_INCLUDING_64_BIT)',
+        XcodeArchsVariableMapping(['x86_64'], ['x86_64']),
+        XcodeArchsVariableMapping(['i386'], ['i386', 'x86_64']),
+        XcodeArchsVariableMapping(
+            ['armv7', 'armv7s'],
+            ['armv7', 'armv7s', 'arm64']))
+  else:
+    XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
+        '$(ARCHS_STANDARD)',
+        XcodeArchsVariableMapping(['x86_64'], ['x86_64']),
+        XcodeArchsVariableMapping(['i386', 'x86_64'], ['i386', 'x86_64']),
+        XcodeArchsVariableMapping(
+            ['armv7', 'armv7s', 'arm64'],
+            ['armv7', 'armv7s', 'arm64']))
+  return XCODE_ARCHS_DEFAULT_CACHE
+
+
+class XcodeSettings(object):
+  """A class that understands the gyp 'xcode_settings' object."""
+
+  # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached
+  # at class-level for efficiency.
+  _sdk_path_cache = {}
+  _sdk_root_cache = {}
+
+  # Populated lazily by GetExtraPlistItems(). Shared by all XcodeSettings, so
+  # cached at class-level for efficiency.
+  _plist_cache = {}
+
+  # Populated lazily by GetIOSPostbuilds.  Shared by all XcodeSettings, so
+  # cached at class-level for efficiency.
+  _codesigning_key_cache = {}
+
+  def __init__(self, spec):
+    self.spec = spec
+
+    self.isIOS = False
+
+    # Per-target 'xcode_settings' are pushed down into configs earlier by gyp.
+    # This means self.xcode_settings[config] always contains all settings
+    # for that config -- the per-target settings as well. Settings that are
+    # the same for all configs are implicitly per-target settings.
+    self.xcode_settings = {}
+    configs = spec['configurations']
+    for configname, config in configs.iteritems():
+      self.xcode_settings[configname] = config.get('xcode_settings', {})
+      self._ConvertConditionalKeys(configname)
+      if self.xcode_settings[configname].get('IPHONEOS_DEPLOYMENT_TARGET',
+                                             None):
+        self.isIOS = True
+
+    # This is only non-None temporarily during the execution of some methods.
+    self.configname = None
+
+    # Used by _AdjustLibrary to match .a and .dylib entries in libraries.
+    self.library_re = re.compile(r'^lib([^/]+)\.(a|dylib)$')
+
+  def _ConvertConditionalKeys(self, configname):
+    """Converts or warns on conditional keys.  Xcode supports conditional keys,
+    such as CODE_SIGN_IDENTITY[sdk=iphoneos*].  This is a partial implementation
+    with some keys converted while the rest force a warning."""
+    settings = self.xcode_settings[configname]
+    conditional_keys = [key for key in settings if key.endswith(']')]
+    for key in conditional_keys:
+      # If you need more, speak up at http://crbug.com/122592
+      if key.endswith("[sdk=iphoneos*]"):
+        if configname.endswith("iphoneos"):
+          new_key = key.split("[")[0]
+          settings[new_key] = settings[key]
+      else:
+        print 'Warning: Conditional keys not implemented, ignoring:', \
+              ' '.join(conditional_keys)
+      del settings[key]
+
+  def _Settings(self):
+    assert self.configname
+    return self.xcode_settings[self.configname]
+
+  def _Test(self, test_key, cond_key, default):
+    return self._Settings().get(test_key, default) == cond_key
+
+  def _Appendf(self, lst, test_key, format_str, default=None):
+    if test_key in self._Settings():
+      lst.append(format_str % str(self._Settings()[test_key]))
+    elif default:
+      lst.append(format_str % str(default))
+
+  def _WarnUnimplemented(self, test_key):
+    if test_key in self._Settings():
+      print 'Warning: Ignoring not yet implemented key "%s".' % test_key
+
+  def _IsBundle(self):
+    return int(self.spec.get('mac_bundle', 0)) != 0
+
+  def _IsIosAppExtension(self):
+    return int(self.spec.get('ios_app_extension', 0)) != 0
+
+  def GetFrameworkVersion(self):
+    """Returns the framework version of the current target. Only valid for
+    bundles."""
+    assert self._IsBundle()
+    return self.GetPerTargetSetting('FRAMEWORK_VERSION', default='A')
+
+  def GetWrapperExtension(self):
+    """Returns the bundle extension (.app, .framework, .plugin, etc).  Only
+    valid for bundles."""
+    assert self._IsBundle()
+    if self.spec['type'] in ('loadable_module', 'shared_library'):
+      default_wrapper_extension = {
+        'loadable_module': 'bundle',
+        'shared_library': 'framework',
+      }[self.spec['type']]
+      wrapper_extension = self.GetPerTargetSetting(
+          'WRAPPER_EXTENSION', default=default_wrapper_extension)
+      return '.' + self.spec.get('product_extension', wrapper_extension)
+    elif self.spec['type'] == 'executable':
+      if self._IsIosAppExtension():
+        return '.' + self.spec.get('product_extension', 'appex')
+      else:
+        return '.' + self.spec.get('product_extension', 'app')
+    else:
+      assert False, "Don't know extension for '%s', target '%s'" % (
+          self.spec['type'], self.spec['target_name'])
+
+  def GetProductName(self):
+    """Returns PRODUCT_NAME."""
+    return self.spec.get('product_name', self.spec['target_name'])
+
+  def GetFullProductName(self):
+    """Returns FULL_PRODUCT_NAME."""
+    if self._IsBundle():
+      return self.GetWrapperName()
+    else:
+      return self._GetStandaloneBinaryPath()
+
+  def GetWrapperName(self):
+    """Returns the directory name of the bundle represented by this target.
+    Only valid for bundles."""
+    assert self._IsBundle()
+    return self.GetProductName() + self.GetWrapperExtension()
+
+  def GetBundleContentsFolderPath(self):
+    """Returns the qualified path to the bundle's contents folder. E.g.
+    Chromium.app/Contents or Foo.bundle/Versions/A. Only valid for bundles."""
+    if self.isIOS:
+      return self.GetWrapperName()
+    assert self._IsBundle()
+    if self.spec['type'] == 'shared_library':
+      return os.path.join(
+          self.GetWrapperName(), 'Versions', self.GetFrameworkVersion())
+    else:
+      # loadable_modules have a 'Contents' folder like executables.
+      return os.path.join(self.GetWrapperName(), 'Contents')
+
+  def GetBundleResourceFolder(self):
+    """Returns the qualified path to the bundle's resource folder. E.g.
+    Chromium.app/Contents/Resources. Only valid for bundles."""
+    assert self._IsBundle()
+    if self.isIOS:
+      return self.GetBundleContentsFolderPath()
+    return os.path.join(self.GetBundleContentsFolderPath(), 'Resources')
+
+  def GetBundlePlistPath(self):
+    """Returns the qualified path to the bundle's plist file. E.g.
+    Chromium.app/Contents/Info.plist. Only valid for bundles."""
+    assert self._IsBundle()
+    if self.spec['type'] in ('executable', 'loadable_module'):
+      return os.path.join(self.GetBundleContentsFolderPath(), 'Info.plist')
+    else:
+      return os.path.join(self.GetBundleContentsFolderPath(),
+                          'Resources', 'Info.plist')
+
+  def GetProductType(self):
+    """Returns the PRODUCT_TYPE of this target."""
+    if self._IsIosAppExtension():
+      assert self._IsBundle(), ('ios_app_extension flag requires mac_bundle '
+          '(target %s)' % self.spec['target_name'])
+      return 'com.apple.product-type.app-extension'
+    if self._IsBundle():
+      return {
+        'executable': 'com.apple.product-type.application',
+        'loadable_module': 'com.apple.product-type.bundle',
+        'shared_library': 'com.apple.product-type.framework',
+      }[self.spec['type']]
+    else:
+      return {
+        'executable': 'com.apple.product-type.tool',
+        'loadable_module': 'com.apple.product-type.library.dynamic',
+        'shared_library': 'com.apple.product-type.library.dynamic',
+        'static_library': 'com.apple.product-type.library.static',
+      }[self.spec['type']]
+
+  def GetMachOType(self):
+    """Returns the MACH_O_TYPE of this target."""
+    # Weird, but matches Xcode.
+    if not self._IsBundle() and self.spec['type'] == 'executable':
+      return ''
+    return {
+      'executable': 'mh_execute',
+      'static_library': 'staticlib',
+      'shared_library': 'mh_dylib',
+      'loadable_module': 'mh_bundle',
+    }[self.spec['type']]
+
+  def _GetBundleBinaryPath(self):
+    """Returns the name of the bundle binary of by this target.
+    E.g. Chromium.app/Contents/MacOS/Chromium. Only valid for bundles."""
+    assert self._IsBundle()
+    if self.spec['type'] in ('shared_library') or self.isIOS:
+      path = self.GetBundleContentsFolderPath()
+    elif self.spec['type'] in ('executable', 'loadable_module'):
+      path = os.path.join(self.GetBundleContentsFolderPath(), 'MacOS')
+    return os.path.join(path, self.GetExecutableName())
+
+  def _GetStandaloneExecutableSuffix(self):
+    if 'product_extension' in self.spec:
+      return '.' + self.spec['product_extension']
+    return {
+      'executable': '',
+      'static_library': '.a',
+      'shared_library': '.dylib',
+      'loadable_module': '.so',
+    }[self.spec['type']]
+
+  def _GetStandaloneExecutablePrefix(self):
+    return self.spec.get('product_prefix', {
+      'executable': '',
+      'static_library': 'lib',
+      'shared_library': 'lib',
+      # Non-bundled loadable_modules are called foo.so for some reason
+      # (that is, .so and no prefix) with the xcode build -- match that.
+      'loadable_module': '',
+    }[self.spec['type']])
+
+  def _GetStandaloneBinaryPath(self):
+    """Returns the name of the non-bundle binary represented by this target.
+    E.g. hello_world. Only valid for non-bundles."""
+    assert not self._IsBundle()
+    assert self.spec['type'] in (
+        'executable', 'shared_library', 'static_library', 'loadable_module'), (
+        'Unexpected type %s' % self.spec['type'])
+    target = self.spec['target_name']
+    if self.spec['type'] == 'static_library':
+      if target[:3] == 'lib':
+        target = target[3:]
+    elif self.spec['type'] in ('loadable_module', 'shared_library'):
+      if target[:3] == 'lib':
+        target = target[3:]
+
+    target_prefix = self._GetStandaloneExecutablePrefix()
+    target = self.spec.get('product_name', target)
+    target_ext = self._GetStandaloneExecutableSuffix()
+    return target_prefix + target + target_ext
+
+  def GetExecutableName(self):
+    """Returns the executable name of the bundle represented by this target.
+    E.g. Chromium."""
+    if self._IsBundle():
+      return self.spec.get('product_name', self.spec['target_name'])
+    else:
+      return self._GetStandaloneBinaryPath()
+
+  def GetExecutablePath(self):
+    """Returns the directory name of the bundle represented by this target. E.g.
+    Chromium.app/Contents/MacOS/Chromium."""
+    if self._IsBundle():
+      return self._GetBundleBinaryPath()
+    else:
+      return self._GetStandaloneBinaryPath()
+
+  def GetActiveArchs(self, configname):
+    """Returns the architectures this target should be built for."""
+    config_settings = self.xcode_settings[configname]
+    xcode_archs_default = GetXcodeArchsDefault()
+    return xcode_archs_default.ActiveArchs(
+        config_settings.get('ARCHS'),
+        config_settings.get('VALID_ARCHS'),
+        config_settings.get('SDKROOT'))
+
+  def _GetSdkVersionInfoItem(self, sdk, infoitem):
+    # xcodebuild requires Xcode and can't run on Command Line Tools-only
+    # systems from 10.7 onward.
+    # Since the CLT has no SDK paths anyway, returning None is the
+    # most sensible route and should still do the right thing.
+    try:
+      return GetStdout(['xcodebuild', '-version', '-sdk', sdk, infoitem])
+    except:
+      pass
+
+  def _SdkRoot(self, configname):
+    if configname is None:
+      configname = self.configname
+    return self.GetPerConfigSetting('SDKROOT', configname, default='')
+
+  def _SdkPath(self, configname=None):
+    sdk_root = self._SdkRoot(configname)
+    if sdk_root.startswith('/'):
+      return sdk_root
+    return self._XcodeSdkPath(sdk_root)
+
+  def _XcodeSdkPath(self, sdk_root):
+    if sdk_root not in XcodeSettings._sdk_path_cache:
+      sdk_path = self._GetSdkVersionInfoItem(sdk_root, 'Path')
+      XcodeSettings._sdk_path_cache[sdk_root] = sdk_path
+      if sdk_root:
+        XcodeSettings._sdk_root_cache[sdk_path] = sdk_root
+    return XcodeSettings._sdk_path_cache[sdk_root]
+
+  def _AppendPlatformVersionMinFlags(self, lst):
+    self._Appendf(lst, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s')
+    if 'IPHONEOS_DEPLOYMENT_TARGET' in self._Settings():
+      # TODO: Implement this better?
+      sdk_path_basename = os.path.basename(self._SdkPath())
+      if sdk_path_basename.lower().startswith('iphonesimulator'):
+        self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET',
+                      '-mios-simulator-version-min=%s')
+      else:
+        self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET',
+                      '-miphoneos-version-min=%s')
+
+  def GetCflags(self, configname, arch=None):
+    """Returns flags that need to be added to .c, .cc, .m, and .mm
+    compilations."""
+    # This functions (and the similar ones below) do not offer complete
+    # emulation of all xcode_settings keys. They're implemented on demand.
+
+    self.configname = configname
+    cflags = []
+
+    sdk_root = self._SdkPath()
+    if 'SDKROOT' in self._Settings() and sdk_root:
+      cflags.append('-isysroot %s' % sdk_root)
+
+    if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'):
+      cflags.append('-Wconstant-conversion')
+
+    if self._Test('GCC_CHAR_IS_UNSIGNED_CHAR', 'YES', default='NO'):
+      cflags.append('-funsigned-char')
+
+    if self._Test('GCC_CW_ASM_SYNTAX', 'YES', default='YES'):
+      cflags.append('-fasm-blocks')
+
+    if 'GCC_DYNAMIC_NO_PIC' in self._Settings():
+      if self._Settings()['GCC_DYNAMIC_NO_PIC'] == 'YES':
+        cflags.append('-mdynamic-no-pic')
+    else:
+      pass
+      # TODO: In this case, it depends on the target. xcode passes
+      # mdynamic-no-pic by default for executable and possibly static lib
+      # according to mento
+
+    if self._Test('GCC_ENABLE_PASCAL_STRINGS', 'YES', default='YES'):
+      cflags.append('-mpascal-strings')
+
+    self._Appendf(cflags, 'GCC_OPTIMIZATION_LEVEL', '-O%s', default='s')
+
+    if self._Test('GCC_GENERATE_DEBUGGING_SYMBOLS', 'YES', default='YES'):
+      dbg_format = self._Settings().get('DEBUG_INFORMATION_FORMAT', 'dwarf')
+      if dbg_format == 'dwarf':
+        cflags.append('-gdwarf-2')
+      elif dbg_format == 'stabs':
+        raise NotImplementedError('stabs debug format is not supported yet.')
+      elif dbg_format == 'dwarf-with-dsym':
+        cflags.append('-gdwarf-2')
+      else:
+        raise NotImplementedError('Unknown debug format %s' % dbg_format)
+
+    if self._Settings().get('GCC_STRICT_ALIASING') == 'YES':
+      cflags.append('-fstrict-aliasing')
+    elif self._Settings().get('GCC_STRICT_ALIASING') == 'NO':
+      cflags.append('-fno-strict-aliasing')
+
+    if self._Test('GCC_SYMBOLS_PRIVATE_EXTERN', 'YES', default='NO'):
+      cflags.append('-fvisibility=hidden')
+
+    if self._Test('GCC_TREAT_WARNINGS_AS_ERRORS', 'YES', default='NO'):
+      cflags.append('-Werror')
+
+    if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'):
+      cflags.append('-Wnewline-eof')
+
+    self._AppendPlatformVersionMinFlags(cflags)
+
+    # TODO:
+    if self._Test('COPY_PHASE_STRIP', 'YES', default='NO'):
+      self._WarnUnimplemented('COPY_PHASE_STRIP')
+    self._WarnUnimplemented('GCC_DEBUGGING_SYMBOLS')
+    self._WarnUnimplemented('GCC_ENABLE_OBJC_EXCEPTIONS')
+
+    # TODO: This is exported correctly, but assigning to it is not supported.
+    self._WarnUnimplemented('MACH_O_TYPE')
+    self._WarnUnimplemented('PRODUCT_TYPE')
+
+    if arch is not None:
+      archs = [arch]
+    else:
+      assert self.configname
+      archs = self.GetActiveArchs(self.configname)
+    if len(archs) != 1:
+      # TODO: Supporting fat binaries will be annoying.
+      self._WarnUnimplemented('ARCHS')
+      archs = ['i386']
+    cflags.append('-arch ' + archs[0])
+
+    if archs[0] in ('i386', 'x86_64'):
+      if self._Test('GCC_ENABLE_SSE3_EXTENSIONS', 'YES', default='NO'):
+        cflags.append('-msse3')
+      if self._Test('GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS', 'YES',
+                    default='NO'):
+        cflags.append('-mssse3')  # Note 3rd 's'.
+      if self._Test('GCC_ENABLE_SSE41_EXTENSIONS', 'YES', default='NO'):
+        cflags.append('-msse4.1')
+      if self._Test('GCC_ENABLE_SSE42_EXTENSIONS', 'YES', default='NO'):
+        cflags.append('-msse4.2')
+
+    cflags += self._Settings().get('WARNING_CFLAGS', [])
+
+    if sdk_root:
+      framework_root = sdk_root
+    else:
+      framework_root = ''
+    config = self.spec['configurations'][self.configname]
+    framework_dirs = config.get('mac_framework_dirs', [])
+    for directory in framework_dirs:
+      cflags.append('-F' + directory.replace('$(SDKROOT)', framework_root))
+
+    self.configname = None
+    return cflags
+
+  def GetCflagsC(self, configname):
+    """Returns flags that need to be added to .c, and .m compilations."""
+    self.configname = configname
+    cflags_c = []
+    if self._Settings().get('GCC_C_LANGUAGE_STANDARD', '') == 'ansi':
+      cflags_c.append('-ansi')
+    else:
+      self._Appendf(cflags_c, 'GCC_C_LANGUAGE_STANDARD', '-std=%s')
+    cflags_c += self._Settings().get('OTHER_CFLAGS', [])
+    self.configname = None
+    return cflags_c
+
+  def GetCflagsCC(self, configname):
+    """Returns flags that need to be added to .cc, and .mm compilations."""
+    self.configname = configname
+    cflags_cc = []
+
+    clang_cxx_language_standard = self._Settings().get(
+        'CLANG_CXX_LANGUAGE_STANDARD')
+    # Note: Don't make c++0x to c++11 so that c++0x can be used with older
+    # clangs that don't understand c++11 yet (like Xcode 4.2's).
+    if clang_cxx_language_standard:
+      cflags_cc.append('-std=%s' % clang_cxx_language_standard)
+
+    self._Appendf(cflags_cc, 'CLANG_CXX_LIBRARY', '-stdlib=%s')
+
+    if self._Test('GCC_ENABLE_CPP_RTTI', 'NO', default='YES'):
+      cflags_cc.append('-fno-rtti')
+    if self._Test('GCC_ENABLE_CPP_EXCEPTIONS', 'NO', default='YES'):
+      cflags_cc.append('-fno-exceptions')
+    if self._Test('GCC_INLINES_ARE_PRIVATE_EXTERN', 'YES', default='NO'):
+      cflags_cc.append('-fvisibility-inlines-hidden')
+    if self._Test('GCC_THREADSAFE_STATICS', 'NO', default='YES'):
+      cflags_cc.append('-fno-threadsafe-statics')
+    # Note: This flag is a no-op for clang, it only has an effect for gcc.
+    if self._Test('GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO', 'NO', default='YES'):
+      cflags_cc.append('-Wno-invalid-offsetof')
+
+    other_ccflags = []
+
+    for flag in self._Settings().get('OTHER_CPLUSPLUSFLAGS', ['$(inherited)']):
+      # TODO: More general variable expansion. Missing in many other places too.
+      if flag in ('$inherited', '$(inherited)', '${inherited}'):
+        flag = '$OTHER_CFLAGS'
+      if flag in ('$OTHER_CFLAGS', '$(OTHER_CFLAGS)', '${OTHER_CFLAGS}'):
+        other_ccflags += self._Settings().get('OTHER_CFLAGS', [])
+      else:
+        other_ccflags.append(flag)
+    cflags_cc += other_ccflags
+
+    self.configname = None
+    return cflags_cc
+
+  def _AddObjectiveCGarbageCollectionFlags(self, flags):
+    gc_policy = self._Settings().get('GCC_ENABLE_OBJC_GC', 'unsupported')
+    if gc_policy == 'supported':
+      flags.append('-fobjc-gc')
+    elif gc_policy == 'required':
+      flags.append('-fobjc-gc-only')
+
+  def _AddObjectiveCARCFlags(self, flags):
+    if self._Test('CLANG_ENABLE_OBJC_ARC', 'YES', default='NO'):
+      flags.append('-fobjc-arc')
+
+  def _AddObjectiveCMissingPropertySynthesisFlags(self, flags):
+    if self._Test('CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS',
+                  'YES', default='NO'):
+      flags.append('-Wobjc-missing-property-synthesis')
+
+  def GetCflagsObjC(self, configname):
+    """Returns flags that need to be added to .m compilations."""
+    self.configname = configname
+    cflags_objc = []
+    self._AddObjectiveCGarbageCollectionFlags(cflags_objc)
+    self._AddObjectiveCARCFlags(cflags_objc)
+    self._AddObjectiveCMissingPropertySynthesisFlags(cflags_objc)
+    self.configname = None
+    return cflags_objc
+
+  def GetCflagsObjCC(self, configname):
+    """Returns flags that need to be added to .mm compilations."""
+    self.configname = configname
+    cflags_objcc = []
+    self._AddObjectiveCGarbageCollectionFlags(cflags_objcc)
+    self._AddObjectiveCARCFlags(cflags_objcc)
+    self._AddObjectiveCMissingPropertySynthesisFlags(cflags_objcc)
+    if self._Test('GCC_OBJC_CALL_CXX_CDTORS', 'YES', default='NO'):
+      cflags_objcc.append('-fobjc-call-cxx-cdtors')
+    self.configname = None
+    return cflags_objcc
+
+  def GetInstallNameBase(self):
+    """Return DYLIB_INSTALL_NAME_BASE for this target."""
+    # Xcode sets this for shared_libraries, and for nonbundled loadable_modules.
+    if (self.spec['type'] != 'shared_library' and
+        (self.spec['type'] != 'loadable_module' or self._IsBundle())):
+      return None
+    install_base = self.GetPerTargetSetting(
+        'DYLIB_INSTALL_NAME_BASE',
+        default='/Library/Frameworks' if self._IsBundle() else '/usr/local/lib')
+    return install_base
+
+  def _StandardizePath(self, path):
+    """Do :standardizepath processing for path."""
+    # I'm not quite sure what :standardizepath does. Just call normpath(),
+    # but don't let @executable_path/../foo collapse to foo.
+    if '/' in path:
+      prefix, rest = '', path
+      if path.startswith('@'):
+        prefix, rest = path.split('/', 1)
+      rest = os.path.normpath(rest)  # :standardizepath
+      path = os.path.join(prefix, rest)
+    return path
+
+  def GetInstallName(self):
+    """Return LD_DYLIB_INSTALL_NAME for this target."""
+    # Xcode sets this for shared_libraries, and for nonbundled loadable_modules.
+    if (self.spec['type'] != 'shared_library' and
+        (self.spec['type'] != 'loadable_module' or self._IsBundle())):
+      return None
+
+    default_install_name = \
+        '$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)'
+    install_name = self.GetPerTargetSetting(
+        'LD_DYLIB_INSTALL_NAME', default=default_install_name)
+
+    # Hardcode support for the variables used in chromium for now, to
+    # unblock people using the make build.
+    if '$' in install_name:
+      assert install_name in ('$(DYLIB_INSTALL_NAME_BASE:standardizepath)/'
+          '$(WRAPPER_NAME)/$(PRODUCT_NAME)', default_install_name), (
+          'Variables in LD_DYLIB_INSTALL_NAME are not generally supported '
+          'yet in target \'%s\' (got \'%s\')' %
+              (self.spec['target_name'], install_name))
+
+      install_name = install_name.replace(
+          '$(DYLIB_INSTALL_NAME_BASE:standardizepath)',
+          self._StandardizePath(self.GetInstallNameBase()))
+      if self._IsBundle():
+        # These are only valid for bundles, hence the |if|.
+        install_name = install_name.replace(
+            '$(WRAPPER_NAME)', self.GetWrapperName())
+        install_name = install_name.replace(
+            '$(PRODUCT_NAME)', self.GetProductName())
+      else:
+        assert '$(WRAPPER_NAME)' not in install_name
+        assert '$(PRODUCT_NAME)' not in install_name
+
+      install_name = install_name.replace(
+          '$(EXECUTABLE_PATH)', self.GetExecutablePath())
+    return install_name
+
+  def _MapLinkerFlagFilename(self, ldflag, gyp_to_build_path):
+    """Checks if ldflag contains a filename and if so remaps it from
+    gyp-directory-relative to build-directory-relative."""
+    # This list is expanded on demand.
+    # They get matched as:
+    #   -exported_symbols_list file
+    #   -Wl,exported_symbols_list file
+    #   -Wl,exported_symbols_list,file
+    LINKER_FILE = '(\S+)'
+    WORD = '\S+'
+    linker_flags = [
+      ['-exported_symbols_list', LINKER_FILE],    # Needed for NaCl.
+      ['-unexported_symbols_list', LINKER_FILE],
+      ['-reexported_symbols_list', LINKER_FILE],
+      ['-sectcreate', WORD, WORD, LINKER_FILE],   # Needed for remoting.
+    ]
+    for flag_pattern in linker_flags:
+      regex = re.compile('(?:-Wl,)?' + '[ ,]'.join(flag_pattern))
+      m = regex.match(ldflag)
+      if m:
+        ldflag = ldflag[:m.start(1)] + gyp_to_build_path(m.group(1)) + \
+                 ldflag[m.end(1):]
+    # Required for ffmpeg (no idea why they don't use LIBRARY_SEARCH_PATHS,
+    # TODO(thakis): Update ffmpeg.gyp):
+    if ldflag.startswith('-L'):
+      ldflag = '-L' + gyp_to_build_path(ldflag[len('-L'):])
+    return ldflag
+
+  def GetLdflags(self, configname, product_dir, gyp_to_build_path, arch=None):
+    """Returns flags that need to be passed to the linker.
+
+    Args:
+        configname: The name of the configuration to get ld flags for.
+        product_dir: The directory where products such static and dynamic
+            libraries are placed. This is added to the library search path.
+        gyp_to_build_path: A function that converts paths relative to the
+            current gyp file to paths relative to the build direcotry.
+    """
+    self.configname = configname
+    ldflags = []
+
+    # The xcode build is relative to a gyp file's directory, and OTHER_LDFLAGS
+    # can contain entries that depend on this. Explicitly absolutify these.
+    for ldflag in self._Settings().get('OTHER_LDFLAGS', []):
+      ldflags.append(self._MapLinkerFlagFilename(ldflag, gyp_to_build_path))
+
+    if self._Test('DEAD_CODE_STRIPPING', 'YES', default='NO'):
+      ldflags.append('-Wl,-dead_strip')
+
+    if self._Test('PREBINDING', 'YES', default='NO'):
+      ldflags.append('-Wl,-prebind')
+
+    self._Appendf(
+        ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s')
+    self._Appendf(
+        ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s')
+
+    self._AppendPlatformVersionMinFlags(ldflags)
+
+    if 'SDKROOT' in self._Settings() and self._SdkPath():
+      ldflags.append('-isysroot ' + self._SdkPath())
+
+    for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []):
+      ldflags.append('-L' + gyp_to_build_path(library_path))
+
+    if 'ORDER_FILE' in self._Settings():
+      ldflags.append('-Wl,-order_file ' +
+                     '-Wl,' + gyp_to_build_path(
+                                  self._Settings()['ORDER_FILE']))
+
+    if arch is not None:
+      archs = [arch]
+    else:
+      assert self.configname
+      archs = self.GetActiveArchs(self.configname)
+    if len(archs) != 1:
+      # TODO: Supporting fat binaries will be annoying.
+      self._WarnUnimplemented('ARCHS')
+      archs = ['i386']
+    ldflags.append('-arch ' + archs[0])
+
+    # Xcode adds the product directory by default.
+    ldflags.append('-L' + product_dir)
+
+    install_name = self.GetInstallName()
+    if install_name and self.spec['type'] != 'loadable_module':
+      ldflags.append('-install_name ' + install_name.replace(' ', r'\ '))
+
+    for rpath in self._Settings().get('LD_RUNPATH_SEARCH_PATHS', []):
+      ldflags.append('-Wl,-rpath,' + rpath)
+
+    sdk_root = self._SdkPath()
+    if not sdk_root:
+      sdk_root = ''
+    config = self.spec['configurations'][self.configname]
+    framework_dirs = config.get('mac_framework_dirs', [])
+    for directory in framework_dirs:
+      ldflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root))
+
+    if sdk_root and self._IsIosAppExtension():
+      # Adds the link flags for extensions. These flags are common for all
+      # extensions and provide loader and main function.
+      # These flags reflect the compilation options used by xcode to compile
+      # extensions.
+      ldflags.append('-lpkstart')
+      ldflags.append(sdk_root +
+          '/System/Library/PrivateFrameworks/PlugInKit.framework/PlugInKit')
+      ldflags.append('-fapplication-extension')
+      ldflags.append('-Xlinker -rpath '
+          '-Xlinker @executable_path/../../Frameworks')
+
+    self._Appendf(ldflags, 'CLANG_CXX_LIBRARY', '-stdlib=%s')
+
+    self.configname = None
+    return ldflags
+
+  def GetLibtoolflags(self, configname):
+    """Returns flags that need to be passed to the static linker.
+
+    Args:
+        configname: The name of the configuration to get ld flags for.
+    """
+    self.configname = configname
+    libtoolflags = []
+
+    for libtoolflag in self._Settings().get('OTHER_LDFLAGS', []):
+      libtoolflags.append(libtoolflag)
+    # TODO(thakis): ARCHS?
+
+    self.configname = None
+    return libtoolflags
+
+  def GetPerTargetSettings(self):
+    """Gets a list of all the per-target settings. This will only fetch keys
+    whose values are the same across all configurations."""
+    first_pass = True
+    result = {}
+    for configname in sorted(self.xcode_settings.keys()):
+      if first_pass:
+        result = dict(self.xcode_settings[configname])
+        first_pass = False
+      else:
+        for key, value in self.xcode_settings[configname].iteritems():
+          if key not in result:
+            continue
+          elif result[key] != value:
+            del result[key]
+    return result
+
+  def GetPerConfigSetting(self, setting, configname, default=None):
+    if configname in self.xcode_settings:
+      return self.xcode_settings[configname].get(setting, default)
+    else:
+      return self.GetPerTargetSetting(setting, default)
+
+  def GetPerTargetSetting(self, setting, default=None):
+    """Tries to get xcode_settings.setting from spec. Assumes that the setting
+       has the same value in all configurations and throws otherwise."""
+    is_first_pass = True
+    result = None
+    for configname in sorted(self.xcode_settings.keys()):
+      if is_first_pass:
+        result = self.xcode_settings[configname].get(setting, None)
+        is_first_pass = False
+      else:
+        assert result == self.xcode_settings[configname].get(setting, None), (
+            "Expected per-target setting for '%s', got per-config setting "
+            "(target %s)" % (setting, self.spec['target_name']))
+    if result is None:
+      return default
+    return result
+
+  def _GetStripPostbuilds(self, configname, output_binary, quiet):
+    """Returns a list of shell commands that contain the shell commands
+    neccessary to strip this target's binary. These should be run as postbuilds
+    before the actual postbuilds run."""
+    self.configname = configname
+
+    result = []
+    if (self._Test('DEPLOYMENT_POSTPROCESSING', 'YES', default='NO') and
+        self._Test('STRIP_INSTALLED_PRODUCT', 'YES', default='NO')):
+
+      default_strip_style = 'debugging'
+      if self.spec['type'] == 'loadable_module' and self._IsBundle():
+        default_strip_style = 'non-global'
+      elif self.spec['type'] == 'executable':
+        default_strip_style = 'all'
+
+      strip_style = self._Settings().get('STRIP_STYLE', default_strip_style)
+      strip_flags = {
+        'all': '',
+        'non-global': '-x',
+        'debugging': '-S',
+      }[strip_style]
+
+      explicit_strip_flags = self._Settings().get('STRIPFLAGS', '')
+      if explicit_strip_flags:
+        strip_flags += ' ' + _NormalizeEnvVarReferences(explicit_strip_flags)
+
+      if not quiet:
+        result.append('echo STRIP\\(%s\\)' % self.spec['target_name'])
+      result.append('strip %s %s' % (strip_flags, output_binary))
+
+    self.configname = None
+    return result
+
+  def _GetDebugInfoPostbuilds(self, configname, output, output_binary, quiet):
+    """Returns a list of shell commands that contain the shell commands
+    neccessary to massage this target's debug information. These should be run
+    as postbuilds before the actual postbuilds run."""
+    self.configname = configname
+
+    # For static libraries, no dSYMs are created.
+    result = []
+    if (self._Test('GCC_GENERATE_DEBUGGING_SYMBOLS', 'YES', default='YES') and
+        self._Test(
+            'DEBUG_INFORMATION_FORMAT', 'dwarf-with-dsym', default='dwarf') and
+        self.spec['type'] != 'static_library'):
+      if not quiet:
+        result.append('echo DSYMUTIL\\(%s\\)' % self.spec['target_name'])
+      result.append('dsymutil %s -o %s' % (output_binary, output + '.dSYM'))
+
+    self.configname = None
+    return result
+
+  def _GetTargetPostbuilds(self, configname, output, output_binary,
+                           quiet=False):
+    """Returns a list of shell commands that contain the shell commands
+    to run as postbuilds for this target, before the actual postbuilds."""
+    # dSYMs need to build before stripping happens.
+    return (
+        self._GetDebugInfoPostbuilds(configname, output, output_binary, quiet) +
+        self._GetStripPostbuilds(configname, output_binary, quiet))
+
+  def _GetIOSPostbuilds(self, configname, output_binary):
+    """Return a shell command to codesign the iOS output binary so it can
+    be deployed to a device.  This should be run as the very last step of the
+    build."""
+    if not (self.isIOS and self.spec['type'] == 'executable'):
+      return []
+
+    settings = self.xcode_settings[configname]
+    key = self._GetIOSCodeSignIdentityKey(settings)
+    if not key:
+      return []
+
+    # Warn for any unimplemented signing xcode keys.
+    unimpl = ['OTHER_CODE_SIGN_FLAGS']
+    unimpl = set(unimpl) & set(self.xcode_settings[configname].keys())
+    if unimpl:
+      print 'Warning: Some codesign keys not implemented, ignoring: %s' % (
+          ', '.join(sorted(unimpl)))
+
+    return ['%s code-sign-bundle "%s" "%s" "%s" "%s"' % (
+        os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
+        settings.get('CODE_SIGN_RESOURCE_RULES_PATH', ''),
+        settings.get('CODE_SIGN_ENTITLEMENTS', ''),
+        settings.get('PROVISIONING_PROFILE', ''))
+    ]
+
+  def _GetIOSCodeSignIdentityKey(self, settings):
+    identity = settings.get('CODE_SIGN_IDENTITY')
+    if not identity:
+      return None
+    if identity not in XcodeSettings._codesigning_key_cache:
+      output = subprocess.check_output(
+          ['security', 'find-identity', '-p', 'codesigning', '-v'])
+      for line in output.splitlines():
+        if identity in line:
+          fingerprint = line.split()[1]
+          cache = XcodeSettings._codesigning_key_cache
+          assert identity not in cache or fingerprint == cache[identity], (
+              "Multiple codesigning fingerprints for identity: %s" % identity)
+          XcodeSettings._codesigning_key_cache[identity] = fingerprint
+    return XcodeSettings._codesigning_key_cache.get(identity, '')
+
+  def AddImplicitPostbuilds(self, configname, output, output_binary,
+                            postbuilds=[], quiet=False):
+    """Returns a list of shell commands that should run before and after
+    |postbuilds|."""
+    assert output_binary is not None
+    pre = self._GetTargetPostbuilds(configname, output, output_binary, quiet)
+    post = self._GetIOSPostbuilds(configname, output_binary)
+    return pre + postbuilds + post
+
+  def _AdjustLibrary(self, library, config_name=None):
+    if library.endswith('.framework'):
+      l = '-framework ' + os.path.splitext(os.path.basename(library))[0]
+    else:
+      m = self.library_re.match(library)
+      if m:
+        l = '-l' + m.group(1)
+      else:
+        l = library
+
+    sdk_root = self._SdkPath(config_name)
+    if not sdk_root:
+      sdk_root = ''
+    return l.replace('$(SDKROOT)', sdk_root)
+
+  def AdjustLibraries(self, libraries, config_name=None):
+    """Transforms entries like 'Cocoa.framework' in libraries into entries like
+    '-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc.
+    """
+    libraries = [self._AdjustLibrary(library, config_name)
+                 for library in libraries]
+    return libraries
+
+  def _BuildMachineOSBuild(self):
+    return GetStdout(['sw_vers', '-buildVersion'])
+
+  def _XcodeIOSDeviceFamily(self, configname):
+    family = self.xcode_settings[configname].get('TARGETED_DEVICE_FAMILY', '1')
+    return [int(x) for x in family.split(',')]
+
+  def GetExtraPlistItems(self, configname=None):
+    """Returns a dictionary with extra items to insert into Info.plist."""
+    if configname not in XcodeSettings._plist_cache:
+      cache = {}
+      cache['BuildMachineOSBuild'] = self._BuildMachineOSBuild()
+
+      xcode, xcode_build = XcodeVersion()
+      cache['DTXcode'] = xcode
+      cache['DTXcodeBuild'] = xcode_build
+
+      sdk_root = self._SdkRoot(configname)
+      if not sdk_root:
+        sdk_root = self._DefaultSdkRoot()
+      cache['DTSDKName'] = sdk_root
+      if xcode >= '0430':
+        cache['DTSDKBuild'] = self._GetSdkVersionInfoItem(
+            sdk_root, 'ProductBuildVersion')
+      else:
+        cache['DTSDKBuild'] = cache['BuildMachineOSBuild']
+
+      if self.isIOS:
+        cache['DTPlatformName'] = cache['DTSDKName']
+        if configname.endswith("iphoneos"):
+          cache['DTPlatformVersion'] = self._GetSdkVersionInfoItem(
+              sdk_root, 'ProductVersion')
+          cache['CFBundleSupportedPlatforms'] = ['iPhoneOS']
+        else:
+          cache['CFBundleSupportedPlatforms'] = ['iPhoneSimulator']
+      XcodeSettings._plist_cache[configname] = cache
+
+    # Include extra plist items that are per-target, not per global
+    # XcodeSettings.
+    items = dict(XcodeSettings._plist_cache[configname])
+    if self.isIOS:
+      items['UIDeviceFamily'] = self._XcodeIOSDeviceFamily(configname)
+    return items
+
+  def _DefaultSdkRoot(self):
+    """Returns the default SDKROOT to use.
+
+    Prior to version 5.0.0, if SDKROOT was not explicitly set in the Xcode
+    project, then the environment variable was empty. Starting with this
+    version, Xcode uses the name of the newest SDK installed.
+    """
+    xcode_version, xcode_build = XcodeVersion()
+    if xcode_version < '0500':
+      return ''
+    default_sdk_path = self._XcodeSdkPath('')
+    default_sdk_root = XcodeSettings._sdk_root_cache.get(default_sdk_path)
+    if default_sdk_root:
+      return default_sdk_root
+    try:
+      all_sdks = GetStdout(['xcodebuild', '-showsdks'])
+    except:
+      # If xcodebuild fails, there will be no valid SDKs
+      return ''
+    for line in all_sdks.splitlines():
+      items = line.split()
+      if len(items) >= 3 and items[-2] == '-sdk':
+        sdk_root = items[-1]
+        sdk_path = self._XcodeSdkPath(sdk_root)
+        if sdk_path == default_sdk_path:
+          return sdk_root
+    return ''
+
+
+class MacPrefixHeader(object):
+  """A class that helps with emulating Xcode's GCC_PREFIX_HEADER feature.
+
+  This feature consists of several pieces:
+  * If GCC_PREFIX_HEADER is present, all compilations in that project get an
+    additional |-include path_to_prefix_header| cflag.
+  * If GCC_PRECOMPILE_PREFIX_HEADER is present too, then the prefix header is
+    instead compiled, and all other compilations in the project get an
+    additional |-include path_to_compiled_header| instead.
+    + Compiled prefix headers have the extension gch. There is one gch file for
+      every language used in the project (c, cc, m, mm), since gch files for
+      different languages aren't compatible.
+    + gch files themselves are built with the target's normal cflags, but they
+      obviously don't get the |-include| flag. Instead, they need a -x flag that
+      describes their language.
+    + All o files in the target need to depend on the gch file, to make sure
+      it's built before any o file is built.
+
+  This class helps with some of these tasks, but it needs help from the build
+  system for writing dependencies to the gch files, for writing build commands
+  for the gch files, and for figuring out the location of the gch files.
+  """
+  def __init__(self, xcode_settings,
+               gyp_path_to_build_path, gyp_path_to_build_output):
+    """If xcode_settings is None, all methods on this class are no-ops.
+
+    Args:
+        gyp_path_to_build_path: A function that takes a gyp-relative path,
+            and returns a path relative to the build directory.
+        gyp_path_to_build_output: A function that takes a gyp-relative path and
+            a language code ('c', 'cc', 'm', or 'mm'), and that returns a path
+            to where the output of precompiling that path for that language
+            should be placed (without the trailing '.gch').
+    """
+    # This doesn't support per-configuration prefix headers. Good enough
+    # for now.
+    self.header = None
+    self.compile_headers = False
+    if xcode_settings:
+      self.header = xcode_settings.GetPerTargetSetting('GCC_PREFIX_HEADER')
+      self.compile_headers = xcode_settings.GetPerTargetSetting(
+          'GCC_PRECOMPILE_PREFIX_HEADER', default='NO') != 'NO'
+    self.compiled_headers = {}
+    if self.header:
+      if self.compile_headers:
+        for lang in ['c', 'cc', 'm', 'mm']:
+          self.compiled_headers[lang] = gyp_path_to_build_output(
+              self.header, lang)
+      self.header = gyp_path_to_build_path(self.header)
+
+  def _CompiledHeader(self, lang, arch):
+    assert self.compile_headers
+    h = self.compiled_headers[lang]
+    if arch:
+      h += '.' + arch
+    return h
+
+  def GetInclude(self, lang, arch=None):
+    """Gets the cflags to include the prefix header for language |lang|."""
+    if self.compile_headers and lang in self.compiled_headers:
+      return '-include %s' % self._CompiledHeader(lang, arch)
+    elif self.header:
+      return '-include %s' % self.header
+    else:
+      return ''
+
+  def _Gch(self, lang, arch):
+    """Returns the actual file name of the prefix header for language |lang|."""
+    assert self.compile_headers
+    return self._CompiledHeader(lang, arch) + '.gch'
+
+  def GetObjDependencies(self, sources, objs, arch=None):
+    """Given a list of source files and the corresponding object files, returns
+    a list of (source, object, gch) tuples, where |gch| is the build-directory
+    relative path to the gch file each object file depends on.  |compilable[i]|
+    has to be the source file belonging to |objs[i]|."""
+    if not self.header or not self.compile_headers:
+      return []
+
+    result = []
+    for source, obj in zip(sources, objs):
+      ext = os.path.splitext(source)[1]
+      lang = {
+        '.c': 'c',
+        '.cpp': 'cc', '.cc': 'cc', '.cxx': 'cc',
+        '.m': 'm',
+        '.mm': 'mm',
+      }.get(ext, None)
+      if lang:
+        result.append((source, obj, self._Gch(lang, arch)))
+    return result
+
+  def GetPchBuildCommands(self, arch=None):
+    """Returns [(path_to_gch, language_flag, language, header)].
+    |path_to_gch| and |header| are relative to the build directory.
+    """
+    if not self.header or not self.compile_headers:
+      return []
+    return [
+      (self._Gch('c', arch), '-x c-header', 'c', self.header),
+      (self._Gch('cc', arch), '-x c++-header', 'cc', self.header),
+      (self._Gch('m', arch), '-x objective-c-header', 'm', self.header),
+      (self._Gch('mm', arch), '-x objective-c++-header', 'mm', self.header),
+    ]
+
+
+def XcodeVersion():
+  """Returns a tuple of version and build version of installed Xcode."""
+  # `xcodebuild -version` output looks like
+  #    Xcode 4.6.3
+  #    Build version 4H1503
+  # or like
+  #    Xcode 3.2.6
+  #    Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0
+  #    BuildVersion: 10M2518
+  # Convert that to '0463', '4H1503'.
+  global XCODE_VERSION_CACHE
+  if XCODE_VERSION_CACHE:
+    return XCODE_VERSION_CACHE
+  try:
+    version_list = GetStdout(['xcodebuild', '-version']).splitlines()
+    # In some circumstances xcodebuild exits 0 but doesn't return
+    # the right results; for example, a user on 10.7 or 10.8 with
+    # a bogus path set via xcode-select
+    # In that case this may be a CLT-only install so fall back to
+    # checking that version.
+    if len(version_list) < 2:
+      raise GypError, "xcodebuild returned unexpected results"
+  except:
+    version = CLTVersion()
+    if version:
+      version = re.match('(\d\.\d\.?\d*)', version).groups()[0]
+    else:
+      raise GypError, "No Xcode or CLT version detected!"
+    # The CLT has no build information, so we return an empty string.
+    version_list = [version, '']
+  version = version_list[0]
+  build = version_list[-1]
+  # Be careful to convert "4.2" to "0420":
+  version = version.split()[-1].replace('.', '')
+  version = (version + '0' * (3 - len(version))).zfill(4)
+  if build:
+    build = build.split()[-1]
+  XCODE_VERSION_CACHE = (version, build)
+  return XCODE_VERSION_CACHE
+
+
+# This function ported from the logic in Homebrew's CLT version check
+def CLTVersion():
+  """Returns the version of command-line tools from pkgutil."""
+  # pkgutil output looks like
+  #   package-id: com.apple.pkg.CLTools_Executables
+  #   version: 5.0.1.0.1.1382131676
+  #   volume: /
+  #   location: /
+  #   install-time: 1382544035
+  #   groups: com.apple.FindSystemFiles.pkg-group com.apple.DevToolsBoth.pkg-group com.apple.DevToolsNonRelocatableShared.pkg-group
+  STANDALONE_PKG_ID = "com.apple.pkg.DeveloperToolsCLILeo"
+  FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI"
+  MAVERICKS_PKG_ID = "com.apple.pkg.CLTools_Executables"
+
+  regex = re.compile('version: (?P<version>.+)')
+  for key in [MAVERICKS_PKG_ID, STANDALONE_PKG_ID, FROM_XCODE_PKG_ID]:
+    try:
+      output = GetStdout(['/usr/sbin/pkgutil', '--pkg-info', key])
+      return re.search(regex, output).groupdict()['version']
+    except:
+      continue
+
+
+def GetStdout(cmdlist):
+  """Returns the content of standard output returned by invoking |cmdlist|.
+  Raises |GypError| if the command return with a non-zero return code."""
+  job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE)
+  out = job.communicate()[0]
+  if job.returncode != 0:
+    sys.stderr.write(out + '\n')
+    raise GypError('Error %d running %s' % (job.returncode, cmdlist[0]))
+  return out.rstrip('\n')
+
+
+def MergeGlobalXcodeSettingsToSpec(global_dict, spec):
+  """Merges the global xcode_settings dictionary into each configuration of the
+  target represented by spec. For keys that are both in the global and the local
+  xcode_settings dict, the local key gets precendence.
+  """
+  # The xcode generator special-cases global xcode_settings and does something
+  # that amounts to merging in the global xcode_settings into each local
+  # xcode_settings dict.
+  global_xcode_settings = global_dict.get('xcode_settings', {})
+  for config in spec['configurations'].values():
+    if 'xcode_settings' in config:
+      new_settings = global_xcode_settings.copy()
+      new_settings.update(config['xcode_settings'])
+      config['xcode_settings'] = new_settings
+
+
+def IsMacBundle(flavor, spec):
+  """Returns if |spec| should be treated as a bundle.
+
+  Bundles are directories with a certain subdirectory structure, instead of
+  just a single file. Bundle rules do not produce a binary but also package
+  resources into that directory."""
+  is_mac_bundle = (int(spec.get('mac_bundle', 0)) != 0 and flavor == 'mac')
+  if is_mac_bundle:
+    assert spec['type'] != 'none', (
+        'mac_bundle targets cannot have type none (target "%s")' %
+        spec['target_name'])
+  return is_mac_bundle
+
+
+def GetMacBundleResources(product_dir, xcode_settings, resources):
+  """Yields (output, resource) pairs for every resource in |resources|.
+  Only call this for mac bundle targets.
+
+  Args:
+      product_dir: Path to the directory containing the output bundle,
+          relative to the build directory.
+      xcode_settings: The XcodeSettings of the current target.
+      resources: A list of bundle resources, relative to the build directory.
+  """
+  dest = os.path.join(product_dir,
+                      xcode_settings.GetBundleResourceFolder())
+  for res in resources:
+    output = dest
+
+    # The make generator doesn't support it, so forbid it everywhere
+    # to keep the generators more interchangable.
+    assert ' ' not in res, (
+      "Spaces in resource filenames not supported (%s)"  % res)
+
+    # Split into (path,file).
+    res_parts = os.path.split(res)
+
+    # Now split the path into (prefix,maybe.lproj).
+    lproj_parts = os.path.split(res_parts[0])
+    # If the resource lives in a .lproj bundle, add that to the destination.
+    if lproj_parts[1].endswith('.lproj'):
+      output = os.path.join(output, lproj_parts[1])
+
+    output = os.path.join(output, res_parts[1])
+    # Compiled XIB files are referred to by .nib.
+    if output.endswith('.xib'):
+      output = os.path.splitext(output)[0] + '.nib'
+    # Compiled storyboard files are referred to by .storyboardc.
+    if output.endswith('.storyboard'):
+      output = os.path.splitext(output)[0] + '.storyboardc'
+
+    yield output, res
+
+
+def GetMacInfoPlist(product_dir, xcode_settings, gyp_path_to_build_path):
+  """Returns (info_plist, dest_plist, defines, extra_env), where:
+  * |info_plist| is the source plist path, relative to the
+    build directory,
+  * |dest_plist| is the destination plist path, relative to the
+    build directory,
+  * |defines| is a list of preprocessor defines (empty if the plist
+    shouldn't be preprocessed,
+  * |extra_env| is a dict of env variables that should be exported when
+    invoking |mac_tool copy-info-plist|.
+
+  Only call this for mac bundle targets.
+
+  Args:
+      product_dir: Path to the directory containing the output bundle,
+          relative to the build directory.
+      xcode_settings: The XcodeSettings of the current target.
+      gyp_to_build_path: A function that converts paths relative to the
+          current gyp file to paths relative to the build direcotry.
+  """
+  info_plist = xcode_settings.GetPerTargetSetting('INFOPLIST_FILE')
+  if not info_plist:
+    return None, None, [], {}
+
+  # The make generator doesn't support it, so forbid it everywhere
+  # to keep the generators more interchangable.
+  assert ' ' not in info_plist, (
+    "Spaces in Info.plist filenames not supported (%s)"  % info_plist)
+
+  info_plist = gyp_path_to_build_path(info_plist)
+
+  # If explicitly set to preprocess the plist, invoke the C preprocessor and
+  # specify any defines as -D flags.
+  if xcode_settings.GetPerTargetSetting(
+      'INFOPLIST_PREPROCESS', default='NO') == 'YES':
+    # Create an intermediate file based on the path.
+    defines = shlex.split(xcode_settings.GetPerTargetSetting(
+        'INFOPLIST_PREPROCESSOR_DEFINITIONS', default=''))
+  else:
+    defines = []
+
+  dest_plist = os.path.join(product_dir, xcode_settings.GetBundlePlistPath())
+  extra_env = xcode_settings.GetPerTargetSettings()
+
+  return info_plist, dest_plist, defines, extra_env
+
+
+def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
+                additional_settings=None):
+  """Return the environment variables that Xcode would set. See
+  http://developer.apple.com/library/mac/#documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW153
+  for a full list.
+
+  Args:
+      xcode_settings: An XcodeSettings object. If this is None, this function
+          returns an empty dict.
+      built_products_dir: Absolute path to the built products dir.
+      srcroot: Absolute path to the source root.
+      configuration: The build configuration name.
+      additional_settings: An optional dict with more values to add to the
+          result.
+  """
+  if not xcode_settings: return {}
+
+  # This function is considered a friend of XcodeSettings, so let it reach into
+  # its implementation details.
+  spec = xcode_settings.spec
+
+  # These are filled in on a as-needed basis.
+  env = {
+    'BUILT_PRODUCTS_DIR' : built_products_dir,
+    'CONFIGURATION' : configuration,
+    'PRODUCT_NAME' : xcode_settings.GetProductName(),
+    # See /Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX\ Product\ Types.xcspec for FULL_PRODUCT_NAME
+    'SRCROOT' : srcroot,
+    'SOURCE_ROOT': '${SRCROOT}',
+    # This is not true for static libraries, but currently the env is only
+    # written for bundles:
+    'TARGET_BUILD_DIR' : built_products_dir,
+    'TEMP_DIR' : '${TMPDIR}',
+  }
+  if xcode_settings.GetPerConfigSetting('SDKROOT', configuration):
+    env['SDKROOT'] = xcode_settings._SdkPath(configuration)
+  else:
+    env['SDKROOT'] = ''
+
+  if spec['type'] in (
+      'executable', 'static_library', 'shared_library', 'loadable_module'):
+    env['EXECUTABLE_NAME'] = xcode_settings.GetExecutableName()
+    env['EXECUTABLE_PATH'] = xcode_settings.GetExecutablePath()
+    env['FULL_PRODUCT_NAME'] = xcode_settings.GetFullProductName()
+    mach_o_type = xcode_settings.GetMachOType()
+    if mach_o_type:
+      env['MACH_O_TYPE'] = mach_o_type
+    env['PRODUCT_TYPE'] = xcode_settings.GetProductType()
+  if xcode_settings._IsBundle():
+    env['CONTENTS_FOLDER_PATH'] = \
+      xcode_settings.GetBundleContentsFolderPath()
+    env['UNLOCALIZED_RESOURCES_FOLDER_PATH'] = \
+        xcode_settings.GetBundleResourceFolder()
+    env['INFOPLIST_PATH'] = xcode_settings.GetBundlePlistPath()
+    env['WRAPPER_NAME'] = xcode_settings.GetWrapperName()
+
+  install_name = xcode_settings.GetInstallName()
+  if install_name:
+    env['LD_DYLIB_INSTALL_NAME'] = install_name
+  install_name_base = xcode_settings.GetInstallNameBase()
+  if install_name_base:
+    env['DYLIB_INSTALL_NAME_BASE'] = install_name_base
+  if XcodeVersion() >= '0500' and not env.get('SDKROOT'):
+    sdk_root = xcode_settings._SdkRoot(configuration)
+    if not sdk_root:
+      sdk_root = xcode_settings._XcodeSdkPath('')
+    env['SDKROOT'] = sdk_root
+
+  if not additional_settings:
+    additional_settings = {}
+  else:
+    # Flatten lists to strings.
+    for k in additional_settings:
+      if not isinstance(additional_settings[k], str):
+        additional_settings[k] = ' '.join(additional_settings[k])
+  additional_settings.update(env)
+
+  for k in additional_settings:
+    additional_settings[k] = _NormalizeEnvVarReferences(additional_settings[k])
+
+  return additional_settings
+
+
+def _NormalizeEnvVarReferences(str):
+  """Takes a string containing variable references in the form ${FOO}, $(FOO),
+  or $FOO, and returns a string with all variable references in the form ${FOO}.
+  """
+  # $FOO -> ${FOO}
+  str = re.sub(r'\$([a-zA-Z_][a-zA-Z0-9_]*)', r'${\1}', str)
+
+  # $(FOO) -> ${FOO}
+  matches = re.findall(r'(\$\(([a-zA-Z0-9\-_]+)\))', str)
+  for match in matches:
+    to_replace, variable = match
+    assert '$(' not in match, '$($(FOO)) variables not supported: ' + match
+    str = str.replace(to_replace, '${' + variable + '}')
+
+  return str
+
+
+def ExpandEnvVars(string, expansions):
+  """Expands ${VARIABLES}, $(VARIABLES), and $VARIABLES in string per the
+  expansions list. If the variable expands to something that references
+  another variable, this variable is expanded as well if it's in env --
+  until no variables present in env are left."""
+  for k, v in reversed(expansions):
+    string = string.replace('${' + k + '}', v)
+    string = string.replace('$(' + k + ')', v)
+    string = string.replace('$' + k, v)
+  return string
+
+
+def _TopologicallySortedEnvVarKeys(env):
+  """Takes a dict |env| whose values are strings that can refer to other keys,
+  for example env['foo'] = '$(bar) and $(baz)'. Returns a list L of all keys of
+  env such that key2 is after key1 in L if env[key2] refers to env[key1].
+
+  Throws an Exception in case of dependency cycles.
+  """
+  # Since environment variables can refer to other variables, the evaluation
+  # order is important. Below is the logic to compute the dependency graph
+  # and sort it.
+  regex = re.compile(r'\$\{([a-zA-Z0-9\-_]+)\}')
+  def GetEdges(node):
+    # Use a definition of edges such that user_of_variable -> used_varible.
+    # This happens to be easier in this case, since a variable's
+    # definition contains all variables it references in a single string.
+    # We can then reverse the result of the topological sort at the end.
+    # Since: reverse(topsort(DAG)) = topsort(reverse_edges(DAG))
+    matches = set([v for v in regex.findall(env[node]) if v in env])
+    for dependee in matches:
+      assert '${' not in dependee, 'Nested variables not supported: ' + dependee
+    return matches
+
+  try:
+    # Topologically sort, and then reverse, because we used an edge definition
+    # that's inverted from the expected result of this function (see comment
+    # above).
+    order = gyp.common.TopologicallySorted(env.keys(), GetEdges)
+    order.reverse()
+    return order
+  except gyp.common.CycleError, e:
+    raise GypError(
+        'Xcode environment variables are cyclically dependent: ' + str(e.nodes))
+
+
+def GetSortedXcodeEnv(xcode_settings, built_products_dir, srcroot,
+                      configuration, additional_settings=None):
+  env = _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
+                    additional_settings)
+  return [(key, env[key]) for key in _TopologicallySortedEnvVarKeys(env)]
+
+
+def GetSpecPostbuildCommands(spec, quiet=False):
+  """Returns the list of postbuilds explicitly defined on |spec|, in a form
+  executable by a shell."""
+  postbuilds = []
+  for postbuild in spec.get('postbuilds', []):
+    if not quiet:
+      postbuilds.append('echo POSTBUILD\\(%s\\) %s' % (
+            spec['target_name'], postbuild['postbuild_name']))
+    postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action']))
+  return postbuilds
+
+
+def _HasIOSTarget(targets):
+  """Returns true if any target contains the iOS specific key
+  IPHONEOS_DEPLOYMENT_TARGET."""
+  for target_dict in targets.values():
+    for config in target_dict['configurations'].values():
+      if config.get('xcode_settings', {}).get('IPHONEOS_DEPLOYMENT_TARGET'):
+        return True
+  return False
+
+
+def _AddIOSDeviceConfigurations(targets):
+  """Clone all targets and append -iphoneos to the name. Configure these targets
+  to build for iOS devices and use correct architectures for those builds."""
+  for target_dict in targets.itervalues():
+    toolset = target_dict['toolset']
+    configs = target_dict['configurations']
+    for config_name, config_dict in dict(configs).iteritems():
+      iphoneos_config_dict = copy.deepcopy(config_dict)
+      configs[config_name + '-iphoneos'] = iphoneos_config_dict
+      configs[config_name + '-iphonesimulator'] = config_dict
+      if toolset == 'target':
+        iphoneos_config_dict['xcode_settings']['SDKROOT'] = 'iphoneos'
+  return targets
+
+def CloneConfigurationForDeviceAndEmulator(target_dicts):
+  """If |target_dicts| contains any iOS targets, automatically create -iphoneos
+  targets for iOS device builds."""
+  if _HasIOSTarget(target_dicts):
+    return _AddIOSDeviceConfigurations(target_dicts)
+  return target_dicts
diff --git a/gyp/pylib/gyp/xcode_ninja.py b/gyp/pylib/gyp/xcode_ninja.py
new file mode 100644 (file)
index 0000000..a005dfd
--- /dev/null
@@ -0,0 +1,259 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Xcode-ninja wrapper project file generator.
+
+This updates the data structures passed to the Xcode gyp generator to build
+with ninja instead. The Xcode project itself is transformed into a list of
+executable targets, each with a build step to build with ninja, and a target
+with every source and resource file.  This appears to sidestep some of the
+major performance headaches experienced using complex projects and large number
+of targets within Xcode.
+"""
+
+import errno
+import gyp.generator.ninja
+import os
+import re
+import xml.sax.saxutils
+
+
+def _WriteWorkspace(main_gyp, sources_gyp):
+  """ Create a workspace to wrap main and sources gyp paths. """
+  (build_file_root, build_file_ext) = os.path.splitext(main_gyp)
+  workspace_path = build_file_root + '.xcworkspace'
+  try:
+    os.makedirs(workspace_path)
+  except OSError, e:
+    if e.errno != errno.EEXIST:
+      raise
+  output_string = '<?xml version="1.0" encoding="UTF-8"?>\n' + \
+                  '<Workspace version = "1.0">\n'
+  for gyp_name in [main_gyp, sources_gyp]:
+    name = os.path.splitext(os.path.basename(gyp_name))[0] + '.xcodeproj'
+    name = xml.sax.saxutils.quoteattr("group:" + name)
+    output_string += '  <FileRef location = %s></FileRef>\n' % name
+  output_string += '</Workspace>\n'
+
+  workspace_file = os.path.join(workspace_path, "contents.xcworkspacedata")
+
+  try:
+    with open(workspace_file, 'r') as input_file:
+      input_string = input_file.read()
+      if input_string == output_string:
+        return
+  except IOError:
+    # Ignore errors if the file doesn't exist.
+    pass
+
+  with open(workspace_file, 'w') as output_file:
+    output_file.write(output_string)
+
+def _TargetFromSpec(old_spec, params):
+  """ Create fake target for xcode-ninja wrapper. """
+  # Determine ninja top level build dir (e.g. /path/to/out).
+  ninja_toplevel = None
+  jobs = 0
+  if params:
+    options = params['options']
+    ninja_toplevel = \
+        os.path.join(options.toplevel_dir,
+                     gyp.generator.ninja.ComputeOutputDir(params))
+    jobs = params.get('generator_flags', {}).get('xcode_ninja_jobs', 0)
+
+  target_name = old_spec.get('target_name')
+  product_name = old_spec.get('product_name', target_name)
+
+  ninja_target = {}
+  ninja_target['target_name'] = target_name
+  ninja_target['product_name'] = product_name
+  ninja_target['toolset'] = old_spec.get('toolset')
+  ninja_target['default_configuration'] = old_spec.get('default_configuration')
+  ninja_target['configurations'] = {}
+
+  # Tell Xcode to look in |ninja_toplevel| for build products.
+  new_xcode_settings = {}
+  if ninja_toplevel:
+    new_xcode_settings['CONFIGURATION_BUILD_DIR'] = \
+        "%s/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)" % ninja_toplevel
+
+  if 'configurations' in old_spec:
+    for config in old_spec['configurations'].iterkeys():
+      old_xcode_settings = \
+        old_spec['configurations'][config].get('xcode_settings', {})
+      if 'IPHONEOS_DEPLOYMENT_TARGET' in old_xcode_settings:
+        new_xcode_settings['CODE_SIGNING_REQUIRED'] = "NO"
+        new_xcode_settings['IPHONEOS_DEPLOYMENT_TARGET'] = \
+            old_xcode_settings['IPHONEOS_DEPLOYMENT_TARGET']
+      ninja_target['configurations'][config] = {}
+      ninja_target['configurations'][config]['xcode_settings'] = \
+          new_xcode_settings
+
+  ninja_target['mac_bundle'] = old_spec.get('mac_bundle', 0)
+  ninja_target['ios_app_extension'] = old_spec.get('ios_app_extension', 0)
+  ninja_target['type'] = old_spec['type']
+  if ninja_toplevel:
+    ninja_target['actions'] = [
+      {
+        'action_name': 'Compile and copy %s via ninja' % target_name,
+        'inputs': [],
+        'outputs': [],
+        'action': [
+          'env',
+          'PATH=%s' % os.environ['PATH'],
+          'ninja',
+          '-C',
+          new_xcode_settings['CONFIGURATION_BUILD_DIR'],
+          target_name,
+        ],
+        'message': 'Compile and copy %s via ninja' % target_name,
+      },
+    ]
+    if jobs > 0:
+      ninja_target['actions'][0]['action'].extend(('-j', jobs))
+  return ninja_target
+
+def IsValidTargetForWrapper(target_extras, executable_target_pattern, spec):
+  """Limit targets for Xcode wrapper.
+
+  Xcode sometimes performs poorly with too many targets, so only include
+  proper executable targets, with filters to customize.
+  Arguments:
+    target_extras: Regular expression to always add, matching any target.
+    executable_target_pattern: Regular expression limiting executable targets.
+    spec: Specifications for target.
+  """
+  target_name = spec.get('target_name')
+  # Always include targets matching target_extras.
+  if target_extras is not None and re.search(target_extras, target_name):
+    return True
+
+  # Otherwise just show executable targets.
+  if spec.get('type', '') == 'executable' and \
+     spec.get('product_extension', '') != 'bundle':
+
+    # If there is a filter and the target does not match, exclude the target.
+    if executable_target_pattern is not None:
+      if not re.search(executable_target_pattern, target_name):
+        return False
+    return True
+  return False
+
+def CreateWrapper(target_list, target_dicts, data, params):
+  """Initialize targets for the ninja wrapper.
+
+  This sets up the necessary variables in the targets to generate Xcode projects
+  that use ninja as an external builder.
+  Arguments:
+    target_list: List of target pairs: 'base/base.gyp:base'.
+    target_dicts: Dict of target properties keyed on target pair.
+    data: Dict of flattened build files keyed on gyp path.
+    params: Dict of global options for gyp.
+  """
+  orig_gyp = params['build_files'][0]
+  for gyp_name, gyp_dict in data.iteritems():
+    if gyp_name == orig_gyp:
+      depth = gyp_dict['_DEPTH']
+
+  # Check for custom main gyp name, otherwise use the default CHROMIUM_GYP_FILE
+  # and prepend .ninja before the .gyp extension.
+  generator_flags = params.get('generator_flags', {})
+  main_gyp = generator_flags.get('xcode_ninja_main_gyp', None)
+  if main_gyp is None:
+    (build_file_root, build_file_ext) = os.path.splitext(orig_gyp)
+    main_gyp = build_file_root + ".ninja" + build_file_ext
+
+  # Create new |target_list|, |target_dicts| and |data| data structures.
+  new_target_list = []
+  new_target_dicts = {}
+  new_data = {}
+
+  # Set base keys needed for |data|.
+  new_data[main_gyp] = {}
+  new_data[main_gyp]['included_files'] = []
+  new_data[main_gyp]['targets'] = []
+  new_data[main_gyp]['xcode_settings'] = \
+      data[orig_gyp].get('xcode_settings', {})
+
+  # Normally the xcode-ninja generator includes only valid executable targets.
+  # If |xcode_ninja_executable_target_pattern| is set, that list is reduced to
+  # executable targets that match the pattern. (Default all)
+  executable_target_pattern = \
+      generator_flags.get('xcode_ninja_executable_target_pattern', None)
+
+  # For including other non-executable targets, add the matching target name
+  # to the |xcode_ninja_target_pattern| regular expression. (Default none)
+  target_extras = generator_flags.get('xcode_ninja_target_pattern', None)
+
+  for old_qualified_target in target_list:
+    spec = target_dicts[old_qualified_target]
+    if IsValidTargetForWrapper(target_extras, executable_target_pattern, spec):
+      # Add to new_target_list.
+      target_name = spec.get('target_name')
+      new_target_name = '%s:%s#target' % (main_gyp, target_name)
+      new_target_list.append(new_target_name)
+
+      # Add to new_target_dicts.
+      new_target_dicts[new_target_name] = _TargetFromSpec(spec, params)
+
+      # Add to new_data.
+      for old_target in data[old_qualified_target.split(':')[0]]['targets']:
+        if old_target['target_name'] == target_name:
+          new_data_target = {}
+          new_data_target['target_name'] = old_target['target_name']
+          new_data_target['toolset'] = old_target['toolset']
+          new_data[main_gyp]['targets'].append(new_data_target)
+
+  # Create sources target.
+  sources_target_name = 'sources_for_indexing'
+  sources_target = _TargetFromSpec(
+    { 'target_name' : sources_target_name,
+      'toolset': 'target',
+      'default_configuration': 'Default',
+      'mac_bundle': '0',
+      'type': 'executable'
+    }, None)
+
+  # Tell Xcode to look everywhere for headers.
+  sources_target['configurations'] = {'Default': { 'include_dirs': [ depth ] } }
+
+  sources = []
+  for target, target_dict in target_dicts.iteritems():
+    base =  os.path.dirname(target)
+    files = target_dict.get('sources', []) + \
+            target_dict.get('mac_bundle_resources', [])
+    # Remove files starting with $. These are mostly intermediate files for the
+    # build system.
+    files = [ file for file in files if not file.startswith('$')]
+
+    # Make sources relative to root build file.
+    relative_path = os.path.dirname(main_gyp)
+    sources += [ os.path.relpath(os.path.join(base, file), relative_path)
+                    for file in files ]
+
+  sources_target['sources'] = sorted(set(sources))
+
+  # Put sources_to_index in it's own gyp.
+  sources_gyp = \
+      os.path.join(os.path.dirname(main_gyp), sources_target_name + ".gyp")
+  fully_qualified_target_name = \
+      '%s:%s#target' % (sources_gyp, sources_target_name)
+
+  # Add to new_target_list, new_target_dicts and new_data.
+  new_target_list.append(fully_qualified_target_name)
+  new_target_dicts[fully_qualified_target_name] = sources_target
+  new_data_target = {}
+  new_data_target['target_name'] = sources_target['target_name']
+  new_data_target['_DEPTH'] = depth
+  new_data_target['toolset'] = "target"
+  new_data[sources_gyp] = {}
+  new_data[sources_gyp]['targets'] = []
+  new_data[sources_gyp]['included_files'] = []
+  new_data[sources_gyp]['xcode_settings'] = \
+      data[orig_gyp].get('xcode_settings', {})
+  new_data[sources_gyp]['targets'].append(new_data_target)
+
+  # Write workspace to file.
+  _WriteWorkspace(main_gyp, sources_gyp)
+  return (new_target_list, new_target_dicts, new_data)
diff --git a/gyp/pylib/gyp/xcodeproj_file.py b/gyp/pylib/gyp/xcodeproj_file.py
new file mode 100644 (file)
index 0000000..7c7f1fb
--- /dev/null
@@ -0,0 +1,2892 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Xcode project file generator.
+
+This module is both an Xcode project file generator and a documentation of the
+Xcode project file format.  Knowledge of the project file format was gained
+based on extensive experience with Xcode, and by making changes to projects in
+Xcode.app and observing the resultant changes in the associated project files.
+
+XCODE PROJECT FILES
+
+The generator targets the file format as written by Xcode 3.2 (specifically,
+3.2.6), but past experience has taught that the format has not changed
+significantly in the past several years, and future versions of Xcode are able
+to read older project files.
+
+Xcode project files are "bundled": the project "file" from an end-user's
+perspective is actually a directory with an ".xcodeproj" extension.  The
+project file from this module's perspective is actually a file inside this
+directory, always named "project.pbxproj".  This file contains a complete
+description of the project and is all that is needed to use the xcodeproj.
+Other files contained in the xcodeproj directory are simply used to store
+per-user settings, such as the state of various UI elements in the Xcode
+application.
+
+The project.pbxproj file is a property list, stored in a format almost
+identical to the NeXTstep property list format.  The file is able to carry
+Unicode data, and is encoded in UTF-8.  The root element in the property list
+is a dictionary that contains several properties of minimal interest, and two
+properties of immense interest.  The most important property is a dictionary
+named "objects".  The entire structure of the project is represented by the
+children of this property.  The objects dictionary is keyed by unique 96-bit
+values represented by 24 uppercase hexadecimal characters.  Each value in the
+objects dictionary is itself a dictionary, describing an individual object.
+
+Each object in the dictionary is a member of a class, which is identified by
+the "isa" property of each object.  A variety of classes are represented in a
+project file.  Objects can refer to other objects by ID, using the 24-character
+hexadecimal object key.  A project's objects form a tree, with a root object
+of class PBXProject at the root.  As an example, the PBXProject object serves
+as parent to an XCConfigurationList object defining the build configurations
+used in the project, a PBXGroup object serving as a container for all files
+referenced in the project, and a list of target objects, each of which defines
+a target in the project.  There are several different types of target object,
+such as PBXNativeTarget and PBXAggregateTarget.  In this module, this
+relationship is expressed by having each target type derive from an abstract
+base named XCTarget.
+
+The project.pbxproj file's root dictionary also contains a property, sibling to
+the "objects" dictionary, named "rootObject".  The value of rootObject is a
+24-character object key referring to the root PBXProject object in the
+objects dictionary.
+
+In Xcode, every file used as input to a target or produced as a final product
+of a target must appear somewhere in the hierarchy rooted at the PBXGroup
+object referenced by the PBXProject's mainGroup property.  A PBXGroup is
+generally represented as a folder in the Xcode application.  PBXGroups can
+contain other PBXGroups as well as PBXFileReferences, which are pointers to
+actual files.
+
+Each XCTarget contains a list of build phases, represented in this module by
+the abstract base XCBuildPhase.  Examples of concrete XCBuildPhase derivations
+are PBXSourcesBuildPhase and PBXFrameworksBuildPhase, which correspond to the
+"Compile Sources" and "Link Binary With Libraries" phases displayed in the
+Xcode application.  Files used as input to these phases (for example, source
+files in the former case and libraries and frameworks in the latter) are
+represented by PBXBuildFile objects, referenced by elements of "files" lists
+in XCTarget objects.  Each PBXBuildFile object refers to a PBXBuildFile
+object as a "weak" reference: it does not "own" the PBXBuildFile, which is
+owned by the root object's mainGroup or a descendant group.  In most cases, the
+layer of indirection between an XCBuildPhase and a PBXFileReference via a
+PBXBuildFile appears extraneous, but there's actually one reason for this:
+file-specific compiler flags are added to the PBXBuildFile object so as to
+allow a single file to be a member of multiple targets while having distinct
+compiler flags for each.  These flags can be modified in the Xcode applciation
+in the "Build" tab of a File Info window.
+
+When a project is open in the Xcode application, Xcode will rewrite it.  As
+such, this module is careful to adhere to the formatting used by Xcode, to
+avoid insignificant changes appearing in the file when it is used in the
+Xcode application.  This will keep version control repositories happy, and
+makes it possible to compare a project file used in Xcode to one generated by
+this module to determine if any significant changes were made in the
+application.
+
+Xcode has its own way of assigning 24-character identifiers to each object,
+which is not duplicated here.  Because the identifier only is only generated
+once, when an object is created, and is then left unchanged, there is no need
+to attempt to duplicate Xcode's behavior in this area.  The generator is free
+to select any identifier, even at random, to refer to the objects it creates,
+and Xcode will retain those identifiers and use them when subsequently
+rewriting the project file.  However, the generator would choose new random
+identifiers each time the project files are generated, leading to difficulties
+comparing "used" project files to "pristine" ones produced by this module,
+and causing the appearance of changes as every object identifier is changed
+when updated projects are checked in to a version control repository.  To
+mitigate this problem, this module chooses identifiers in a more deterministic
+way, by hashing a description of each object as well as its parent and ancestor
+objects.  This strategy should result in minimal "shift" in IDs as successive
+generations of project files are produced.
+
+THIS MODULE
+
+This module introduces several classes, all derived from the XCObject class.
+Nearly all of the "brains" are built into the XCObject class, which understands
+how to create and modify objects, maintain the proper tree structure, compute
+identifiers, and print objects.  For the most part, classes derived from
+XCObject need only provide a _schema class object, a dictionary that
+expresses what properties objects of the class may contain.
+
+Given this structure, it's possible to build a minimal project file by creating
+objects of the appropriate types and making the proper connections:
+
+  config_list = XCConfigurationList()
+  group = PBXGroup()
+  project = PBXProject({'buildConfigurationList': config_list,
+                        'mainGroup': group})
+
+With the project object set up, it can be added to an XCProjectFile object.
+XCProjectFile is a pseudo-class in the sense that it is a concrete XCObject
+subclass that does not actually correspond to a class type found in a project
+file.  Rather, it is used to represent the project file's root dictionary.
+Printing an XCProjectFile will print the entire project file, including the
+full "objects" dictionary.
+
+  project_file = XCProjectFile({'rootObject': project})
+  project_file.ComputeIDs()
+  project_file.Print()
+
+Xcode project files are always encoded in UTF-8.  This module will accept
+strings of either the str class or the unicode class.  Strings of class str
+are assumed to already be encoded in UTF-8.  Obviously, if you're just using
+ASCII, you won't encounter difficulties because ASCII is a UTF-8 subset.
+Strings of class unicode are handled properly and encoded in UTF-8 when
+a project file is output.
+"""
+
+import gyp.common
+import posixpath
+import re
+import struct
+import sys
+
+# hashlib is supplied as of Python 2.5 as the replacement interface for sha
+# and other secure hashes.  In 2.6, sha is deprecated.  Import hashlib if
+# available, avoiding a deprecation warning under 2.6.  Import sha otherwise,
+# preserving 2.4 compatibility.
+try:
+  import hashlib
+  _new_sha1 = hashlib.sha1
+except ImportError:
+  import sha
+  _new_sha1 = sha.new
+
+
+# See XCObject._EncodeString.  This pattern is used to determine when a string
+# can be printed unquoted.  Strings that match this pattern may be printed
+# unquoted.  Strings that do not match must be quoted and may be further
+# transformed to be properly encoded.  Note that this expression matches the
+# characters listed with "+", for 1 or more occurrences: if a string is empty,
+# it must not match this pattern, because it needs to be encoded as "".
+_unquoted = re.compile('^[A-Za-z0-9$./_]+$')
+
+# Strings that match this pattern are quoted regardless of what _unquoted says.
+# Oddly, Xcode will quote any string with a run of three or more underscores.
+_quoted = re.compile('___')
+
+# This pattern should match any character that needs to be escaped by
+# XCObject._EncodeString.  See that function.
+_escaped = re.compile('[\\\\"]|[\x00-\x1f]')
+
+
+# Used by SourceTreeAndPathFromPath
+_path_leading_variable = re.compile('^\$\((.*?)\)(/(.*))?$')
+
+def SourceTreeAndPathFromPath(input_path):
+  """Given input_path, returns a tuple with sourceTree and path values.
+
+  Examples:
+    input_path     (source_tree, output_path)
+    '$(VAR)/path'  ('VAR', 'path')
+    '$(VAR)'       ('VAR', None)
+    'path'         (None, 'path')
+  """
+
+  source_group_match = _path_leading_variable.match(input_path)
+  if source_group_match:
+    source_tree = source_group_match.group(1)
+    output_path = source_group_match.group(3)  # This may be None.
+  else:
+    source_tree = None
+    output_path = input_path
+
+  return (source_tree, output_path)
+
+def ConvertVariablesToShellSyntax(input_string):
+  return re.sub('\$\((.*?)\)', '${\\1}', input_string)
+
+class XCObject(object):
+  """The abstract base of all class types used in Xcode project files.
+
+  Class variables:
+    _schema: A dictionary defining the properties of this class.  The keys to
+             _schema are string property keys as used in project files.  Values
+             are a list of four or five elements:
+             [ is_list, property_type, is_strong, is_required, default ]
+             is_list: True if the property described is a list, as opposed
+                      to a single element.
+             property_type: The type to use as the value of the property,
+                            or if is_list is True, the type to use for each
+                            element of the value's list.  property_type must
+                            be an XCObject subclass, or one of the built-in
+                            types str, int, or dict.
+             is_strong: If property_type is an XCObject subclass, is_strong
+                        is True to assert that this class "owns," or serves
+                        as parent, to the property value (or, if is_list is
+                        True, values).  is_strong must be False if
+                        property_type is not an XCObject subclass.
+             is_required: True if the property is required for the class.
+                          Note that is_required being True does not preclude
+                          an empty string ("", in the case of property_type
+                          str) or list ([], in the case of is_list True) from
+                          being set for the property.
+             default: Optional.  If is_requried is True, default may be set
+                      to provide a default value for objects that do not supply
+                      their own value.  If is_required is True and default
+                      is not provided, users of the class must supply their own
+                      value for the property.
+             Note that although the values of the array are expressed in
+             boolean terms, subclasses provide values as integers to conserve
+             horizontal space.
+    _should_print_single_line: False in XCObject.  Subclasses whose objects
+                               should be written to the project file in the
+                               alternate single-line format, such as
+                               PBXFileReference and PBXBuildFile, should
+                               set this to True.
+    _encode_transforms: Used by _EncodeString to encode unprintable characters.
+                        The index into this list is the ordinal of the
+                        character to transform; each value is a string
+                        used to represent the character in the output.  XCObject
+                        provides an _encode_transforms list suitable for most
+                        XCObject subclasses.
+    _alternate_encode_transforms: Provided for subclasses that wish to use
+                                  the alternate encoding rules.  Xcode seems
+                                  to use these rules when printing objects in
+                                  single-line format.  Subclasses that desire
+                                  this behavior should set _encode_transforms
+                                  to _alternate_encode_transforms.
+    _hashables: A list of XCObject subclasses that can be hashed by ComputeIDs
+                to construct this object's ID.  Most classes that need custom
+                hashing behavior should do it by overriding Hashables,
+                but in some cases an object's parent may wish to push a
+                hashable value into its child, and it can do so by appending
+                to _hashables.
+  Attributes:
+    id: The object's identifier, a 24-character uppercase hexadecimal string.
+        Usually, objects being created should not set id until the entire
+        project file structure is built.  At that point, UpdateIDs() should
+        be called on the root object to assign deterministic values for id to
+        each object in the tree.
+    parent: The object's parent.  This is set by a parent XCObject when a child
+            object is added to it.
+    _properties: The object's property dictionary.  An object's properties are
+                 described by its class' _schema variable.
+  """
+
+  _schema = {}
+  _should_print_single_line = False
+
+  # See _EncodeString.
+  _encode_transforms = []
+  i = 0
+  while i < ord(' '):
+    _encode_transforms.append('\\U%04x' % i)
+    i = i + 1
+  _encode_transforms[7] = '\\a'
+  _encode_transforms[8] = '\\b'
+  _encode_transforms[9] = '\\t'
+  _encode_transforms[10] = '\\n'
+  _encode_transforms[11] = '\\v'
+  _encode_transforms[12] = '\\f'
+  _encode_transforms[13] = '\\n'
+
+  _alternate_encode_transforms = list(_encode_transforms)
+  _alternate_encode_transforms[9] = chr(9)
+  _alternate_encode_transforms[10] = chr(10)
+  _alternate_encode_transforms[11] = chr(11)
+
+  def __init__(self, properties=None, id=None, parent=None):
+    self.id = id
+    self.parent = parent
+    self._properties = {}
+    self._hashables = []
+    self._SetDefaultsFromSchema()
+    self.UpdateProperties(properties)
+
+  def __repr__(self):
+    try:
+      name = self.Name()
+    except NotImplementedError:
+      return '<%s at 0x%x>' % (self.__class__.__name__, id(self))
+    return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self))
+
+  def Copy(self):
+    """Make a copy of this object.
+
+    The new object will have its own copy of lists and dicts.  Any XCObject
+    objects owned by this object (marked "strong") will be copied in the
+    new object, even those found in lists.  If this object has any weak
+    references to other XCObjects, the same references are added to the new
+    object without making a copy.
+    """
+
+    that = self.__class__(id=self.id, parent=self.parent)
+    for key, value in self._properties.iteritems():
+      is_strong = self._schema[key][2]
+
+      if isinstance(value, XCObject):
+        if is_strong:
+          new_value = value.Copy()
+          new_value.parent = that
+          that._properties[key] = new_value
+        else:
+          that._properties[key] = value
+      elif isinstance(value, str) or isinstance(value, unicode) or \
+           isinstance(value, int):
+        that._properties[key] = value
+      elif isinstance(value, list):
+        if is_strong:
+          # If is_strong is True, each element is an XCObject, so it's safe to
+          # call Copy.
+          that._properties[key] = []
+          for item in value:
+            new_item = item.Copy()
+            new_item.parent = that
+            that._properties[key].append(new_item)
+        else:
+          that._properties[key] = value[:]
+      elif isinstance(value, dict):
+        # dicts are never strong.
+        if is_strong:
+          raise TypeError, 'Strong dict for key ' + key + ' in ' + \
+                           self.__class__.__name__
+        else:
+          that._properties[key] = value.copy()
+      else:
+        raise TypeError, 'Unexpected type ' + value.__class__.__name__ + \
+                         ' for key ' + key + ' in ' + self.__class__.__name__
+
+    return that
+
+  def Name(self):
+    """Return the name corresponding to an object.
+
+    Not all objects necessarily need to be nameable, and not all that do have
+    a "name" property.  Override as needed.
+    """
+
+    # If the schema indicates that "name" is required, try to access the
+    # property even if it doesn't exist.  This will result in a KeyError
+    # being raised for the property that should be present, which seems more
+    # appropriate than NotImplementedError in this case.
+    if 'name' in self._properties or \
+        ('name' in self._schema and self._schema['name'][3]):
+      return self._properties['name']
+
+    raise NotImplementedError, \
+          self.__class__.__name__ + ' must implement Name'
+
+  def Comment(self):
+    """Return a comment string for the object.
+
+    Most objects just use their name as the comment, but PBXProject uses
+    different values.
+
+    The returned comment is not escaped and does not have any comment marker
+    strings applied to it.
+    """
+
+    return self.Name()
+
+  def Hashables(self):
+    hashables = [self.__class__.__name__]
+
+    name = self.Name()
+    if name != None:
+      hashables.append(name)
+
+    hashables.extend(self._hashables)
+
+    return hashables
+
+  def HashablesForChild(self):
+    return None
+
+  def ComputeIDs(self, recursive=True, overwrite=True, seed_hash=None):
+    """Set "id" properties deterministically.
+
+    An object's "id" property is set based on a hash of its class type and
+    name, as well as the class type and name of all ancestor objects.  As
+    such, it is only advisable to call ComputeIDs once an entire project file
+    tree is built.
+
+    If recursive is True, recurse into all descendant objects and update their
+    hashes.
+
+    If overwrite is True, any existing value set in the "id" property will be
+    replaced.
+    """
+
+    def _HashUpdate(hash, data):
+      """Update hash with data's length and contents.
+
+      If the hash were updated only with the value of data, it would be
+      possible for clowns to induce collisions by manipulating the names of
+      their objects.  By adding the length, it's exceedingly less likely that
+      ID collisions will be encountered, intentionally or not.
+      """
+
+      hash.update(struct.pack('>i', len(data)))
+      hash.update(data)
+
+    if seed_hash is None:
+      seed_hash = _new_sha1()
+
+    hash = seed_hash.copy()
+
+    hashables = self.Hashables()
+    assert len(hashables) > 0
+    for hashable in hashables:
+      _HashUpdate(hash, hashable)
+
+    if recursive:
+      hashables_for_child = self.HashablesForChild()
+      if hashables_for_child is None:
+        child_hash = hash
+      else:
+        assert len(hashables_for_child) > 0
+        child_hash = seed_hash.copy()
+        for hashable in hashables_for_child:
+          _HashUpdate(child_hash, hashable)
+
+      for child in self.Children():
+        child.ComputeIDs(recursive, overwrite, child_hash)
+
+    if overwrite or self.id is None:
+      # Xcode IDs are only 96 bits (24 hex characters), but a SHA-1 digest is
+      # is 160 bits.  Instead of throwing out 64 bits of the digest, xor them
+      # into the portion that gets used.
+      assert hash.digest_size % 4 == 0
+      digest_int_count = hash.digest_size / 4
+      digest_ints = struct.unpack('>' + 'I' * digest_int_count, hash.digest())
+      id_ints = [0, 0, 0]
+      for index in xrange(0, digest_int_count):
+        id_ints[index % 3] ^= digest_ints[index]
+      self.id = '%08X%08X%08X' % tuple(id_ints)
+
+  def EnsureNoIDCollisions(self):
+    """Verifies that no two objects have the same ID.  Checks all descendants.
+    """
+
+    ids = {}
+    descendants = self.Descendants()
+    for descendant in descendants:
+      if descendant.id in ids:
+        other = ids[descendant.id]
+        raise KeyError, \
+              'Duplicate ID %s, objects "%s" and "%s" in "%s"' % \
+              (descendant.id, str(descendant._properties),
+               str(other._properties), self._properties['rootObject'].Name())
+      ids[descendant.id] = descendant
+
+  def Children(self):
+    """Returns a list of all of this object's owned (strong) children."""
+
+    children = []
+    for property, attributes in self._schema.iteritems():
+      (is_list, property_type, is_strong) = attributes[0:3]
+      if is_strong and property in self._properties:
+        if not is_list:
+          children.append(self._properties[property])
+        else:
+          children.extend(self._properties[property])
+    return children
+
+  def Descendants(self):
+    """Returns a list of all of this object's descendants, including this
+    object.
+    """
+
+    children = self.Children()
+    descendants = [self]
+    for child in children:
+      descendants.extend(child.Descendants())
+    return descendants
+
+  def PBXProjectAncestor(self):
+    # The base case for recursion is defined at PBXProject.PBXProjectAncestor.
+    if self.parent:
+      return self.parent.PBXProjectAncestor()
+    return None
+
+  def _EncodeComment(self, comment):
+    """Encodes a comment to be placed in the project file output, mimicing
+    Xcode behavior.
+    """
+
+    # This mimics Xcode behavior by wrapping the comment in "/*" and "*/".  If
+    # the string already contains a "*/", it is turned into "(*)/".  This keeps
+    # the file writer from outputting something that would be treated as the
+    # end of a comment in the middle of something intended to be entirely a
+    # comment.
+
+    return '/* ' + comment.replace('*/', '(*)/') + ' */'
+
+  def _EncodeTransform(self, match):
+    # This function works closely with _EncodeString.  It will only be called
+    # by re.sub with match.group(0) containing a character matched by the
+    # the _escaped expression.
+    char = match.group(0)
+
+    # Backslashes (\) and quotation marks (") are always replaced with a
+    # backslash-escaped version of the same.  Everything else gets its
+    # replacement from the class' _encode_transforms array.
+    if char == '\\':
+      return '\\\\'
+    if char == '"':
+      return '\\"'
+    return self._encode_transforms[ord(char)]
+
+  def _EncodeString(self, value):
+    """Encodes a string to be placed in the project file output, mimicing
+    Xcode behavior.
+    """
+
+    # Use quotation marks when any character outside of the range A-Z, a-z, 0-9,
+    # $ (dollar sign), . (period), and _ (underscore) is present.  Also use
+    # quotation marks to represent empty strings.
+    #
+    # Escape " (double-quote) and \ (backslash) by preceding them with a
+    # backslash.
+    #
+    # Some characters below the printable ASCII range are encoded specially:
+    #     7 ^G BEL is encoded as "\a"
+    #     8 ^H BS  is encoded as "\b"
+    #    11 ^K VT  is encoded as "\v"
+    #    12 ^L NP  is encoded as "\f"
+    #   127 ^? DEL is passed through as-is without escaping
+    #  - In PBXFileReference and PBXBuildFile objects:
+    #     9 ^I HT  is passed through as-is without escaping
+    #    10 ^J NL  is passed through as-is without escaping
+    #    13 ^M CR  is passed through as-is without escaping
+    #  - In other objects:
+    #     9 ^I HT  is encoded as "\t"
+    #    10 ^J NL  is encoded as "\n"
+    #    13 ^M CR  is encoded as "\n" rendering it indistinguishable from
+    #              10 ^J NL
+    # All other characters within the ASCII control character range (0 through
+    # 31 inclusive) are encoded as "\U001f" referring to the Unicode code point
+    # in hexadecimal.  For example, character 14 (^N SO) is encoded as "\U000e".
+    # Characters above the ASCII range are passed through to the output encoded
+    # as UTF-8 without any escaping.  These mappings are contained in the
+    # class' _encode_transforms list.
+
+    if _unquoted.search(value) and not _quoted.search(value):
+      return value
+
+    return '"' + _escaped.sub(self._EncodeTransform, value) + '"'
+
+  def _XCPrint(self, file, tabs, line):
+    file.write('\t' * tabs + line)
+
+  def _XCPrintableValue(self, tabs, value, flatten_list=False):
+    """Returns a representation of value that may be printed in a project file,
+    mimicing Xcode's behavior.
+
+    _XCPrintableValue can handle str and int values, XCObjects (which are
+    made printable by returning their id property), and list and dict objects
+    composed of any of the above types.  When printing a list or dict, and
+    _should_print_single_line is False, the tabs parameter is used to determine
+    how much to indent the lines corresponding to the items in the list or
+    dict.
+
+    If flatten_list is True, single-element lists will be transformed into
+    strings.
+    """
+
+    printable = ''
+    comment = None
+
+    if self._should_print_single_line:
+      sep = ' '
+      element_tabs = ''
+      end_tabs = ''
+    else:
+      sep = '\n'
+      element_tabs = '\t' * (tabs + 1)
+      end_tabs = '\t' * tabs
+
+    if isinstance(value, XCObject):
+      printable += value.id
+      comment = value.Comment()
+    elif isinstance(value, str):
+      printable += self._EncodeString(value)
+    elif isinstance(value, unicode):
+      printable += self._EncodeString(value.encode('utf-8'))
+    elif isinstance(value, int):
+      printable += str(value)
+    elif isinstance(value, list):
+      if flatten_list and len(value) <= 1:
+        if len(value) == 0:
+          printable += self._EncodeString('')
+        else:
+          printable += self._EncodeString(value[0])
+      else:
+        printable = '(' + sep
+        for item in value:
+          printable += element_tabs + \
+                       self._XCPrintableValue(tabs + 1, item, flatten_list) + \
+                       ',' + sep
+        printable += end_tabs + ')'
+    elif isinstance(value, dict):
+      printable = '{' + sep
+      for item_key, item_value in sorted(value.iteritems()):
+        printable += element_tabs + \
+            self._XCPrintableValue(tabs + 1, item_key, flatten_list) + ' = ' + \
+            self._XCPrintableValue(tabs + 1, item_value, flatten_list) + ';' + \
+            sep
+      printable += end_tabs + '}'
+    else:
+      raise TypeError, "Can't make " + value.__class__.__name__ + ' printable'
+
+    if comment != None:
+      printable += ' ' + self._EncodeComment(comment)
+
+    return printable
+
+  def _XCKVPrint(self, file, tabs, key, value):
+    """Prints a key and value, members of an XCObject's _properties dictionary,
+    to file.
+
+    tabs is an int identifying the indentation level.  If the class'
+    _should_print_single_line variable is True, tabs is ignored and the
+    key-value pair will be followed by a space insead of a newline.
+    """
+
+    if self._should_print_single_line:
+      printable = ''
+      after_kv = ' '
+    else:
+      printable = '\t' * tabs
+      after_kv = '\n'
+
+    # Xcode usually prints remoteGlobalIDString values in PBXContainerItemProxy
+    # objects without comments.  Sometimes it prints them with comments, but
+    # the majority of the time, it doesn't.  To avoid unnecessary changes to
+    # the project file after Xcode opens it, don't write comments for
+    # remoteGlobalIDString.  This is a sucky hack and it would certainly be
+    # cleaner to extend the schema to indicate whether or not a comment should
+    # be printed, but since this is the only case where the problem occurs and
+    # Xcode itself can't seem to make up its mind, the hack will suffice.
+    #
+    # Also see PBXContainerItemProxy._schema['remoteGlobalIDString'].
+    if key == 'remoteGlobalIDString' and isinstance(self,
+                                                    PBXContainerItemProxy):
+      value_to_print = value.id
+    else:
+      value_to_print = value
+
+    # PBXBuildFile's settings property is represented in the output as a dict,
+    # but a hack here has it represented as a string. Arrange to strip off the
+    # quotes so that it shows up in the output as expected.
+    if key == 'settings' and isinstance(self, PBXBuildFile):
+      strip_value_quotes = True
+    else:
+      strip_value_quotes = False
+
+    # In another one-off, let's set flatten_list on buildSettings properties
+    # of XCBuildConfiguration objects, because that's how Xcode treats them.
+    if key == 'buildSettings' and isinstance(self, XCBuildConfiguration):
+      flatten_list = True
+    else:
+      flatten_list = False
+
+    try:
+      printable_key = self._XCPrintableValue(tabs, key, flatten_list)
+      printable_value = self._XCPrintableValue(tabs, value_to_print,
+                                               flatten_list)
+      if strip_value_quotes and len(printable_value) > 1 and \
+          printable_value[0] == '"' and printable_value[-1] == '"':
+        printable_value = printable_value[1:-1]
+      printable += printable_key + ' = ' + printable_value + ';' + after_kv
+    except TypeError, e:
+      gyp.common.ExceptionAppend(e,
+                                 'while printing key "%s"' % key)
+      raise
+
+    self._XCPrint(file, 0, printable)
+
+  def Print(self, file=sys.stdout):
+    """Prints a reprentation of this object to file, adhering to Xcode output
+    formatting.
+    """
+
+    self.VerifyHasRequiredProperties()
+
+    if self._should_print_single_line:
+      # When printing an object in a single line, Xcode doesn't put any space
+      # between the beginning of a dictionary (or presumably a list) and the
+      # first contained item, so you wind up with snippets like
+      #   ...CDEF = {isa = PBXFileReference; fileRef = 0123...
+      # If it were me, I would have put a space in there after the opening
+      # curly, but I guess this is just another one of those inconsistencies
+      # between how Xcode prints PBXFileReference and PBXBuildFile objects as
+      # compared to other objects.  Mimic Xcode's behavior here by using an
+      # empty string for sep.
+      sep = ''
+      end_tabs = 0
+    else:
+      sep = '\n'
+      end_tabs = 2
+
+    # Start the object.  For example, '\t\tPBXProject = {\n'.
+    self._XCPrint(file, 2, self._XCPrintableValue(2, self) + ' = {' + sep)
+
+    # "isa" isn't in the _properties dictionary, it's an intrinsic property
+    # of the class which the object belongs to.  Xcode always outputs "isa"
+    # as the first element of an object dictionary.
+    self._XCKVPrint(file, 3, 'isa', self.__class__.__name__)
+
+    # The remaining elements of an object dictionary are sorted alphabetically.
+    for property, value in sorted(self._properties.iteritems()):
+      self._XCKVPrint(file, 3, property, value)
+
+    # End the object.
+    self._XCPrint(file, end_tabs, '};\n')
+
+  def UpdateProperties(self, properties, do_copy=False):
+    """Merge the supplied properties into the _properties dictionary.
+
+    The input properties must adhere to the class schema or a KeyError or
+    TypeError exception will be raised.  If adding an object of an XCObject
+    subclass and the schema indicates a strong relationship, the object's
+    parent will be set to this object.
+
+    If do_copy is True, then lists, dicts, strong-owned XCObjects, and
+    strong-owned XCObjects in lists will be copied instead of having their
+    references added.
+    """
+
+    if properties is None:
+      return
+
+    for property, value in properties.iteritems():
+      # Make sure the property is in the schema.
+      if not property in self._schema:
+        raise KeyError, property + ' not in ' + self.__class__.__name__
+
+      # Make sure the property conforms to the schema.
+      (is_list, property_type, is_strong) = self._schema[property][0:3]
+      if is_list:
+        if value.__class__ != list:
+          raise TypeError, \
+                property + ' of ' + self.__class__.__name__ + \
+                ' must be list, not ' + value.__class__.__name__
+        for item in value:
+          if not isinstance(item, property_type) and \
+             not (item.__class__ == unicode and property_type == str):
+            # Accept unicode where str is specified.  str is treated as
+            # UTF-8-encoded.
+            raise TypeError, \
+                  'item of ' + property + ' of ' + self.__class__.__name__ + \
+                  ' must be ' + property_type.__name__ + ', not ' + \
+                  item.__class__.__name__
+      elif not isinstance(value, property_type) and \
+           not (value.__class__ == unicode and property_type == str):
+        # Accept unicode where str is specified.  str is treated as
+        # UTF-8-encoded.
+        raise TypeError, \
+              property + ' of ' + self.__class__.__name__ + ' must be ' + \
+              property_type.__name__ + ', not ' + value.__class__.__name__
+
+      # Checks passed, perform the assignment.
+      if do_copy:
+        if isinstance(value, XCObject):
+          if is_strong:
+            self._properties[property] = value.Copy()
+          else:
+            self._properties[property] = value
+        elif isinstance(value, str) or isinstance(value, unicode) or \
+             isinstance(value, int):
+          self._properties[property] = value
+        elif isinstance(value, list):
+          if is_strong:
+            # If is_strong is True, each element is an XCObject, so it's safe
+            # to call Copy.
+            self._properties[property] = []
+            for item in value:
+              self._properties[property].append(item.Copy())
+          else:
+            self._properties[property] = value[:]
+        elif isinstance(value, dict):
+          self._properties[property] = value.copy()
+        else:
+          raise TypeError, "Don't know how to copy a " + \
+                           value.__class__.__name__ + ' object for ' + \
+                           property + ' in ' + self.__class__.__name__
+      else:
+        self._properties[property] = value
+
+      # Set up the child's back-reference to this object.  Don't use |value|
+      # any more because it may not be right if do_copy is true.
+      if is_strong:
+        if not is_list:
+          self._properties[property].parent = self
+        else:
+          for item in self._properties[property]:
+            item.parent = self
+
+  def HasProperty(self, key):
+    return key in self._properties
+
+  def GetProperty(self, key):
+    return self._properties[key]
+
+  def SetProperty(self, key, value):
+    self.UpdateProperties({key: value})
+
+  def DelProperty(self, key):
+    if key in self._properties:
+      del self._properties[key]
+
+  def AppendProperty(self, key, value):
+    # TODO(mark): Support ExtendProperty too (and make this call that)?
+
+    # Schema validation.
+    if not key in self._schema:
+      raise KeyError, key + ' not in ' + self.__class__.__name__
+
+    (is_list, property_type, is_strong) = self._schema[key][0:3]
+    if not is_list:
+      raise TypeError, key + ' of ' + self.__class__.__name__ + ' must be list'
+    if not isinstance(value, property_type):
+      raise TypeError, 'item of ' + key + ' of ' + self.__class__.__name__ + \
+                       ' must be ' + property_type.__name__ + ', not ' + \
+                       value.__class__.__name__
+
+    # If the property doesn't exist yet, create a new empty list to receive the
+    # item.
+    if not key in self._properties:
+      self._properties[key] = []
+
+    # Set up the ownership link.
+    if is_strong:
+      value.parent = self
+
+    # Store the item.
+    self._properties[key].append(value)
+
+  def VerifyHasRequiredProperties(self):
+    """Ensure that all properties identified as required by the schema are
+    set.
+    """
+
+    # TODO(mark): A stronger verification mechanism is needed.  Some
+    # subclasses need to perform validation beyond what the schema can enforce.
+    for property, attributes in self._schema.iteritems():
+      (is_list, property_type, is_strong, is_required) = attributes[0:4]
+      if is_required and not property in self._properties:
+        raise KeyError, self.__class__.__name__ + ' requires ' + property
+
+  def _SetDefaultsFromSchema(self):
+    """Assign object default values according to the schema.  This will not
+    overwrite properties that have already been set."""
+
+    defaults = {}
+    for property, attributes in self._schema.iteritems():
+      (is_list, property_type, is_strong, is_required) = attributes[0:4]
+      if is_required and len(attributes) >= 5 and \
+          not property in self._properties:
+        default = attributes[4]
+
+        defaults[property] = default
+
+    if len(defaults) > 0:
+      # Use do_copy=True so that each new object gets its own copy of strong
+      # objects, lists, and dicts.
+      self.UpdateProperties(defaults, do_copy=True)
+
+
+class XCHierarchicalElement(XCObject):
+  """Abstract base for PBXGroup and PBXFileReference.  Not represented in a
+  project file."""
+
+  # TODO(mark): Do name and path belong here?  Probably so.
+  # If path is set and name is not, name may have a default value.  Name will
+  # be set to the basename of path, if the basename of path is different from
+  # the full value of path.  If path is already just a leaf name, name will
+  # not be set.
+  _schema = XCObject._schema.copy()
+  _schema.update({
+    'comments':       [0, str, 0, 0],
+    'fileEncoding':   [0, str, 0, 0],
+    'includeInIndex': [0, int, 0, 0],
+    'indentWidth':    [0, int, 0, 0],
+    'lineEnding':     [0, int, 0, 0],
+    'sourceTree':     [0, str, 0, 1, '<group>'],
+    'tabWidth':       [0, int, 0, 0],
+    'usesTabs':       [0, int, 0, 0],
+    'wrapsLines':     [0, int, 0, 0],
+  })
+
+  def __init__(self, properties=None, id=None, parent=None):
+    # super
+    XCObject.__init__(self, properties, id, parent)
+    if 'path' in self._properties and not 'name' in self._properties:
+      path = self._properties['path']
+      name = posixpath.basename(path)
+      if name != '' and path != name:
+        self.SetProperty('name', name)
+
+    if 'path' in self._properties and \
+        (not 'sourceTree' in self._properties or \
+         self._properties['sourceTree'] == '<group>'):
+      # If the pathname begins with an Xcode variable like "$(SDKROOT)/", take
+      # the variable out and make the path be relative to that variable by
+      # assigning the variable name as the sourceTree.
+      (source_tree, path) = SourceTreeAndPathFromPath(self._properties['path'])
+      if source_tree != None:
+        self._properties['sourceTree'] = source_tree
+      if path != None:
+        self._properties['path'] = path
+      if source_tree != None and path is None and \
+         not 'name' in self._properties:
+        # The path was of the form "$(SDKROOT)" with no path following it.
+        # This object is now relative to that variable, so it has no path
+        # attribute of its own.  It does, however, keep a name.
+        del self._properties['path']
+        self._properties['name'] = source_tree
+
+  def Name(self):
+    if 'name' in self._properties:
+      return self._properties['name']
+    elif 'path' in self._properties:
+      return self._properties['path']
+    else:
+      # This happens in the case of the root PBXGroup.
+      return None
+
+  def Hashables(self):
+    """Custom hashables for XCHierarchicalElements.
+
+    XCHierarchicalElements are special.  Generally, their hashes shouldn't
+    change if the paths don't change.  The normal XCObject implementation of
+    Hashables adds a hashable for each object, which means that if
+    the hierarchical structure changes (possibly due to changes caused when
+    TakeOverOnlyChild runs and encounters slight changes in the hierarchy),
+    the hashes will change.  For example, if a project file initially contains
+    a/b/f1 and a/b becomes collapsed into a/b, f1 will have a single parent
+    a/b.  If someone later adds a/f2 to the project file, a/b can no longer be
+    collapsed, and f1 winds up with parent b and grandparent a.  That would
+    be sufficient to change f1's hash.
+
+    To counteract this problem, hashables for all XCHierarchicalElements except
+    for the main group (which has neither a name nor a path) are taken to be
+    just the set of path components.  Because hashables are inherited from
+    parents, this provides assurance that a/b/f1 has the same set of hashables
+    whether its parent is b or a/b.
+
+    The main group is a special case.  As it is permitted to have no name or
+    path, it is permitted to use the standard XCObject hash mechanism.  This
+    is not considered a problem because there can be only one main group.
+    """
+
+    if self == self.PBXProjectAncestor()._properties['mainGroup']:
+      # super
+      return XCObject.Hashables(self)
+
+    hashables = []
+
+    # Put the name in first, ensuring that if TakeOverOnlyChild collapses
+    # children into a top-level group like "Source", the name always goes
+    # into the list of hashables without interfering with path components.
+    if 'name' in self._properties:
+      # Make it less likely for people to manipulate hashes by following the
+      # pattern of always pushing an object type value onto the list first.
+      hashables.append(self.__class__.__name__ + '.name')
+      hashables.append(self._properties['name'])
+
+    # NOTE: This still has the problem that if an absolute path is encountered,
+    # including paths with a sourceTree, they'll still inherit their parents'
+    # hashables, even though the paths aren't relative to their parents.  This
+    # is not expected to be much of a problem in practice.
+    path = self.PathFromSourceTreeAndPath()
+    if path != None:
+      components = path.split(posixpath.sep)
+      for component in components:
+        hashables.append(self.__class__.__name__ + '.path')
+        hashables.append(component)
+
+    hashables.extend(self._hashables)
+
+    return hashables
+
+  def Compare(self, other):
+    # Allow comparison of these types.  PBXGroup has the highest sort rank;
+    # PBXVariantGroup is treated as equal to PBXFileReference.
+    valid_class_types = {
+      PBXFileReference: 'file',
+      PBXGroup:         'group',
+      PBXVariantGroup:  'file',
+    }
+    self_type = valid_class_types[self.__class__]
+    other_type = valid_class_types[other.__class__]
+
+    if self_type == other_type:
+      # If the two objects are of the same sort rank, compare their names.
+      return cmp(self.Name(), other.Name())
+
+    # Otherwise, sort groups before everything else.
+    if self_type == 'group':
+      return -1
+    return 1
+
+  def CompareRootGroup(self, other):
+    # This function should be used only to compare direct children of the
+    # containing PBXProject's mainGroup.  These groups should appear in the
+    # listed order.
+    # TODO(mark): "Build" is used by gyp.generator.xcode, perhaps the
+    # generator should have a way of influencing this list rather than having
+    # to hardcode for the generator here.
+    order = ['Source', 'Intermediates', 'Projects', 'Frameworks', 'Products',
+             'Build']
+
+    # If the groups aren't in the listed order, do a name comparison.
+    # Otherwise, groups in the listed order should come before those that
+    # aren't.
+    self_name = self.Name()
+    other_name = other.Name()
+    self_in = isinstance(self, PBXGroup) and self_name in order
+    other_in = isinstance(self, PBXGroup) and other_name in order
+    if not self_in and not other_in:
+      return self.Compare(other)
+    if self_name in order and not other_name in order:
+      return -1
+    if other_name in order and not self_name in order:
+      return 1
+
+    # If both groups are in the listed order, go by the defined order.
+    self_index = order.index(self_name)
+    other_index = order.index(other_name)
+    if self_index < other_index:
+      return -1
+    if self_index > other_index:
+      return 1
+    return 0
+
+  def PathFromSourceTreeAndPath(self):
+    # Turn the object's sourceTree and path properties into a single flat
+    # string of a form comparable to the path parameter.  If there's a
+    # sourceTree property other than "<group>", wrap it in $(...) for the
+    # comparison.
+    components = []
+    if self._properties['sourceTree'] != '<group>':
+      components.append('$(' + self._properties['sourceTree'] + ')')
+    if 'path' in self._properties:
+      components.append(self._properties['path'])
+
+    if len(components) > 0:
+      return posixpath.join(*components)
+
+    return None
+
+  def FullPath(self):
+    # Returns a full path to self relative to the project file, or relative
+    # to some other source tree.  Start with self, and walk up the chain of
+    # parents prepending their paths, if any, until no more parents are
+    # available (project-relative path) or until a path relative to some
+    # source tree is found.
+    xche = self
+    path = None
+    while isinstance(xche, XCHierarchicalElement) and \
+          (path is None or \
+           (not path.startswith('/') and not path.startswith('$'))):
+      this_path = xche.PathFromSourceTreeAndPath()
+      if this_path != None and path != None:
+        path = posixpath.join(this_path, path)
+      elif this_path != None:
+        path = this_path
+      xche = xche.parent
+
+    return path
+
+
+class PBXGroup(XCHierarchicalElement):
+  """
+  Attributes:
+    _children_by_path: Maps pathnames of children of this PBXGroup to the
+      actual child XCHierarchicalElement objects.
+    _variant_children_by_name_and_path: Maps (name, path) tuples of
+      PBXVariantGroup children to the actual child PBXVariantGroup objects.
+  """
+
+  _schema = XCHierarchicalElement._schema.copy()
+  _schema.update({
+    'children': [1, XCHierarchicalElement, 1, 1, []],
+    'name':     [0, str,                   0, 0],
+    'path':     [0, str,                   0, 0],
+  })
+
+  def __init__(self, properties=None, id=None, parent=None):
+    # super
+    XCHierarchicalElement.__init__(self, properties, id, parent)
+    self._children_by_path = {}
+    self._variant_children_by_name_and_path = {}
+    for child in self._properties.get('children', []):
+      self._AddChildToDicts(child)
+
+  def Hashables(self):
+    # super
+    hashables = XCHierarchicalElement.Hashables(self)
+
+    # It is not sufficient to just rely on name and parent to build a unique
+    # hashable : a node could have two child PBXGroup sharing a common name.
+    # To add entropy the hashable is enhanced with the names of all its
+    # children.
+    for child in self._properties.get('children', []):
+      child_name = child.Name()
+      if child_name != None:
+        hashables.append(child_name)
+
+    return hashables
+
+  def HashablesForChild(self):
+    # To avoid a circular reference the hashables used to compute a child id do
+    # not include the child names.
+    return XCHierarchicalElement.Hashables(self)
+
+  def _AddChildToDicts(self, child):
+    # Sets up this PBXGroup object's dicts to reference the child properly.
+    child_path = child.PathFromSourceTreeAndPath()
+    if child_path:
+      if child_path in self._children_by_path:
+        raise ValueError, 'Found multiple children with path ' + child_path
+      self._children_by_path[child_path] = child
+
+    if isinstance(child, PBXVariantGroup):
+      child_name = child._properties.get('name', None)
+      key = (child_name, child_path)
+      if key in self._variant_children_by_name_and_path:
+        raise ValueError, 'Found multiple PBXVariantGroup children with ' + \
+                          'name ' + str(child_name) + ' and path ' + \
+                          str(child_path)
+      self._variant_children_by_name_and_path[key] = child
+
+  def AppendChild(self, child):
+    # Callers should use this instead of calling
+    # AppendProperty('children', child) directly because this function
+    # maintains the group's dicts.
+    self.AppendProperty('children', child)
+    self._AddChildToDicts(child)
+
+  def GetChildByName(self, name):
+    # This is not currently optimized with a dict as GetChildByPath is because
+    # it has few callers.  Most callers probably want GetChildByPath.  This
+    # function is only useful to get children that have names but no paths,
+    # which is rare.  The children of the main group ("Source", "Products",
+    # etc.) is pretty much the only case where this likely to come up.
+    #
+    # TODO(mark): Maybe this should raise an error if more than one child is
+    # present with the same name.
+    if not 'children' in self._properties:
+      return None
+
+    for child in self._properties['children']:
+      if child.Name() == name:
+        return child
+
+    return None
+
+  def GetChildByPath(self, path):
+    if not path:
+      return None
+
+    if path in self._children_by_path:
+      return self._children_by_path[path]
+
+    return None
+
+  def GetChildByRemoteObject(self, remote_object):
+    # This method is a little bit esoteric.  Given a remote_object, which
+    # should be a PBXFileReference in another project file, this method will
+    # return this group's PBXReferenceProxy object serving as a local proxy
+    # for the remote PBXFileReference.
+    #
+    # This function might benefit from a dict optimization as GetChildByPath
+    # for some workloads, but profiling shows that it's not currently a
+    # problem.
+    if not 'children' in self._properties:
+      return None
+
+    for child in self._properties['children']:
+      if not isinstance(child, PBXReferenceProxy):
+        continue
+
+      container_proxy = child._properties['remoteRef']
+      if container_proxy._properties['remoteGlobalIDString'] == remote_object:
+        return child
+
+    return None
+
+  def AddOrGetFileByPath(self, path, hierarchical):
+    """Returns an existing or new file reference corresponding to path.
+
+    If hierarchical is True, this method will create or use the necessary
+    hierarchical group structure corresponding to path.  Otherwise, it will
+    look in and create an item in the current group only.
+
+    If an existing matching reference is found, it is returned, otherwise, a
+    new one will be created, added to the correct group, and returned.
+
+    If path identifies a directory by virtue of carrying a trailing slash,
+    this method returns a PBXFileReference of "folder" type.  If path
+    identifies a variant, by virtue of it identifying a file inside a directory
+    with an ".lproj" extension, this method returns a PBXVariantGroup
+    containing the variant named by path, and possibly other variants.  For
+    all other paths, a "normal" PBXFileReference will be returned.
+    """
+
+    # Adding or getting a directory?  Directories end with a trailing slash.
+    is_dir = False
+    if path.endswith('/'):
+      is_dir = True
+    path = posixpath.normpath(path)
+    if is_dir:
+      path = path + '/'
+
+    # Adding or getting a variant?  Variants are files inside directories
+    # with an ".lproj" extension.  Xcode uses variants for localization.  For
+    # a variant path/to/Language.lproj/MainMenu.nib, put a variant group named
+    # MainMenu.nib inside path/to, and give it a variant named Language.  In
+    # this example, grandparent would be set to path/to and parent_root would
+    # be set to Language.
+    variant_name = None
+    parent = posixpath.dirname(path)
+    grandparent = posixpath.dirname(parent)
+    parent_basename = posixpath.basename(parent)
+    (parent_root, parent_ext) = posixpath.splitext(parent_basename)
+    if parent_ext == '.lproj':
+      variant_name = parent_root
+    if grandparent == '':
+      grandparent = None
+
+    # Putting a directory inside a variant group is not currently supported.
+    assert not is_dir or variant_name is None
+
+    path_split = path.split(posixpath.sep)
+    if len(path_split) == 1 or \
+       ((is_dir or variant_name != None) and len(path_split) == 2) or \
+       not hierarchical:
+      # The PBXFileReference or PBXVariantGroup will be added to or gotten from
+      # this PBXGroup, no recursion necessary.
+      if variant_name is None:
+        # Add or get a PBXFileReference.
+        file_ref = self.GetChildByPath(path)
+        if file_ref != None:
+          assert file_ref.__class__ == PBXFileReference
+        else:
+          file_ref = PBXFileReference({'path': path})
+          self.AppendChild(file_ref)
+      else:
+        # Add or get a PBXVariantGroup.  The variant group name is the same
+        # as the basename (MainMenu.nib in the example above).  grandparent
+        # specifies the path to the variant group itself, and path_split[-2:]
+        # is the path of the specific variant relative to its group.
+        variant_group_name = posixpath.basename(path)
+        variant_group_ref = self.AddOrGetVariantGroupByNameAndPath(
+            variant_group_name, grandparent)
+        variant_path = posixpath.sep.join(path_split[-2:])
+        variant_ref = variant_group_ref.GetChildByPath(variant_path)
+        if variant_ref != None:
+          assert variant_ref.__class__ == PBXFileReference
+        else:
+          variant_ref = PBXFileReference({'name': variant_name,
+                                          'path': variant_path})
+          variant_group_ref.AppendChild(variant_ref)
+        # The caller is interested in the variant group, not the specific
+        # variant file.
+        file_ref = variant_group_ref
+      return file_ref
+    else:
+      # Hierarchical recursion.  Add or get a PBXGroup corresponding to the
+      # outermost path component, and then recurse into it, chopping off that
+      # path component.
+      next_dir = path_split[0]
+      group_ref = self.GetChildByPath(next_dir)
+      if group_ref != None:
+        assert group_ref.__class__ == PBXGroup
+      else:
+        group_ref = PBXGroup({'path': next_dir})
+        self.AppendChild(group_ref)
+      return group_ref.AddOrGetFileByPath(posixpath.sep.join(path_split[1:]),
+                                          hierarchical)
+
+  def AddOrGetVariantGroupByNameAndPath(self, name, path):
+    """Returns an existing or new PBXVariantGroup for name and path.
+
+    If a PBXVariantGroup identified by the name and path arguments is already
+    present as a child of this object, it is returned.  Otherwise, a new
+    PBXVariantGroup with the correct properties is created, added as a child,
+    and returned.
+
+    This method will generally be called by AddOrGetFileByPath, which knows
+    when to create a variant group based on the structure of the pathnames
+    passed to it.
+    """
+
+    key = (name, path)
+    if key in self._variant_children_by_name_and_path:
+      variant_group_ref = self._variant_children_by_name_and_path[key]
+      assert variant_group_ref.__class__ == PBXVariantGroup
+      return variant_group_ref
+
+    variant_group_properties = {'name': name}
+    if path != None:
+      variant_group_properties['path'] = path
+    variant_group_ref = PBXVariantGroup(variant_group_properties)
+    self.AppendChild(variant_group_ref)
+
+    return variant_group_ref
+
+  def TakeOverOnlyChild(self, recurse=False):
+    """If this PBXGroup has only one child and it's also a PBXGroup, take
+    it over by making all of its children this object's children.
+
+    This function will continue to take over only children when those children
+    are groups.  If there are three PBXGroups representing a, b, and c, with
+    c inside b and b inside a, and a and b have no other children, this will
+    result in a taking over both b and c, forming a PBXGroup for a/b/c.
+
+    If recurse is True, this function will recurse into children and ask them
+    to collapse themselves by taking over only children as well.  Assuming
+    an example hierarchy with files at a/b/c/d1, a/b/c/d2, and a/b/c/d3/e/f
+    (d1, d2, and f are files, the rest are groups), recursion will result in
+    a group for a/b/c containing a group for d3/e.
+    """
+
+    # At this stage, check that child class types are PBXGroup exactly,
+    # instead of using isinstance.  The only subclass of PBXGroup,
+    # PBXVariantGroup, should not participate in reparenting in the same way:
+    # reparenting by merging different object types would be wrong.
+    while len(self._properties['children']) == 1 and \
+          self._properties['children'][0].__class__ == PBXGroup:
+      # Loop to take over the innermost only-child group possible.
+
+      child = self._properties['children'][0]
+
+      # Assume the child's properties, including its children.  Save a copy
+      # of this object's old properties, because they'll still be needed.
+      # This object retains its existing id and parent attributes.
+      old_properties = self._properties
+      self._properties = child._properties
+      self._children_by_path = child._children_by_path
+
+      if not 'sourceTree' in self._properties or \
+         self._properties['sourceTree'] == '<group>':
+        # The child was relative to its parent.  Fix up the path.  Note that
+        # children with a sourceTree other than "<group>" are not relative to
+        # their parents, so no path fix-up is needed in that case.
+        if 'path' in old_properties:
+          if 'path' in self._properties:
+            # Both the original parent and child have paths set.
+            self._properties['path'] = posixpath.join(old_properties['path'],
+                                                      self._properties['path'])
+          else:
+            # Only the original parent has a path, use it.
+            self._properties['path'] = old_properties['path']
+        if 'sourceTree' in old_properties:
+          # The original parent had a sourceTree set, use it.
+          self._properties['sourceTree'] = old_properties['sourceTree']
+
+      # If the original parent had a name set, keep using it.  If the original
+      # parent didn't have a name but the child did, let the child's name
+      # live on.  If the name attribute seems unnecessary now, get rid of it.
+      if 'name' in old_properties and old_properties['name'] != None and \
+         old_properties['name'] != self.Name():
+        self._properties['name'] = old_properties['name']
+      if 'name' in self._properties and 'path' in self._properties and \
+         self._properties['name'] == self._properties['path']:
+        del self._properties['name']
+
+      # Notify all children of their new parent.
+      for child in self._properties['children']:
+        child.parent = self
+
+    # If asked to recurse, recurse.
+    if recurse:
+      for child in self._properties['children']:
+        if child.__class__ == PBXGroup:
+          child.TakeOverOnlyChild(recurse)
+
+  def SortGroup(self):
+    self._properties['children'] = \
+        sorted(self._properties['children'], cmp=lambda x,y: x.Compare(y))
+
+    # Recurse.
+    for child in self._properties['children']:
+      if isinstance(child, PBXGroup):
+        child.SortGroup()
+
+
+class XCFileLikeElement(XCHierarchicalElement):
+  # Abstract base for objects that can be used as the fileRef property of
+  # PBXBuildFile.
+
+  def PathHashables(self):
+    # A PBXBuildFile that refers to this object will call this method to
+    # obtain additional hashables specific to this XCFileLikeElement.  Don't
+    # just use this object's hashables, they're not specific and unique enough
+    # on their own (without access to the parent hashables.)  Instead, provide
+    # hashables that identify this object by path by getting its hashables as
+    # well as the hashables of ancestor XCHierarchicalElement objects.
+
+    hashables = []
+    xche = self
+    while xche != None and isinstance(xche, XCHierarchicalElement):
+      xche_hashables = xche.Hashables()
+      for index in xrange(0, len(xche_hashables)):
+        hashables.insert(index, xche_hashables[index])
+      xche = xche.parent
+    return hashables
+
+
+class XCContainerPortal(XCObject):
+  # Abstract base for objects that can be used as the containerPortal property
+  # of PBXContainerItemProxy.
+  pass
+
+
+class XCRemoteObject(XCObject):
+  # Abstract base for objects that can be used as the remoteGlobalIDString
+  # property of PBXContainerItemProxy.
+  pass
+
+
+class PBXFileReference(XCFileLikeElement, XCContainerPortal, XCRemoteObject):
+  _schema = XCFileLikeElement._schema.copy()
+  _schema.update({
+    'explicitFileType':  [0, str, 0, 0],
+    'lastKnownFileType': [0, str, 0, 0],
+    'name':              [0, str, 0, 0],
+    'path':              [0, str, 0, 1],
+  })
+
+  # Weird output rules for PBXFileReference.
+  _should_print_single_line = True
+  # super
+  _encode_transforms = XCFileLikeElement._alternate_encode_transforms
+
+  def __init__(self, properties=None, id=None, parent=None):
+    # super
+    XCFileLikeElement.__init__(self, properties, id, parent)
+    if 'path' in self._properties and self._properties['path'].endswith('/'):
+      self._properties['path'] = self._properties['path'][:-1]
+      is_dir = True
+    else:
+      is_dir = False
+
+    if 'path' in self._properties and \
+        not 'lastKnownFileType' in self._properties and \
+        not 'explicitFileType' in self._properties:
+      # TODO(mark): This is the replacement for a replacement for a quick hack.
+      # It is no longer incredibly sucky, but this list needs to be extended.
+      extension_map = {
+        'a':           'archive.ar',
+        'app':         'wrapper.application',
+        'bdic':        'file',
+        'bundle':      'wrapper.cfbundle',
+        'c':           'sourcecode.c.c',
+        'cc':          'sourcecode.cpp.cpp',
+        'cpp':         'sourcecode.cpp.cpp',
+        'css':         'text.css',
+        'cxx':         'sourcecode.cpp.cpp',
+        'dart':        'sourcecode',
+        'dylib':       'compiled.mach-o.dylib',
+        'framework':   'wrapper.framework',
+        'gyp':         'sourcecode',
+        'gypi':        'sourcecode',
+        'h':           'sourcecode.c.h',
+        'hxx':         'sourcecode.cpp.h',
+        'icns':        'image.icns',
+        'java':        'sourcecode.java',
+        'js':          'sourcecode.javascript',
+        'm':           'sourcecode.c.objc',
+        'mm':          'sourcecode.cpp.objcpp',
+        'nib':         'wrapper.nib',
+        'o':           'compiled.mach-o.objfile',
+        'pdf':         'image.pdf',
+        'pl':          'text.script.perl',
+        'plist':       'text.plist.xml',
+        'pm':          'text.script.perl',
+        'png':         'image.png',
+        'py':          'text.script.python',
+        'r':           'sourcecode.rez',
+        'rez':         'sourcecode.rez',
+        's':           'sourcecode.asm',
+        'storyboard':  'file.storyboard',
+        'strings':     'text.plist.strings',
+        'ttf':         'file',
+        'xcassets':    'folder.assetcatalog',
+        'xcconfig':    'text.xcconfig',
+        'xcdatamodel': 'wrapper.xcdatamodel',
+        'xcdatamodeld':'wrapper.xcdatamodeld',
+        'xib':         'file.xib',
+        'y':           'sourcecode.yacc',
+      }
+
+      prop_map = {
+        'dart':        'explicitFileType',
+        'gyp':         'explicitFileType',
+        'gypi':        'explicitFileType',
+      }
+
+      if is_dir:
+        file_type = 'folder'
+        prop_name = 'lastKnownFileType'
+      else:
+        basename = posixpath.basename(self._properties['path'])
+        (root, ext) = posixpath.splitext(basename)
+        # Check the map using a lowercase extension.
+        # TODO(mark): Maybe it should try with the original case first and fall
+        # back to lowercase, in case there are any instances where case
+        # matters.  There currently aren't.
+        if ext != '':
+          ext = ext[1:].lower()
+
+        # TODO(mark): "text" is the default value, but "file" is appropriate
+        # for unrecognized files not containing text.  Xcode seems to choose
+        # based on content.
+        file_type = extension_map.get(ext, 'text')
+        prop_name = prop_map.get(ext, 'lastKnownFileType')
+
+      self._properties[prop_name] = file_type
+
+
+class PBXVariantGroup(PBXGroup, XCFileLikeElement):
+  """PBXVariantGroup is used by Xcode to represent localizations."""
+  # No additions to the schema relative to PBXGroup.
+  pass
+
+
+# PBXReferenceProxy is also an XCFileLikeElement subclass.  It is defined below
+# because it uses PBXContainerItemProxy, defined below.
+
+
+class XCBuildConfiguration(XCObject):
+  _schema = XCObject._schema.copy()
+  _schema.update({
+    'baseConfigurationReference': [0, PBXFileReference, 0, 0],
+    'buildSettings':              [0, dict, 0, 1, {}],
+    'name':                       [0, str,  0, 1],
+  })
+
+  def HasBuildSetting(self, key):
+    return key in self._properties['buildSettings']
+
+  def GetBuildSetting(self, key):
+    return self._properties['buildSettings'][key]
+
+  def SetBuildSetting(self, key, value):
+    # TODO(mark): If a list, copy?
+    self._properties['buildSettings'][key] = value
+
+  def AppendBuildSetting(self, key, value):
+    if not key in self._properties['buildSettings']:
+      self._properties['buildSettings'][key] = []
+    self._properties['buildSettings'][key].append(value)
+
+  def DelBuildSetting(self, key):
+    if key in self._properties['buildSettings']:
+      del self._properties['buildSettings'][key]
+
+  def SetBaseConfiguration(self, value):
+    self._properties['baseConfigurationReference'] = value
+
+class XCConfigurationList(XCObject):
+  # _configs is the default list of configurations.
+  _configs = [ XCBuildConfiguration({'name': 'Debug'}),
+               XCBuildConfiguration({'name': 'Release'}) ]
+
+  _schema = XCObject._schema.copy()
+  _schema.update({
+    'buildConfigurations':           [1, XCBuildConfiguration, 1, 1, _configs],
+    'defaultConfigurationIsVisible': [0, int,                  0, 1, 1],
+    'defaultConfigurationName':      [0, str,                  0, 1, 'Release'],
+  })
+
+  def Name(self):
+    return 'Build configuration list for ' + \
+           self.parent.__class__.__name__ + ' "' + self.parent.Name() + '"'
+
+  def ConfigurationNamed(self, name):
+    """Convenience accessor to obtain an XCBuildConfiguration by name."""
+    for configuration in self._properties['buildConfigurations']:
+      if configuration._properties['name'] == name:
+        return configuration
+
+    raise KeyError, name
+
+  def DefaultConfiguration(self):
+    """Convenience accessor to obtain the default XCBuildConfiguration."""
+    return self.ConfigurationNamed(self._properties['defaultConfigurationName'])
+
+  def HasBuildSetting(self, key):
+    """Determines the state of a build setting in all XCBuildConfiguration
+    child objects.
+
+    If all child objects have key in their build settings, and the value is the
+    same in all child objects, returns 1.
+
+    If no child objects have the key in their build settings, returns 0.
+
+    If some, but not all, child objects have the key in their build settings,
+    or if any children have different values for the key, returns -1.
+    """
+
+    has = None
+    value = None
+    for configuration in self._properties['buildConfigurations']:
+      configuration_has = configuration.HasBuildSetting(key)
+      if has is None:
+        has = configuration_has
+      elif has != configuration_has:
+        return -1
+
+      if configuration_has:
+        configuration_value = configuration.GetBuildSetting(key)
+        if value is None:
+          value = configuration_value
+        elif value != configuration_value:
+          return -1
+
+    if not has:
+      return 0
+
+    return 1
+
+  def GetBuildSetting(self, key):
+    """Gets the build setting for key.
+
+    All child XCConfiguration objects must have the same value set for the
+    setting, or a ValueError will be raised.
+    """
+
+    # TODO(mark): This is wrong for build settings that are lists.  The list
+    # contents should be compared (and a list copy returned?)
+
+    value = None
+    for configuration in self._properties['buildConfigurations']:
+      configuration_value = configuration.GetBuildSetting(key)
+      if value is None:
+        value = configuration_value
+      else:
+        if value != configuration_value:
+          raise ValueError, 'Variant values for ' + key
+
+    return value
+
+  def SetBuildSetting(self, key, value):
+    """Sets the build setting for key to value in all child
+    XCBuildConfiguration objects.
+    """
+
+    for configuration in self._properties['buildConfigurations']:
+      configuration.SetBuildSetting(key, value)
+
+  def AppendBuildSetting(self, key, value):
+    """Appends value to the build setting for key, which is treated as a list,
+    in all child XCBuildConfiguration objects.
+    """
+
+    for configuration in self._properties['buildConfigurations']:
+      configuration.AppendBuildSetting(key, value)
+
+  def DelBuildSetting(self, key):
+    """Deletes the build setting key from all child XCBuildConfiguration
+    objects.
+    """
+
+    for configuration in self._properties['buildConfigurations']:
+      configuration.DelBuildSetting(key)
+
+  def SetBaseConfiguration(self, value):
+    """Sets the build configuration in all child XCBuildConfiguration objects.
+    """
+
+    for configuration in self._properties['buildConfigurations']:
+      configuration.SetBaseConfiguration(value)
+
+
+class PBXBuildFile(XCObject):
+  _schema = XCObject._schema.copy()
+  _schema.update({
+    'fileRef':  [0, XCFileLikeElement, 0, 1],
+    'settings': [0, str,               0, 0],  # hack, it's a dict
+  })
+
+  # Weird output rules for PBXBuildFile.
+  _should_print_single_line = True
+  _encode_transforms = XCObject._alternate_encode_transforms
+
+  def Name(self):
+    # Example: "main.cc in Sources"
+    return self._properties['fileRef'].Name() + ' in ' + self.parent.Name()
+
+  def Hashables(self):
+    # super
+    hashables = XCObject.Hashables(self)
+
+    # It is not sufficient to just rely on Name() to get the
+    # XCFileLikeElement's name, because that is not a complete pathname.
+    # PathHashables returns hashables unique enough that no two
+    # PBXBuildFiles should wind up with the same set of hashables, unless
+    # someone adds the same file multiple times to the same target.  That
+    # would be considered invalid anyway.
+    hashables.extend(self._properties['fileRef'].PathHashables())
+
+    return hashables
+
+
+class XCBuildPhase(XCObject):
+  """Abstract base for build phase classes.  Not represented in a project
+  file.
+
+  Attributes:
+    _files_by_path: A dict mapping each path of a child in the files list by
+      path (keys) to the corresponding PBXBuildFile children (values).
+    _files_by_xcfilelikeelement: A dict mapping each XCFileLikeElement (keys)
+      to the corresponding PBXBuildFile children (values).
+  """
+
+  # TODO(mark): Some build phase types, like PBXShellScriptBuildPhase, don't
+  # actually have a "files" list.  XCBuildPhase should not have "files" but
+  # another abstract subclass of it should provide this, and concrete build
+  # phase types that do have "files" lists should be derived from that new
+  # abstract subclass.  XCBuildPhase should only provide buildActionMask and
+  # runOnlyForDeploymentPostprocessing, and not files or the various
+  # file-related methods and attributes.
+
+  _schema = XCObject._schema.copy()
+  _schema.update({
+    'buildActionMask':                    [0, int,          0, 1, 0x7fffffff],
+    'files':                              [1, PBXBuildFile, 1, 1, []],
+    'runOnlyForDeploymentPostprocessing': [0, int,          0, 1, 0],
+  })
+
+  def __init__(self, properties=None, id=None, parent=None):
+    # super
+    XCObject.__init__(self, properties, id, parent)
+
+    self._files_by_path = {}
+    self._files_by_xcfilelikeelement = {}
+    for pbxbuildfile in self._properties.get('files', []):
+      self._AddBuildFileToDicts(pbxbuildfile)
+
+  def FileGroup(self, path):
+    # Subclasses must override this by returning a two-element tuple.  The
+    # first item in the tuple should be the PBXGroup to which "path" should be
+    # added, either as a child or deeper descendant.  The second item should
+    # be a boolean indicating whether files should be added into hierarchical
+    # groups or one single flat group.
+    raise NotImplementedError, \
+          self.__class__.__name__ + ' must implement FileGroup'
+
+  def _AddPathToDict(self, pbxbuildfile, path):
+    """Adds path to the dict tracking paths belonging to this build phase.
+
+    If the path is already a member of this build phase, raises an exception.
+    """
+
+    if path in self._files_by_path:
+      raise ValueError, 'Found multiple build files with path ' + path
+    self._files_by_path[path] = pbxbuildfile
+
+  def _AddBuildFileToDicts(self, pbxbuildfile, path=None):
+    """Maintains the _files_by_path and _files_by_xcfilelikeelement dicts.
+
+    If path is specified, then it is the path that is being added to the
+    phase, and pbxbuildfile must contain either a PBXFileReference directly
+    referencing that path, or it must contain a PBXVariantGroup that itself
+    contains a PBXFileReference referencing the path.
+
+    If path is not specified, either the PBXFileReference's path or the paths
+    of all children of the PBXVariantGroup are taken as being added to the
+    phase.
+
+    If the path is already present in the phase, raises an exception.
+
+    If the PBXFileReference or PBXVariantGroup referenced by pbxbuildfile
+    are already present in the phase, referenced by a different PBXBuildFile
+    object, raises an exception.  This does not raise an exception when
+    a PBXFileReference or PBXVariantGroup reappear and are referenced by the
+    same PBXBuildFile that has already introduced them, because in the case
+    of PBXVariantGroup objects, they may correspond to multiple paths that are
+    not all added simultaneously.  When this situation occurs, the path needs
+    to be added to _files_by_path, but nothing needs to change in
+    _files_by_xcfilelikeelement, and the caller should have avoided adding
+    the PBXBuildFile if it is already present in the list of children.
+    """
+
+    xcfilelikeelement = pbxbuildfile._properties['fileRef']
+
+    paths = []
+    if path != None:
+      # It's best when the caller provides the path.
+      if isinstance(xcfilelikeelement, PBXVariantGroup):
+        paths.append(path)
+    else:
+      # If the caller didn't provide a path, there can be either multiple
+      # paths (PBXVariantGroup) or one.
+      if isinstance(xcfilelikeelement, PBXVariantGroup):
+        for variant in xcfilelikeelement._properties['children']:
+          paths.append(variant.FullPath())
+      else:
+        paths.append(xcfilelikeelement.FullPath())
+
+    # Add the paths first, because if something's going to raise, the
+    # messages provided by _AddPathToDict are more useful owing to its
+    # having access to a real pathname and not just an object's Name().
+    for a_path in paths:
+      self._AddPathToDict(pbxbuildfile, a_path)
+
+    # If another PBXBuildFile references this XCFileLikeElement, there's a
+    # problem.
+    if xcfilelikeelement in self._files_by_xcfilelikeelement and \
+       self._files_by_xcfilelikeelement[xcfilelikeelement] != pbxbuildfile:
+      raise ValueError, 'Found multiple build files for ' + \
+                        xcfilelikeelement.Name()
+    self._files_by_xcfilelikeelement[xcfilelikeelement] = pbxbuildfile
+
+  def AppendBuildFile(self, pbxbuildfile, path=None):
+    # Callers should use this instead of calling
+    # AppendProperty('files', pbxbuildfile) directly because this function
+    # maintains the object's dicts.  Better yet, callers can just call AddFile
+    # with a pathname and not worry about building their own PBXBuildFile
+    # objects.
+    self.AppendProperty('files', pbxbuildfile)
+    self._AddBuildFileToDicts(pbxbuildfile, path)
+
+  def AddFile(self, path, settings=None):
+    (file_group, hierarchical) = self.FileGroup(path)
+    file_ref = file_group.AddOrGetFileByPath(path, hierarchical)
+
+    if file_ref in self._files_by_xcfilelikeelement and \
+       isinstance(file_ref, PBXVariantGroup):
+      # There's already a PBXBuildFile in this phase corresponding to the
+      # PBXVariantGroup.  path just provides a new variant that belongs to
+      # the group.  Add the path to the dict.
+      pbxbuildfile = self._files_by_xcfilelikeelement[file_ref]
+      self._AddBuildFileToDicts(pbxbuildfile, path)
+    else:
+      # Add a new PBXBuildFile to get file_ref into the phase.
+      if settings is None:
+        pbxbuildfile = PBXBuildFile({'fileRef': file_ref})
+      else:
+        pbxbuildfile = PBXBuildFile({'fileRef': file_ref, 'settings': settings})
+      self.AppendBuildFile(pbxbuildfile, path)
+
+
+class PBXHeadersBuildPhase(XCBuildPhase):
+  # No additions to the schema relative to XCBuildPhase.
+
+  def Name(self):
+    return 'Headers'
+
+  def FileGroup(self, path):
+    return self.PBXProjectAncestor().RootGroupForPath(path)
+
+
+class PBXResourcesBuildPhase(XCBuildPhase):
+  # No additions to the schema relative to XCBuildPhase.
+
+  def Name(self):
+    return 'Resources'
+
+  def FileGroup(self, path):
+    return self.PBXProjectAncestor().RootGroupForPath(path)
+
+
+class PBXSourcesBuildPhase(XCBuildPhase):
+  # No additions to the schema relative to XCBuildPhase.
+
+  def Name(self):
+    return 'Sources'
+
+  def FileGroup(self, path):
+    return self.PBXProjectAncestor().RootGroupForPath(path)
+
+
+class PBXFrameworksBuildPhase(XCBuildPhase):
+  # No additions to the schema relative to XCBuildPhase.
+
+  def Name(self):
+    return 'Frameworks'
+
+  def FileGroup(self, path):
+    (root, ext) = posixpath.splitext(path)
+    if ext != '':
+      ext = ext[1:].lower()
+    if ext == 'o':
+      # .o files are added to Xcode Frameworks phases, but conceptually aren't
+      # frameworks, they're more like sources or intermediates. Redirect them
+      # to show up in one of those other groups.
+      return self.PBXProjectAncestor().RootGroupForPath(path)
+    else:
+      return (self.PBXProjectAncestor().FrameworksGroup(), False)
+
+
+class PBXShellScriptBuildPhase(XCBuildPhase):
+  _schema = XCBuildPhase._schema.copy()
+  _schema.update({
+    'inputPaths':       [1, str, 0, 1, []],
+    'name':             [0, str, 0, 0],
+    'outputPaths':      [1, str, 0, 1, []],
+    'shellPath':        [0, str, 0, 1, '/bin/sh'],
+    'shellScript':      [0, str, 0, 1],
+    'showEnvVarsInLog': [0, int, 0, 0],
+  })
+
+  def Name(self):
+    if 'name' in self._properties:
+      return self._properties['name']
+
+    return 'ShellScript'
+
+
+class PBXCopyFilesBuildPhase(XCBuildPhase):
+  _schema = XCBuildPhase._schema.copy()
+  _schema.update({
+    'dstPath':          [0, str, 0, 1],
+    'dstSubfolderSpec': [0, int, 0, 1],
+    'name':             [0, str, 0, 0],
+  })
+
+  # path_tree_re matches "$(DIR)/path" or just "$(DIR)".  Match group 1 is
+  # "DIR", match group 3 is "path" or None.
+  path_tree_re = re.compile('^\\$\\((.*)\\)(/(.*)|)$')
+
+  # path_tree_to_subfolder maps names of Xcode variables to the associated
+  # dstSubfolderSpec property value used in a PBXCopyFilesBuildPhase object.
+  path_tree_to_subfolder = {
+    'BUILT_PRODUCTS_DIR': 16,  # Products Directory
+    # Other types that can be chosen via the Xcode UI.
+    # TODO(mark): Map Xcode variable names to these.
+    # : 1,  # Wrapper
+    # : 6,  # Executables: 6
+    # : 7,  # Resources
+    # : 15,  # Java Resources
+    # : 10,  # Frameworks
+    # : 11,  # Shared Frameworks
+    # : 12,  # Shared Support
+    # : 13,  # PlugIns
+  }
+
+  def Name(self):
+    if 'name' in self._properties:
+      return self._properties['name']
+
+    return 'CopyFiles'
+
+  def FileGroup(self, path):
+    return self.PBXProjectAncestor().RootGroupForPath(path)
+
+  def SetDestination(self, path):
+    """Set the dstSubfolderSpec and dstPath properties from path.
+
+    path may be specified in the same notation used for XCHierarchicalElements,
+    specifically, "$(DIR)/path".
+    """
+
+    path_tree_match = self.path_tree_re.search(path)
+    if path_tree_match:
+      # Everything else needs to be relative to an Xcode variable.
+      path_tree = path_tree_match.group(1)
+      relative_path = path_tree_match.group(3)
+
+      if path_tree in self.path_tree_to_subfolder:
+        subfolder = self.path_tree_to_subfolder[path_tree]
+        if relative_path is None:
+          relative_path = ''
+      else:
+        # The path starts with an unrecognized Xcode variable
+        # name like $(SRCROOT).  Xcode will still handle this
+        # as an "absolute path" that starts with the variable.
+        subfolder = 0
+        relative_path = path
+    elif path.startswith('/'):
+      # Special case.  Absolute paths are in dstSubfolderSpec 0.
+      subfolder = 0
+      relative_path = path[1:]
+    else:
+      raise ValueError, 'Can\'t use path %s in a %s' % \
+                        (path, self.__class__.__name__)
+
+    self._properties['dstPath'] = relative_path
+    self._properties['dstSubfolderSpec'] = subfolder
+
+
+class PBXBuildRule(XCObject):
+  _schema = XCObject._schema.copy()
+  _schema.update({
+    'compilerSpec': [0, str, 0, 1],
+    'filePatterns': [0, str, 0, 0],
+    'fileType':     [0, str, 0, 1],
+    'isEditable':   [0, int, 0, 1, 1],
+    'outputFiles':  [1, str, 0, 1, []],
+    'script':       [0, str, 0, 0],
+  })
+
+  def Name(self):
+    # Not very inspired, but it's what Xcode uses.
+    return self.__class__.__name__
+
+  def Hashables(self):
+    # super
+    hashables = XCObject.Hashables(self)
+
+    # Use the hashables of the weak objects that this object refers to.
+    hashables.append(self._properties['fileType'])
+    if 'filePatterns' in self._properties:
+      hashables.append(self._properties['filePatterns'])
+    return hashables
+
+
+class PBXContainerItemProxy(XCObject):
+  # When referencing an item in this project file, containerPortal is the
+  # PBXProject root object of this project file.  When referencing an item in
+  # another project file, containerPortal is a PBXFileReference identifying
+  # the other project file.
+  #
+  # When serving as a proxy to an XCTarget (in this project file or another),
+  # proxyType is 1.  When serving as a proxy to a PBXFileReference (in another
+  # project file), proxyType is 2.  Type 2 is used for references to the
+  # producs of the other project file's targets.
+  #
+  # Xcode is weird about remoteGlobalIDString.  Usually, it's printed without
+  # a comment, indicating that it's tracked internally simply as a string, but
+  # sometimes it's printed with a comment (usually when the object is initially
+  # created), indicating that it's tracked as a project file object at least
+  # sometimes.  This module always tracks it as an object, but contains a hack
+  # to prevent it from printing the comment in the project file output.  See
+  # _XCKVPrint.
+  _schema = XCObject._schema.copy()
+  _schema.update({
+    'containerPortal':      [0, XCContainerPortal, 0, 1],
+    'proxyType':            [0, int,               0, 1],
+    'remoteGlobalIDString': [0, XCRemoteObject,    0, 1],
+    'remoteInfo':           [0, str,               0, 1],
+  })
+
+  def __repr__(self):
+    props = self._properties
+    name = '%s.gyp:%s' % (props['containerPortal'].Name(), props['remoteInfo'])
+    return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self))
+
+  def Name(self):
+    # Admittedly not the best name, but it's what Xcode uses.
+    return self.__class__.__name__
+
+  def Hashables(self):
+    # super
+    hashables = XCObject.Hashables(self)
+
+    # Use the hashables of the weak objects that this object refers to.
+    hashables.extend(self._properties['containerPortal'].Hashables())
+    hashables.extend(self._properties['remoteGlobalIDString'].Hashables())
+    return hashables
+
+
+class PBXTargetDependency(XCObject):
+  # The "target" property accepts an XCTarget object, and obviously not
+  # NoneType.  But XCTarget is defined below, so it can't be put into the
+  # schema yet.  The definition of PBXTargetDependency can't be moved below
+  # XCTarget because XCTarget's own schema references PBXTargetDependency.
+  # Python doesn't deal well with this circular relationship, and doesn't have
+  # a real way to do forward declarations.  To work around, the type of
+  # the "target" property is reset below, after XCTarget is defined.
+  #
+  # At least one of "name" and "target" is required.
+  _schema = XCObject._schema.copy()
+  _schema.update({
+    'name':        [0, str,                   0, 0],
+    'target':      [0, None.__class__,        0, 0],
+    'targetProxy': [0, PBXContainerItemProxy, 1, 1],
+  })
+
+  def __repr__(self):
+    name = self._properties.get('name') or self._properties['target'].Name()
+    return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self))
+
+  def Name(self):
+    # Admittedly not the best name, but it's what Xcode uses.
+    return self.__class__.__name__
+
+  def Hashables(self):
+    # super
+    hashables = XCObject.Hashables(self)
+
+    # Use the hashables of the weak objects that this object refers to.
+    hashables.extend(self._properties['targetProxy'].Hashables())
+    return hashables
+
+
+class PBXReferenceProxy(XCFileLikeElement):
+  _schema = XCFileLikeElement._schema.copy()
+  _schema.update({
+    'fileType':  [0, str,                   0, 1],
+    'path':      [0, str,                   0, 1],
+    'remoteRef': [0, PBXContainerItemProxy, 1, 1],
+  })
+
+
+class XCTarget(XCRemoteObject):
+  # An XCTarget is really just an XCObject, the XCRemoteObject thing is just
+  # to allow PBXProject to be used in the remoteGlobalIDString property of
+  # PBXContainerItemProxy.
+  #
+  # Setting a "name" property at instantiation may also affect "productName",
+  # which may in turn affect the "PRODUCT_NAME" build setting in children of
+  # "buildConfigurationList".  See __init__ below.
+  _schema = XCRemoteObject._schema.copy()
+  _schema.update({
+    'buildConfigurationList': [0, XCConfigurationList, 1, 1,
+                               XCConfigurationList()],
+    'buildPhases':            [1, XCBuildPhase,        1, 1, []],
+    'dependencies':           [1, PBXTargetDependency, 1, 1, []],
+    'name':                   [0, str,                 0, 1],
+    'productName':            [0, str,                 0, 1],
+  })
+
+  def __init__(self, properties=None, id=None, parent=None,
+               force_outdir=None, force_prefix=None, force_extension=None):
+    # super
+    XCRemoteObject.__init__(self, properties, id, parent)
+
+    # Set up additional defaults not expressed in the schema.  If a "name"
+    # property was supplied, set "productName" if it is not present.  Also set
+    # the "PRODUCT_NAME" build setting in each configuration, but only if
+    # the setting is not present in any build configuration.
+    if 'name' in self._properties:
+      if not 'productName' in self._properties:
+        self.SetProperty('productName', self._properties['name'])
+
+    if 'productName' in self._properties:
+      if 'buildConfigurationList' in self._properties:
+        configs = self._properties['buildConfigurationList']
+        if configs.HasBuildSetting('PRODUCT_NAME') == 0:
+          configs.SetBuildSetting('PRODUCT_NAME',
+                                  self._properties['productName'])
+
+  def AddDependency(self, other):
+    pbxproject = self.PBXProjectAncestor()
+    other_pbxproject = other.PBXProjectAncestor()
+    if pbxproject == other_pbxproject:
+      # Add a dependency to another target in the same project file.
+      container = PBXContainerItemProxy({'containerPortal':      pbxproject,
+                                         'proxyType':            1,
+                                         'remoteGlobalIDString': other,
+                                         'remoteInfo':           other.Name()})
+      dependency = PBXTargetDependency({'target':      other,
+                                        'targetProxy': container})
+      self.AppendProperty('dependencies', dependency)
+    else:
+      # Add a dependency to a target in a different project file.
+      other_project_ref = \
+          pbxproject.AddOrGetProjectReference(other_pbxproject)[1]
+      container = PBXContainerItemProxy({
+            'containerPortal':      other_project_ref,
+            'proxyType':            1,
+            'remoteGlobalIDString': other,
+            'remoteInfo':           other.Name(),
+          })
+      dependency = PBXTargetDependency({'name':        other.Name(),
+                                        'targetProxy': container})
+      self.AppendProperty('dependencies', dependency)
+
+  # Proxy all of these through to the build configuration list.
+
+  def ConfigurationNamed(self, name):
+    return self._properties['buildConfigurationList'].ConfigurationNamed(name)
+
+  def DefaultConfiguration(self):
+    return self._properties['buildConfigurationList'].DefaultConfiguration()
+
+  def HasBuildSetting(self, key):
+    return self._properties['buildConfigurationList'].HasBuildSetting(key)
+
+  def GetBuildSetting(self, key):
+    return self._properties['buildConfigurationList'].GetBuildSetting(key)
+
+  def SetBuildSetting(self, key, value):
+    return self._properties['buildConfigurationList'].SetBuildSetting(key, \
+                                                                      value)
+
+  def AppendBuildSetting(self, key, value):
+    return self._properties['buildConfigurationList'].AppendBuildSetting(key, \
+                                                                         value)
+
+  def DelBuildSetting(self, key):
+    return self._properties['buildConfigurationList'].DelBuildSetting(key)
+
+
+# Redefine the type of the "target" property.  See PBXTargetDependency._schema
+# above.
+PBXTargetDependency._schema['target'][1] = XCTarget
+
+
+class PBXNativeTarget(XCTarget):
+  # buildPhases is overridden in the schema to be able to set defaults.
+  #
+  # NOTE: Contrary to most objects, it is advisable to set parent when
+  # constructing PBXNativeTarget.  A parent of an XCTarget must be a PBXProject
+  # object.  A parent reference is required for a PBXNativeTarget during
+  # construction to be able to set up the target defaults for productReference,
+  # because a PBXBuildFile object must be created for the target and it must
+  # be added to the PBXProject's mainGroup hierarchy.
+  _schema = XCTarget._schema.copy()
+  _schema.update({
+    'buildPhases':      [1, XCBuildPhase,     1, 1,
+                         [PBXSourcesBuildPhase(), PBXFrameworksBuildPhase()]],
+    'buildRules':       [1, PBXBuildRule,     1, 1, []],
+    'productReference': [0, PBXFileReference, 0, 1],
+    'productType':      [0, str,              0, 1],
+  })
+
+  # Mapping from Xcode product-types to settings.  The settings are:
+  #  filetype : used for explicitFileType in the project file
+  #  prefix : the prefix for the file name
+  #  suffix : the suffix for the file name
+  _product_filetypes = {
+    'com.apple.product-type.application':       ['wrapper.application',
+                                                 '', '.app'],
+    'com.apple.product-type.app-extension':     ['wrapper.app-extension',
+                                                 '', '.appex'],
+    'com.apple.product-type.bundle':            ['wrapper.cfbundle',
+                                                 '', '.bundle'],
+    'com.apple.product-type.framework':         ['wrapper.framework',
+                                                 '', '.framework'],
+    'com.apple.product-type.library.dynamic':   ['compiled.mach-o.dylib',
+                                                 'lib', '.dylib'],
+    'com.apple.product-type.library.static':    ['archive.ar',
+                                                 'lib', '.a'],
+    'com.apple.product-type.tool':              ['compiled.mach-o.executable',
+                                                 '', ''],
+    'com.apple.product-type.bundle.unit-test':  ['wrapper.cfbundle',
+                                                 '', '.xctest'],
+    'com.googlecode.gyp.xcode.bundle':          ['compiled.mach-o.dylib',
+                                                 '', '.so'],
+  }
+
+  def __init__(self, properties=None, id=None, parent=None,
+               force_outdir=None, force_prefix=None, force_extension=None):
+    # super
+    XCTarget.__init__(self, properties, id, parent)
+
+    if 'productName' in self._properties and \
+       'productType' in self._properties and \
+       not 'productReference' in self._properties and \
+       self._properties['productType'] in self._product_filetypes:
+      products_group = None
+      pbxproject = self.PBXProjectAncestor()
+      if pbxproject != None:
+        products_group = pbxproject.ProductsGroup()
+
+      if products_group != None:
+        (filetype, prefix, suffix) = \
+            self._product_filetypes[self._properties['productType']]
+        # Xcode does not have a distinct type for loadable modules that are
+        # pure BSD targets (not in a bundle wrapper). GYP allows such modules
+        # to be specified by setting a target type to loadable_module without
+        # having mac_bundle set. These are mapped to the pseudo-product type
+        # com.googlecode.gyp.xcode.bundle.
+        #
+        # By picking up this special type and converting it to a dynamic
+        # library (com.apple.product-type.library.dynamic) with fix-ups,
+        # single-file loadable modules can be produced.
+        #
+        # MACH_O_TYPE is changed to mh_bundle to produce the proper file type
+        # (as opposed to mh_dylib). In order for linking to succeed,
+        # DYLIB_CURRENT_VERSION and DYLIB_COMPATIBILITY_VERSION must be
+        # cleared. They are meaningless for type mh_bundle.
+        #
+        # Finally, the .so extension is forcibly applied over the default
+        # (.dylib), unless another forced extension is already selected.
+        # .dylib is plainly wrong, and .bundle is used by loadable_modules in
+        # bundle wrappers (com.apple.product-type.bundle). .so seems an odd
+        # choice because it's used as the extension on many other systems that
+        # don't distinguish between linkable shared libraries and non-linkable
+        # loadable modules, but there's precedent: Python loadable modules on
+        # Mac OS X use an .so extension.
+        if self._properties['productType'] == 'com.googlecode.gyp.xcode.bundle':
+          self._properties['productType'] = \
+              'com.apple.product-type.library.dynamic'
+          self.SetBuildSetting('MACH_O_TYPE', 'mh_bundle')
+          self.SetBuildSetting('DYLIB_CURRENT_VERSION', '')
+          self.SetBuildSetting('DYLIB_COMPATIBILITY_VERSION', '')
+          if force_extension is None:
+            force_extension = suffix[1:]
+
+        if self._properties['productType'] == \
+           'com.apple.product-type-bundle.unit.test':
+          if force_extension is None:
+            force_extension = suffix[1:]
+
+        if force_extension is not None:
+          # If it's a wrapper (bundle), set WRAPPER_EXTENSION.
+          # Extension override.
+          suffix = '.' + force_extension
+          if filetype.startswith('wrapper.'):
+            self.SetBuildSetting('WRAPPER_EXTENSION', force_extension)
+          else:
+            self.SetBuildSetting('EXECUTABLE_EXTENSION', force_extension)
+
+          if filetype.startswith('compiled.mach-o.executable'):
+            product_name = self._properties['productName']
+            product_name += suffix
+            suffix = ''
+            self.SetProperty('productName', product_name)
+            self.SetBuildSetting('PRODUCT_NAME', product_name)
+
+        # Xcode handles most prefixes based on the target type, however there
+        # are exceptions.  If a "BSD Dynamic Library" target is added in the
+        # Xcode UI, Xcode sets EXECUTABLE_PREFIX.  This check duplicates that
+        # behavior.
+        if force_prefix is not None:
+          prefix = force_prefix
+        if filetype.startswith('wrapper.'):
+          self.SetBuildSetting('WRAPPER_PREFIX', prefix)
+        else:
+          self.SetBuildSetting('EXECUTABLE_PREFIX', prefix)
+
+        if force_outdir is not None:
+          self.SetBuildSetting('TARGET_BUILD_DIR', force_outdir)
+
+        # TODO(tvl): Remove the below hack.
+        #    http://code.google.com/p/gyp/issues/detail?id=122
+
+        # Some targets include the prefix in the target_name.  These targets
+        # really should just add a product_name setting that doesn't include
+        # the prefix.  For example:
+        #  target_name = 'libevent', product_name = 'event'
+        # This check cleans up for them.
+        product_name = self._properties['productName']
+        prefix_len = len(prefix)
+        if prefix_len and (product_name[:prefix_len] == prefix):
+          product_name = product_name[prefix_len:]
+          self.SetProperty('productName', product_name)
+          self.SetBuildSetting('PRODUCT_NAME', product_name)
+
+        ref_props = {
+          'explicitFileType': filetype,
+          'includeInIndex':   0,
+          'path':             prefix + product_name + suffix,
+          'sourceTree':       'BUILT_PRODUCTS_DIR',
+        }
+        file_ref = PBXFileReference(ref_props)
+        products_group.AppendChild(file_ref)
+        self.SetProperty('productReference', file_ref)
+
+  def GetBuildPhaseByType(self, type):
+    if not 'buildPhases' in self._properties:
+      return None
+
+    the_phase = None
+    for phase in self._properties['buildPhases']:
+      if isinstance(phase, type):
+        # Some phases may be present in multiples in a well-formed project file,
+        # but phases like PBXSourcesBuildPhase may only be present singly, and
+        # this function is intended as an aid to GetBuildPhaseByType.  Loop
+        # over the entire list of phases and assert if more than one of the
+        # desired type is found.
+        assert the_phase is None
+        the_phase = phase
+
+    return the_phase
+
+  def HeadersPhase(self):
+    headers_phase = self.GetBuildPhaseByType(PBXHeadersBuildPhase)
+    if headers_phase is None:
+      headers_phase = PBXHeadersBuildPhase()
+
+      # The headers phase should come before the resources, sources, and
+      # frameworks phases, if any.
+      insert_at = len(self._properties['buildPhases'])
+      for index in xrange(0, len(self._properties['buildPhases'])):
+        phase = self._properties['buildPhases'][index]
+        if isinstance(phase, PBXResourcesBuildPhase) or \
+           isinstance(phase, PBXSourcesBuildPhase) or \
+           isinstance(phase, PBXFrameworksBuildPhase):
+          insert_at = index
+          break
+
+      self._properties['buildPhases'].insert(insert_at, headers_phase)
+      headers_phase.parent = self
+
+    return headers_phase
+
+  def ResourcesPhase(self):
+    resources_phase = self.GetBuildPhaseByType(PBXResourcesBuildPhase)
+    if resources_phase is None:
+      resources_phase = PBXResourcesBuildPhase()
+
+      # The resources phase should come before the sources and frameworks
+      # phases, if any.
+      insert_at = len(self._properties['buildPhases'])
+      for index in xrange(0, len(self._properties['buildPhases'])):
+        phase = self._properties['buildPhases'][index]
+        if isinstance(phase, PBXSourcesBuildPhase) or \
+           isinstance(phase, PBXFrameworksBuildPhase):
+          insert_at = index
+          break
+
+      self._properties['buildPhases'].insert(insert_at, resources_phase)
+      resources_phase.parent = self
+
+    return resources_phase
+
+  def SourcesPhase(self):
+    sources_phase = self.GetBuildPhaseByType(PBXSourcesBuildPhase)
+    if sources_phase is None:
+      sources_phase = PBXSourcesBuildPhase()
+      self.AppendProperty('buildPhases', sources_phase)
+
+    return sources_phase
+
+  def FrameworksPhase(self):
+    frameworks_phase = self.GetBuildPhaseByType(PBXFrameworksBuildPhase)
+    if frameworks_phase is None:
+      frameworks_phase = PBXFrameworksBuildPhase()
+      self.AppendProperty('buildPhases', frameworks_phase)
+
+    return frameworks_phase
+
+  def AddDependency(self, other):
+    # super
+    XCTarget.AddDependency(self, other)
+
+    static_library_type = 'com.apple.product-type.library.static'
+    shared_library_type = 'com.apple.product-type.library.dynamic'
+    framework_type = 'com.apple.product-type.framework'
+    if isinstance(other, PBXNativeTarget) and \
+       'productType' in self._properties and \
+       self._properties['productType'] != static_library_type and \
+       'productType' in other._properties and \
+       (other._properties['productType'] == static_library_type or \
+        ((other._properties['productType'] == shared_library_type or \
+          other._properties['productType'] == framework_type) and \
+         ((not other.HasBuildSetting('MACH_O_TYPE')) or
+          other.GetBuildSetting('MACH_O_TYPE') != 'mh_bundle'))):
+
+      file_ref = other.GetProperty('productReference')
+
+      pbxproject = self.PBXProjectAncestor()
+      other_pbxproject = other.PBXProjectAncestor()
+      if pbxproject != other_pbxproject:
+        other_project_product_group = \
+            pbxproject.AddOrGetProjectReference(other_pbxproject)[0]
+        file_ref = other_project_product_group.GetChildByRemoteObject(file_ref)
+
+      self.FrameworksPhase().AppendProperty('files',
+                                            PBXBuildFile({'fileRef': file_ref}))
+
+
+class PBXAggregateTarget(XCTarget):
+  pass
+
+
+class PBXProject(XCContainerPortal):
+  # A PBXProject is really just an XCObject, the XCContainerPortal thing is
+  # just to allow PBXProject to be used in the containerPortal property of
+  # PBXContainerItemProxy.
+  """
+
+  Attributes:
+    path: "sample.xcodeproj".  TODO(mark) Document me!
+    _other_pbxprojects: A dictionary, keyed by other PBXProject objects.  Each
+                        value is a reference to the dict in the
+                        projectReferences list associated with the keyed
+                        PBXProject.
+  """
+
+  _schema = XCContainerPortal._schema.copy()
+  _schema.update({
+    'attributes':             [0, dict,                0, 0],
+    'buildConfigurationList': [0, XCConfigurationList, 1, 1,
+                               XCConfigurationList()],
+    'compatibilityVersion':   [0, str,                 0, 1, 'Xcode 3.2'],
+    'hasScannedForEncodings': [0, int,                 0, 1, 1],
+    'mainGroup':              [0, PBXGroup,            1, 1, PBXGroup()],
+    'projectDirPath':         [0, str,                 0, 1, ''],
+    'projectReferences':      [1, dict,                0, 0],
+    'projectRoot':            [0, str,                 0, 1, ''],
+    'targets':                [1, XCTarget,            1, 1, []],
+  })
+
+  def __init__(self, properties=None, id=None, parent=None, path=None):
+    self.path = path
+    self._other_pbxprojects = {}
+    # super
+    return XCContainerPortal.__init__(self, properties, id, parent)
+
+  def Name(self):
+    name = self.path
+    if name[-10:] == '.xcodeproj':
+      name = name[:-10]
+    return posixpath.basename(name)
+
+  def Path(self):
+    return self.path
+
+  def Comment(self):
+    return 'Project object'
+
+  def Children(self):
+    # super
+    children = XCContainerPortal.Children(self)
+
+    # Add children that the schema doesn't know about.  Maybe there's a more
+    # elegant way around this, but this is the only case where we need to own
+    # objects in a dictionary (that is itself in a list), and three lines for
+    # a one-off isn't that big a deal.
+    if 'projectReferences' in self._properties:
+      for reference in self._properties['projectReferences']:
+        children.append(reference['ProductGroup'])
+
+    return children
+
+  def PBXProjectAncestor(self):
+    return self
+
+  def _GroupByName(self, name):
+    if not 'mainGroup' in self._properties:
+      self.SetProperty('mainGroup', PBXGroup())
+
+    main_group = self._properties['mainGroup']
+    group = main_group.GetChildByName(name)
+    if group is None:
+      group = PBXGroup({'name': name})
+      main_group.AppendChild(group)
+
+    return group
+
+  # SourceGroup and ProductsGroup are created by default in Xcode's own
+  # templates.
+  def SourceGroup(self):
+    return self._GroupByName('Source')
+
+  def ProductsGroup(self):
+    return self._GroupByName('Products')
+
+  # IntermediatesGroup is used to collect source-like files that are generated
+  # by rules or script phases and are placed in intermediate directories such
+  # as DerivedSources.
+  def IntermediatesGroup(self):
+    return self._GroupByName('Intermediates')
+
+  # FrameworksGroup and ProjectsGroup are top-level groups used to collect
+  # frameworks and projects.
+  def FrameworksGroup(self):
+    return self._GroupByName('Frameworks')
+
+  def ProjectsGroup(self):
+    return self._GroupByName('Projects')
+
+  def RootGroupForPath(self, path):
+    """Returns a PBXGroup child of this object to which path should be added.
+
+    This method is intended to choose between SourceGroup and
+    IntermediatesGroup on the basis of whether path is present in a source
+    directory or an intermediates directory.  For the purposes of this
+    determination, any path located within a derived file directory such as
+    PROJECT_DERIVED_FILE_DIR is treated as being in an intermediates
+    directory.
+
+    The returned value is a two-element tuple.  The first element is the
+    PBXGroup, and the second element specifies whether that group should be
+    organized hierarchically (True) or as a single flat list (False).
+    """
+
+    # TODO(mark): make this a class variable and bind to self on call?
+    # Also, this list is nowhere near exhaustive.
+    # INTERMEDIATE_DIR and SHARED_INTERMEDIATE_DIR are used by
+    # gyp.generator.xcode.  There should probably be some way for that module
+    # to push the names in, rather than having to hard-code them here.
+    source_tree_groups = {
+      'DERIVED_FILE_DIR':         (self.IntermediatesGroup, True),
+      'INTERMEDIATE_DIR':         (self.IntermediatesGroup, True),
+      'PROJECT_DERIVED_FILE_DIR': (self.IntermediatesGroup, True),
+      'SHARED_INTERMEDIATE_DIR':  (self.IntermediatesGroup, True),
+    }
+
+    (source_tree, path) = SourceTreeAndPathFromPath(path)
+    if source_tree != None and source_tree in source_tree_groups:
+      (group_func, hierarchical) = source_tree_groups[source_tree]
+      group = group_func()
+      return (group, hierarchical)
+
+    # TODO(mark): make additional choices based on file extension.
+
+    return (self.SourceGroup(), True)
+
+  def AddOrGetFileInRootGroup(self, path):
+    """Returns a PBXFileReference corresponding to path in the correct group
+    according to RootGroupForPath's heuristics.
+
+    If an existing PBXFileReference for path exists, it will be returned.
+    Otherwise, one will be created and returned.
+    """
+
+    (group, hierarchical) = self.RootGroupForPath(path)
+    return group.AddOrGetFileByPath(path, hierarchical)
+
+  def RootGroupsTakeOverOnlyChildren(self, recurse=False):
+    """Calls TakeOverOnlyChild for all groups in the main group."""
+
+    for group in self._properties['mainGroup']._properties['children']:
+      if isinstance(group, PBXGroup):
+        group.TakeOverOnlyChild(recurse)
+
+  def SortGroups(self):
+    # Sort the children of the mainGroup (like "Source" and "Products")
+    # according to their defined order.
+    self._properties['mainGroup']._properties['children'] = \
+        sorted(self._properties['mainGroup']._properties['children'],
+               cmp=lambda x,y: x.CompareRootGroup(y))
+
+    # Sort everything else by putting group before files, and going
+    # alphabetically by name within sections of groups and files.  SortGroup
+    # is recursive.
+    for group in self._properties['mainGroup']._properties['children']:
+      if not isinstance(group, PBXGroup):
+        continue
+
+      if group.Name() == 'Products':
+        # The Products group is a special case.  Instead of sorting
+        # alphabetically, sort things in the order of the targets that
+        # produce the products.  To do this, just build up a new list of
+        # products based on the targets.
+        products = []
+        for target in self._properties['targets']:
+          if not isinstance(target, PBXNativeTarget):
+            continue
+          product = target._properties['productReference']
+          # Make sure that the product is already in the products group.
+          assert product in group._properties['children']
+          products.append(product)
+
+        # Make sure that this process doesn't miss anything that was already
+        # in the products group.
+        assert len(products) == len(group._properties['children'])
+        group._properties['children'] = products
+      else:
+        group.SortGroup()
+
+  def AddOrGetProjectReference(self, other_pbxproject):
+    """Add a reference to another project file (via PBXProject object) to this
+    one.
+
+    Returns [ProductGroup, ProjectRef].  ProductGroup is a PBXGroup object in
+    this project file that contains a PBXReferenceProxy object for each
+    product of each PBXNativeTarget in the other project file.  ProjectRef is
+    a PBXFileReference to the other project file.
+
+    If this project file already references the other project file, the
+    existing ProductGroup and ProjectRef are returned.  The ProductGroup will
+    still be updated if necessary.
+    """
+
+    if not 'projectReferences' in self._properties:
+      self._properties['projectReferences'] = []
+
+    product_group = None
+    project_ref = None
+
+    if not other_pbxproject in self._other_pbxprojects:
+      # This project file isn't yet linked to the other one.  Establish the
+      # link.
+      product_group = PBXGroup({'name': 'Products'})
+
+      # ProductGroup is strong.
+      product_group.parent = self
+
+      # There's nothing unique about this PBXGroup, and if left alone, it will
+      # wind up with the same set of hashables as all other PBXGroup objects
+      # owned by the projectReferences list.  Add the hashables of the
+      # remote PBXProject that it's related to.
+      product_group._hashables.extend(other_pbxproject.Hashables())
+
+      # The other project reports its path as relative to the same directory
+      # that this project's path is relative to.  The other project's path
+      # is not necessarily already relative to this project.  Figure out the
+      # pathname that this project needs to use to refer to the other one.
+      this_path = posixpath.dirname(self.Path())
+      projectDirPath = self.GetProperty('projectDirPath')
+      if projectDirPath:
+        if posixpath.isabs(projectDirPath[0]):
+          this_path = projectDirPath
+        else:
+          this_path = posixpath.join(this_path, projectDirPath)
+      other_path = gyp.common.RelativePath(other_pbxproject.Path(), this_path)
+
+      # ProjectRef is weak (it's owned by the mainGroup hierarchy).
+      project_ref = PBXFileReference({
+            'lastKnownFileType': 'wrapper.pb-project',
+            'path':              other_path,
+            'sourceTree':        'SOURCE_ROOT',
+          })
+      self.ProjectsGroup().AppendChild(project_ref)
+
+      ref_dict = {'ProductGroup': product_group, 'ProjectRef': project_ref}
+      self._other_pbxprojects[other_pbxproject] = ref_dict
+      self.AppendProperty('projectReferences', ref_dict)
+
+      # Xcode seems to sort this list case-insensitively
+      self._properties['projectReferences'] = \
+          sorted(self._properties['projectReferences'], cmp=lambda x,y:
+                 cmp(x['ProjectRef'].Name().lower(),
+                     y['ProjectRef'].Name().lower()))
+    else:
+      # The link already exists.  Pull out the relevnt data.
+      project_ref_dict = self._other_pbxprojects[other_pbxproject]
+      product_group = project_ref_dict['ProductGroup']
+      project_ref = project_ref_dict['ProjectRef']
+
+    self._SetUpProductReferences(other_pbxproject, product_group, project_ref)
+
+    return [product_group, project_ref]
+
+  def _SetUpProductReferences(self, other_pbxproject, product_group,
+                              project_ref):
+    # TODO(mark): This only adds references to products in other_pbxproject
+    # when they don't exist in this pbxproject.  Perhaps it should also
+    # remove references from this pbxproject that are no longer present in
+    # other_pbxproject.  Perhaps it should update various properties if they
+    # change.
+    for target in other_pbxproject._properties['targets']:
+      if not isinstance(target, PBXNativeTarget):
+        continue
+
+      other_fileref = target._properties['productReference']
+      if product_group.GetChildByRemoteObject(other_fileref) is None:
+        # Xcode sets remoteInfo to the name of the target and not the name
+        # of its product, despite this proxy being a reference to the product.
+        container_item = PBXContainerItemProxy({
+              'containerPortal':      project_ref,
+              'proxyType':            2,
+              'remoteGlobalIDString': other_fileref,
+              'remoteInfo':           target.Name()
+            })
+        # TODO(mark): Does sourceTree get copied straight over from the other
+        # project?  Can the other project ever have lastKnownFileType here
+        # instead of explicitFileType?  (Use it if so?)  Can path ever be
+        # unset?  (I don't think so.)  Can other_fileref have name set, and
+        # does it impact the PBXReferenceProxy if so?  These are the questions
+        # that perhaps will be answered one day.
+        reference_proxy = PBXReferenceProxy({
+              'fileType':   other_fileref._properties['explicitFileType'],
+              'path':       other_fileref._properties['path'],
+              'sourceTree': other_fileref._properties['sourceTree'],
+              'remoteRef':  container_item,
+            })
+
+        product_group.AppendChild(reference_proxy)
+
+  def SortRemoteProductReferences(self):
+    # For each remote project file, sort the associated ProductGroup in the
+    # same order that the targets are sorted in the remote project file.  This
+    # is the sort order used by Xcode.
+
+    def CompareProducts(x, y, remote_products):
+      # x and y are PBXReferenceProxy objects.  Go through their associated
+      # PBXContainerItem to get the remote PBXFileReference, which will be
+      # present in the remote_products list.
+      x_remote = x._properties['remoteRef']._properties['remoteGlobalIDString']
+      y_remote = y._properties['remoteRef']._properties['remoteGlobalIDString']
+      x_index = remote_products.index(x_remote)
+      y_index = remote_products.index(y_remote)
+
+      # Use the order of each remote PBXFileReference in remote_products to
+      # determine the sort order.
+      return cmp(x_index, y_index)
+
+    for other_pbxproject, ref_dict in self._other_pbxprojects.iteritems():
+      # Build up a list of products in the remote project file, ordered the
+      # same as the targets that produce them.
+      remote_products = []
+      for target in other_pbxproject._properties['targets']:
+        if not isinstance(target, PBXNativeTarget):
+          continue
+        remote_products.append(target._properties['productReference'])
+
+      # Sort the PBXReferenceProxy children according to the list of remote
+      # products.
+      product_group = ref_dict['ProductGroup']
+      product_group._properties['children'] = sorted(
+          product_group._properties['children'],
+          cmp=lambda x, y: CompareProducts(x, y, remote_products))
+
+
+class XCProjectFile(XCObject):
+  _schema = XCObject._schema.copy()
+  _schema.update({
+    'archiveVersion': [0, int,        0, 1, 1],
+    'classes':        [0, dict,       0, 1, {}],
+    'objectVersion':  [0, int,        0, 1, 45],
+    'rootObject':     [0, PBXProject, 1, 1],
+  })
+
+  def SetXcodeVersion(self, version):
+    version_to_object_version = {
+      '2.4': 45,
+      '3.0': 45,
+      '3.1': 45,
+      '3.2': 46,
+    }
+    if not version in version_to_object_version:
+      supported_str = ', '.join(sorted(version_to_object_version.keys()))
+      raise Exception(
+          'Unsupported Xcode version %s (supported: %s)' %
+          ( version, supported_str ) )
+    compatibility_version = 'Xcode %s' % version
+    self._properties['rootObject'].SetProperty('compatibilityVersion',
+                                               compatibility_version)
+    self.SetProperty('objectVersion', version_to_object_version[version]);
+
+  def ComputeIDs(self, recursive=True, overwrite=True, hash=None):
+    # Although XCProjectFile is implemented here as an XCObject, it's not a
+    # proper object in the Xcode sense, and it certainly doesn't have its own
+    # ID.  Pass through an attempt to update IDs to the real root object.
+    if recursive:
+      self._properties['rootObject'].ComputeIDs(recursive, overwrite, hash)
+
+  def Print(self, file=sys.stdout):
+    self.VerifyHasRequiredProperties()
+
+    # Add the special "objects" property, which will be caught and handled
+    # separately during printing.  This structure allows a fairly standard
+    # loop do the normal printing.
+    self._properties['objects'] = {}
+    self._XCPrint(file, 0, '// !$*UTF8*$!\n')
+    if self._should_print_single_line:
+      self._XCPrint(file, 0, '{ ')
+    else:
+      self._XCPrint(file, 0, '{\n')
+    for property, value in sorted(self._properties.iteritems(),
+                                  cmp=lambda x, y: cmp(x, y)):
+      if property == 'objects':
+        self._PrintObjects(file)
+      else:
+        self._XCKVPrint(file, 1, property, value)
+    self._XCPrint(file, 0, '}\n')
+    del self._properties['objects']
+
+  def _PrintObjects(self, file):
+    if self._should_print_single_line:
+      self._XCPrint(file, 0, 'objects = {')
+    else:
+      self._XCPrint(file, 1, 'objects = {\n')
+
+    objects_by_class = {}
+    for object in self.Descendants():
+      if object == self:
+        continue
+      class_name = object.__class__.__name__
+      if not class_name in objects_by_class:
+        objects_by_class[class_name] = []
+      objects_by_class[class_name].append(object)
+
+    for class_name in sorted(objects_by_class):
+      self._XCPrint(file, 0, '\n')
+      self._XCPrint(file, 0, '/* Begin ' + class_name + ' section */\n')
+      for object in sorted(objects_by_class[class_name],
+                           cmp=lambda x, y: cmp(x.id, y.id)):
+        object.Print(file)
+      self._XCPrint(file, 0, '/* End ' + class_name + ' section */\n')
+
+    if self._should_print_single_line:
+      self._XCPrint(file, 0, '}; ')
+    else:
+      self._XCPrint(file, 1, '};\n')
diff --git a/gyp/pylib/gyp/xml_fix.py b/gyp/pylib/gyp/xml_fix.py
new file mode 100644 (file)
index 0000000..5de8481
--- /dev/null
@@ -0,0 +1,69 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Applies a fix to CR LF TAB handling in xml.dom.
+
+Fixes this: http://code.google.com/p/chromium/issues/detail?id=76293
+Working around this: http://bugs.python.org/issue5752
+TODO(bradnelson): Consider dropping this when we drop XP support.
+"""
+
+
+import xml.dom.minidom
+
+
+def _Replacement_write_data(writer, data, is_attrib=False):
+  """Writes datachars to writer."""
+  data = data.replace("&", "&amp;").replace("<", "&lt;")
+  data = data.replace("\"", "&quot;").replace(">", "&gt;")
+  if is_attrib:
+    data = data.replace(
+        "\r", "&#xD;").replace(
+        "\n", "&#xA;").replace(
+        "\t", "&#x9;")
+  writer.write(data)
+
+
+def _Replacement_writexml(self, writer, indent="", addindent="", newl=""):
+  # indent = current indentation
+  # addindent = indentation to add to higher levels
+  # newl = newline string
+  writer.write(indent+"<" + self.tagName)
+
+  attrs = self._get_attributes()
+  a_names = attrs.keys()
+  a_names.sort()
+
+  for a_name in a_names:
+    writer.write(" %s=\"" % a_name)
+    _Replacement_write_data(writer, attrs[a_name].value, is_attrib=True)
+    writer.write("\"")
+  if self.childNodes:
+    writer.write(">%s" % newl)
+    for node in self.childNodes:
+      node.writexml(writer, indent + addindent, addindent, newl)
+    writer.write("%s</%s>%s" % (indent, self.tagName, newl))
+  else:
+    writer.write("/>%s" % newl)
+
+
+class XmlFix(object):
+  """Object to manage temporary patching of xml.dom.minidom."""
+
+  def __init__(self):
+    # Preserve current xml.dom.minidom functions.
+    self.write_data = xml.dom.minidom._write_data
+    self.writexml = xml.dom.minidom.Element.writexml
+    # Inject replacement versions of a function and a method.
+    xml.dom.minidom._write_data = _Replacement_write_data
+    xml.dom.minidom.Element.writexml = _Replacement_writexml
+
+  def Cleanup(self):
+    if self.write_data:
+      xml.dom.minidom._write_data = self.write_data
+      xml.dom.minidom.Element.writexml = self.writexml
+      self.write_data = None
+
+  def __del__(self):
+    self.Cleanup()
diff --git a/gyp/samples/samples b/gyp/samples/samples
new file mode 100755 (executable)
index 0000000..804b618
--- /dev/null
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os.path
+import shutil
+import sys
+
+
+gyps = [
+    'app/app.gyp',
+    'base/base.gyp',
+    'build/temp_gyp/googleurl.gyp',
+    'build/all.gyp',
+    'build/common.gypi',
+    'build/external_code.gypi',
+    'chrome/test/security_tests/security_tests.gyp',
+    'chrome/third_party/hunspell/hunspell.gyp',
+    'chrome/chrome.gyp',
+    'media/media.gyp',
+    'net/net.gyp',
+    'printing/printing.gyp',
+    'sdch/sdch.gyp',
+    'skia/skia.gyp',
+    'testing/gmock.gyp',
+    'testing/gtest.gyp',
+    'third_party/bzip2/bzip2.gyp',
+    'third_party/icu38/icu38.gyp',
+    'third_party/libevent/libevent.gyp',
+    'third_party/libjpeg/libjpeg.gyp',
+    'third_party/libpng/libpng.gyp',
+    'third_party/libxml/libxml.gyp',
+    'third_party/libxslt/libxslt.gyp',
+    'third_party/lzma_sdk/lzma_sdk.gyp',
+    'third_party/modp_b64/modp_b64.gyp',
+    'third_party/npapi/npapi.gyp',
+    'third_party/sqlite/sqlite.gyp',
+    'third_party/zlib/zlib.gyp',
+    'v8/tools/gyp/v8.gyp',
+    'webkit/activex_shim/activex_shim.gyp',
+    'webkit/activex_shim_dll/activex_shim_dll.gyp',
+    'webkit/build/action_csspropertynames.py',
+    'webkit/build/action_cssvaluekeywords.py',
+    'webkit/build/action_jsconfig.py',
+    'webkit/build/action_makenames.py',
+    'webkit/build/action_maketokenizer.py',
+    'webkit/build/action_useragentstylesheets.py',
+    'webkit/build/rule_binding.py',
+    'webkit/build/rule_bison.py',
+    'webkit/build/rule_gperf.py',
+    'webkit/tools/test_shell/test_shell.gyp',
+    'webkit/webkit.gyp',
+]
+
+
+def Main(argv):
+  if len(argv) != 3 or argv[1] not in ['push', 'pull']:
+    print 'Usage: %s push/pull PATH_TO_CHROME' % argv[0]
+    return 1
+
+  path_to_chrome = argv[2]
+
+  for g in gyps:
+    chrome_file = os.path.join(path_to_chrome, g)
+    local_file = os.path.join(os.path.dirname(argv[0]), os.path.split(g)[1])
+    if argv[1] == 'push':
+      print 'Copying %s to %s' % (local_file, chrome_file)
+      shutil.copyfile(local_file, chrome_file)
+    elif argv[1] == 'pull':
+      print 'Copying %s to %s' % (chrome_file, local_file)
+      shutil.copyfile(chrome_file, local_file)
+    else:
+      assert False
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv))
diff --git a/gyp/samples/samples.bat b/gyp/samples/samples.bat
new file mode 100644 (file)
index 0000000..778d9c9
--- /dev/null
@@ -0,0 +1,5 @@
+@rem Copyright (c) 2009 Google Inc. All rights reserved.\r
+@rem Use of this source code is governed by a BSD-style license that can be\r
+@rem found in the LICENSE file.\r
+\r
+@python %~dp0/samples %*\r
diff --git a/gyp/setup.py b/gyp/setup.py
new file mode 100755 (executable)
index 0000000..75a4255
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from setuptools import setup
+
+setup(
+  name='gyp',
+  version='0.1',
+  description='Generate Your Projects',
+  author='Chromium Authors',
+  author_email='chromium-dev@googlegroups.com',
+  url='http://code.google.com/p/gyp',
+  package_dir = {'': 'pylib'},
+  packages=['gyp', 'gyp.generator'],
+  entry_points = {'console_scripts': ['gyp=gyp:script_main'] }
+)
diff --git a/gyp/test/actions-bare/gyptest-bare.py b/gyp/test/actions-bare/gyptest-bare.py
new file mode 100755 (executable)
index 0000000..b0c1093
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies actions which are not depended on by other targets get executed.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('bare.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+test.build('bare.gyp', chdir='relocate/src')
+
+file_content = 'Hello from bare.py\n'
+
+test.built_file_must_match('out.txt', file_content, chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/actions-bare/src/bare.gyp b/gyp/test/actions-bare/src/bare.gyp
new file mode 100644 (file)
index 0000000..3d28f09
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'bare',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'action1',
+          'inputs': [
+            'bare.py',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/out.txt',
+          ],
+          'action': ['python', 'bare.py', '<(PRODUCT_DIR)/out.txt'],
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/actions-bare/src/bare.py b/gyp/test/actions-bare/src/bare.py
new file mode 100755 (executable)
index 0000000..1230750
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+f = open(sys.argv[1], 'wb')
+f.write('Hello from bare.py\n')
+f.close()
diff --git a/gyp/test/actions-multiple/gyptest-all.py b/gyp/test/actions-multiple/gyptest-all.py
new file mode 100755 (executable)
index 0000000..2a083de
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies two actions can be attached to the same input files.
+"""
+
+import sys
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Test of fine-grained dependencies for generators that can build individual
+# files on demand.
+# In particular:
+#   - TargetA depends on TargetB.
+#   - TargetA and TargetB are 'none' type with actions attached.
+#   - TargetA has multiple actions.
+#   - An output from one of the actions in TargetA (not the first listed),
+#     is requested as the build target.
+# Ensure that TargetB gets built.
+#
+# This sub-test can only be done with generators/build tools that can
+# be asked to build individual files rather than whole targets (make, ninja).
+if test.format in ['make', 'ninja']:
+  # Select location of target based on generator.
+  if test.format == 'make':
+    target = 'multi2.txt'
+  elif test.format == 'ninja':
+    if sys.platform in ['win32', 'cygwin']:
+      target = '..\\..\\multi2.txt'
+    else:
+      target = '../../multi2.txt'
+  else:
+    assert False
+  test.build('actions.gyp', chdir='relocate/src', target=target)
+  test.must_contain('relocate/src/multi2.txt', 'hello there')
+  test.must_contain('relocate/src/multi_dep.txt', 'hello there')
+
+
+# Test that two actions can be attached to the same inputs.
+test.build('actions.gyp', test.ALL, chdir='relocate/src')
+test.must_contain('relocate/src/output1.txt', 'hello there')
+test.must_contain('relocate/src/output2.txt', 'hello there')
+test.must_contain('relocate/src/output3.txt', 'hello there')
+test.must_contain('relocate/src/output4.txt', 'hello there')
+
+# Test that process_outputs_as_sources works in conjuction with merged
+# actions.
+test.run_built_executable(
+    'multiple_action_source_filter',
+    chdir='relocate/src',
+    stdout=(
+        '{\n'
+        'bar\n'
+        'car\n'
+        'dar\n'
+        'ear\n'
+        '}\n'
+    ),
+)
+
+
+test.pass_test()
diff --git a/gyp/test/actions-multiple/src/actions.gyp b/gyp/test/actions-multiple/src/actions.gyp
new file mode 100644 (file)
index 0000000..c70a58f
--- /dev/null
@@ -0,0 +1,226 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    # Have a long string so that actions will exceed xp 512 character
+    # command limit on xp.
+    'long_string':
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+        'abcdefghijklmnopqrstuvwxyz0123456789'
+  },
+  'targets': [
+    {
+      'target_name': 'multiple_action_target',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'action1',
+          'inputs': [
+            'copy.py',
+            'input.txt',
+          ],
+          'outputs': [
+            'output1.txt',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+        {
+          'action_name': 'action2',
+          'inputs': [
+            'copy.py',
+            'input.txt',
+          ],
+          'outputs': [
+            'output2.txt',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+        {
+          'action_name': 'action3',
+          'inputs': [
+            'copy.py',
+            'input.txt',
+          ],
+          'outputs': [
+            'output3.txt',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+        {
+          'action_name': 'action4',
+          'inputs': [
+            'copy.py',
+            'input.txt',
+          ],
+          'outputs': [
+            'output4.txt',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+    {
+      'target_name': 'multiple_action_source_filter',
+      'type': 'executable',
+      'sources': [
+        'main.c',
+        # TODO(bradnelson): add foo.c here once this issue is fixed:
+        #     http://code.google.com/p/gyp/issues/detail?id=175
+      ],
+      'actions': [
+        {
+          'action_name': 'action1',
+          'inputs': [
+            'foo.c',
+            'filter.py',
+          ],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/output1.c',
+          ],
+          'process_outputs_as_sources': 1,
+          'action': [
+            'python', 'filter.py', 'foo', 'bar', 'foo.c', '<@(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+        {
+          'action_name': 'action2',
+          'inputs': [
+            'foo.c',
+            'filter.py',
+          ],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/output2.c',
+          ],
+          'process_outputs_as_sources': 1,
+          'action': [
+            'python', 'filter.py', 'foo', 'car', 'foo.c', '<@(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+        {
+          'action_name': 'action3',
+          'inputs': [
+            'foo.c',
+            'filter.py',
+          ],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/output3.c',
+          ],
+          'process_outputs_as_sources': 1,
+          'action': [
+            'python', 'filter.py', 'foo', 'dar', 'foo.c', '<@(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+        {
+          'action_name': 'action4',
+          'inputs': [
+            'foo.c',
+            'filter.py',
+          ],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/output4.c',
+          ],
+          'process_outputs_as_sources': 1,
+          'action': [
+            'python', 'filter.py', 'foo', 'ear', 'foo.c', '<@(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+    {
+      'target_name': 'multiple_dependent_target',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'action1',
+          'inputs': [
+            'copy.py',
+            'input.txt',
+          ],
+          'outputs': [
+            'multi1.txt',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+        {
+          'action_name': 'action2',
+          'inputs': [
+            'copy.py',
+            'input.txt',
+          ],
+          'outputs': [
+            'multi2.txt',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+      'dependencies': [
+        'multiple_required_target',
+      ],
+    },
+    {
+      'target_name': 'multiple_required_target',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'multi_dep',
+          'inputs': [
+            'copy.py',
+            'input.txt',
+          ],
+          'outputs': [
+            'multi_dep.txt',
+          ],
+          'process_outputs_as_sources': 1,
+          'action': [
+            'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/actions-multiple/src/copy.py b/gyp/test/actions-multiple/src/copy.py
new file mode 100755 (executable)
index 0000000..0774679
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import shutil
+import sys
+
+shutil.copyfile(sys.argv[1], sys.argv[2])
diff --git a/gyp/test/actions-multiple/src/filter.py b/gyp/test/actions-multiple/src/filter.py
new file mode 100755 (executable)
index 0000000..f61a5fa
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import sys
+
+data = open(sys.argv[3], 'r').read()
+fh = open(sys.argv[4], 'w')
+fh.write(data.replace(sys.argv[1], sys.argv[2]))
+fh.close()
diff --git a/gyp/test/actions-multiple/src/foo.c b/gyp/test/actions-multiple/src/foo.c
new file mode 100644 (file)
index 0000000..23c4ef7
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+void foo(void) {
+  printf("foo\n");
+}
diff --git a/gyp/test/actions-multiple/src/input.txt b/gyp/test/actions-multiple/src/input.txt
new file mode 100644 (file)
index 0000000..c7c7da3
--- /dev/null
@@ -0,0 +1 @@
+hello there
diff --git a/gyp/test/actions-multiple/src/main.c b/gyp/test/actions-multiple/src/main.c
new file mode 100644 (file)
index 0000000..0a420b9
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+void bar(void);
+void car(void);
+void dar(void);
+void ear(void);
+
+int main() {
+  printf("{\n");
+  bar();
+  car();
+  dar();
+  ear();
+  printf("}\n");
+  return 0;
+}
diff --git a/gyp/test/actions-none/gyptest-none.py b/gyp/test/actions-none/gyptest-none.py
new file mode 100755 (executable)
index 0000000..1e0b691
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies actions can be in 'none' type targets with source files.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('none_with_source_files.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+test.build('none_with_source_files.gyp', chdir='relocate/src')
+
+file_content = 'foo.cc\n'
+
+test.built_file_must_match('fake.out', file_content, chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/actions-none/src/fake_cross.py b/gyp/test/actions-none/src/fake_cross.py
new file mode 100644 (file)
index 0000000..2913f66
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import sys
+
+fh = open(sys.argv[-1], 'wb')
+for filename in sys.argv[1:-1]:
+  fh.write(open(filename).read())
+fh.close()
diff --git a/gyp/test/actions-none/src/foo.cc b/gyp/test/actions-none/src/foo.cc
new file mode 100644 (file)
index 0000000..c6c6174
--- /dev/null
@@ -0,0 +1 @@
+foo.cc
diff --git a/gyp/test/actions-none/src/none_with_source_files.gyp b/gyp/test/actions-none/src/none_with_source_files.gyp
new file mode 100644 (file)
index 0000000..e2aaebc
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Test that 'none' type targets can have .cc files in them.
+
+{
+  'targets': [
+    {
+      'target_name': 'none_with_sources',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'foo.cc',
+      ],
+      'actions': [
+        {
+          'action_name': 'fake_cross',
+          'inputs': [
+            'fake_cross.py',
+            '<@(_sources)',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/fake.out',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<@(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        }
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/actions-subdir/gyptest-action.py b/gyp/test/actions-subdir/gyptest-action.py
new file mode 100755 (executable)
index 0000000..09cfef1
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test actions that output to PRODUCT_DIR.
+"""
+
+import TestGyp
+
+# TODO fix this for xcode: http://code.google.com/p/gyp/issues/detail?id=88
+test = TestGyp.TestGyp(formats=['!xcode'])
+
+test.run_gyp('none.gyp', chdir='src')
+
+test.build('none.gyp', test.ALL, chdir='src')
+
+file_content = 'Hello from make-file.py\n'
+subdir_file_content = 'Hello from make-subdir-file.py\n'
+
+test.built_file_must_match('file.out', file_content, chdir='src')
+test.built_file_must_match('subdir_file.out', subdir_file_content, chdir='src')
+
+test.pass_test()
diff --git a/gyp/test/actions-subdir/src/make-file.py b/gyp/test/actions-subdir/src/make-file.py
new file mode 100755 (executable)
index 0000000..74e5581
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = 'Hello from make-file.py\n'
+
+open(sys.argv[1], 'wb').write(contents)
diff --git a/gyp/test/actions-subdir/src/none.gyp b/gyp/test/actions-subdir/src/none.gyp
new file mode 100644 (file)
index 0000000..23f8d25
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'file',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'actions': [
+        {
+          'action_name': 'make-file',
+          'inputs': [
+            'make-file.py',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/file.out',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        }
+      ],
+      'dependencies': [
+        'subdir/subdir.gyp:subdir_file',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/actions-subdir/src/subdir/make-subdir-file.py b/gyp/test/actions-subdir/src/subdir/make-subdir-file.py
new file mode 100755 (executable)
index 0000000..80ce19a
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = 'Hello from make-subdir-file.py\n'
+
+open(sys.argv[1], 'wb').write(contents)
diff --git a/gyp/test/actions-subdir/src/subdir/subdir.gyp b/gyp/test/actions-subdir/src/subdir/subdir.gyp
new file mode 100644 (file)
index 0000000..0315d4e
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'subdir_file',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'actions': [
+        {
+          'action_name': 'make-subdir-file',
+          'inputs': [
+            'make-subdir-file.py',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/subdir_file.out',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        }
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/actions/generated-header/action.py b/gyp/test/actions/generated-header/action.py
new file mode 100644 (file)
index 0000000..9be9879
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+
+outfile = sys.argv[1]
+open(outfile, 'w').write('const char kFoo[] = "%s";' % sys.argv[2])
diff --git a/gyp/test/actions/generated-header/main.cc b/gyp/test/actions/generated-header/main.cc
new file mode 100644 (file)
index 0000000..7973781
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+#include "MyHeader.h"
+
+int main() {
+  printf("%s\n", kFoo);
+}
diff --git a/gyp/test/actions/generated-header/test.gyp b/gyp/test/actions/generated-header/test.gyp
new file mode 100644 (file)
index 0000000..209b951
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'generate_header',
+      'type': 'none',
+      'actions': [
+        {
+          'inputs': [ ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/MyHeader.h',
+          ],
+          'action_name': 'generate header',
+          'action': ['python', './action.py',
+                     '<(SHARED_INTERMEDIATE_DIR)/MyHeader.h', 'foobar output' ],
+        },
+      ],
+      'msvs_cygwin_shell': 0,
+    },
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'dependencies': [
+        'generate_header',
+      ],
+      'include_dirs': [
+        '<(SHARED_INTERMEDIATE_DIR)',
+      ],
+      'sources': [ 'main.cc' ],
+    },
+  ],
+}
diff --git a/gyp/test/actions/gyptest-all.py b/gyp/test/actions/gyptest-all.py
new file mode 100755 (executable)
index 0000000..705fec4
--- /dev/null
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple actions when using an explicit build target of 'all'.
+"""
+
+import glob
+import os
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_all')
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Some gyp files use an action that mentions an output but never
+# writes it as a means to making the action run on every build.  That
+# doesn't mesh well with ninja's semantics.  TODO(evan): figure out
+# how to work always-run actions in to ninja.
+# Android also can't do this as it doesn't have order-only dependencies.
+if test.format in ['ninja', 'android']:
+  test.build('actions.gyp', test.ALL, chdir='relocate/src')
+else:
+  # Test that an "always run" action increases a counter on multiple
+  # invocations, and that a dependent action updates in step.
+  test.build('actions.gyp', test.ALL, chdir='relocate/src')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '1')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '1')
+  test.build('actions.gyp', test.ALL, chdir='relocate/src')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '2')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
+
+  # The "always run" action only counts to 2, but the dependent target
+  # will count forever if it's allowed to run. This verifies that the
+  # dependent target only runs when the "always run" action generates
+  # new output, not just because the "always run" ran.
+  test.build('actions.gyp', test.ALL, chdir='relocate/src')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '2')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
+
+expect = """\
+Hello from program.c
+Hello from make-prog1.py
+Hello from make-prog2.py
+"""
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir1'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+
+test.must_match('relocate/src/subdir2/file.out', "Hello from make-file.py\n")
+
+
+expect = "Hello from generate_main.py\n"
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir3'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('null_input', chdir=chdir, stdout=expect)
+
+
+# Clean out files which may have been created if test.ALL was run.
+def clean_dep_files():
+  for file in (glob.glob('relocate/src/dep_*.txt') +
+               glob.glob('relocate/src/deps_all_done_*.txt')):
+    if os.path.exists(file):
+      os.remove(file)
+
+# Confirm our clean.
+clean_dep_files()
+test.must_not_exist('relocate/src/dep_1.txt')
+test.must_not_exist('relocate/src/deps_all_done_first_123.txt')
+
+# Make sure all deps finish before an action is run on a 'None' target.
+# If using the Make builder, add -j to make things more difficult.
+arguments = []
+if test.format == 'make':
+  arguments = ['-j']
+test.build('actions.gyp', 'action_with_dependencies_123', chdir='relocate/src',
+           arguments=arguments)
+test.must_exist('relocate/src/deps_all_done_first_123.txt')
+
+# Try again with a target that has deps in reverse.  Output files from
+# previous tests deleted.  Confirm this execution did NOT run the ALL
+# target which would mess up our dep tests.
+clean_dep_files()
+test.build('actions.gyp', 'action_with_dependencies_321', chdir='relocate/src',
+           arguments=arguments)
+test.must_exist('relocate/src/deps_all_done_first_321.txt')
+test.must_not_exist('relocate/src/deps_all_done_first_123.txt')
+
+
+test.pass_test()
diff --git a/gyp/test/actions/gyptest-default.py b/gyp/test/actions/gyptest-default.py
new file mode 100755 (executable)
index 0000000..f5b4e35
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple actions when using the default build target.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_default')
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Some gyp files use an action that mentions an output but never
+# writes it as a means to making the action run on every build.  That
+# doesn't mesh well with ninja's semantics.  TODO(evan): figure out
+# how to work always-run actions in to ninja.
+# Android also can't do this as it doesn't have order-only dependencies.
+if test.format in ['ninja', 'android']:
+  test.build('actions.gyp', test.ALL, chdir='relocate/src')
+else:
+  # Test that an "always run" action increases a counter on multiple
+  # invocations, and that a dependent action updates in step.
+  test.build('actions.gyp', chdir='relocate/src')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '1')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '1')
+  test.build('actions.gyp', chdir='relocate/src')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '2')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
+
+  # The "always run" action only counts to 2, but the dependent target
+  # will count forever if it's allowed to run. This verifies that the
+  # dependent target only runs when the "always run" action generates
+  # new output, not just because the "always run" ran.
+  test.build('actions.gyp', test.ALL, chdir='relocate/src')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '2')
+  test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
+
+expect = """\
+Hello from program.c
+Hello from make-prog1.py
+Hello from make-prog2.py
+"""
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir1'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+
+test.must_match('relocate/src/subdir2/file.out', "Hello from make-file.py\n")
+
+
+expect = "Hello from generate_main.py\n"
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir3'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('null_input', chdir=chdir, stdout=expect)
+
+
+test.pass_test()
diff --git a/gyp/test/actions/gyptest-errors.py b/gyp/test/actions/gyptest-errors.py
new file mode 100755 (executable)
index 0000000..e1ef883
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies behavior for different action configuration errors:
+exit status of 1, and the expected error message must be in stderr.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_errors')
+
+
+test.run_gyp('action_missing_name.gyp', chdir='src', status=1, stderr=None)
+expect = [
+  "Anonymous action in target broken_actions2.  An action must have an 'action_name' field.",
+]
+test.must_contain_all_lines(test.stderr(), expect)
+
+
+test.pass_test()
diff --git a/gyp/test/actions/gyptest-generated-header.py b/gyp/test/actions/gyptest-generated-header.py
new file mode 100644 (file)
index 0000000..fa680ab
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that dependencies on generated headers work, even if the header has
+a mixed-case file name.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+if test.format == 'android':
+  # This test currently fails on android. Investigate why, fix the issues
+  # responsible, and reenable this test on android. See bug:
+  # https://code.google.com/p/gyp/issues/detail?id=436
+  test.skip_test(message='Test fails on android. Fix and reenable.\n')
+
+CHDIR = 'generated-header'
+
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', 'program', chdir=CHDIR)
+test.up_to_date('test.gyp', 'program', chdir=CHDIR)
+
+expect = 'foobar output\n'
+test.run_built_executable('program', chdir=CHDIR, stdout=expect)
+
+# Change what's written to the generated header, regyp and rebuild, and check
+# that the change makes it to the executable and that the build is clean.
+test.sleep()
+test.write('generated-header/test.gyp',
+           test.read('generated-header/test.gyp').replace('foobar', 'barbaz'))
+
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', 'program', chdir=CHDIR)
+test.up_to_date('test.gyp', 'program', chdir=CHDIR)
+
+expect = 'barbaz output\n'
+test.run_built_executable('program', chdir=CHDIR, stdout=expect)
+
+test.pass_test()
diff --git a/gyp/test/actions/src/action_missing_name.gyp b/gyp/test/actions/src/action_missing_name.gyp
new file mode 100644 (file)
index 0000000..00424c3
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'broken_actions2',
+      'type': 'none',
+      'actions': [
+        {
+          'inputs': [
+            'no_name.input',
+          ],
+          'action': [
+            'python',
+            '-c',
+            'print \'missing name\'',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/actions/src/actions.gyp b/gyp/test/actions/src/actions.gyp
new file mode 100644 (file)
index 0000000..5d2db19
--- /dev/null
@@ -0,0 +1,114 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'pull_in_all_actions',
+      'type': 'none',
+      'dependencies': [
+        'subdir1/executable.gyp:*',
+        'subdir2/none.gyp:*',
+        'subdir3/null_input.gyp:*',
+      ],
+    },
+    {
+      'target_name': 'depend_on_always_run_action',
+      'type': 'none',
+      'dependencies': [ 'subdir1/executable.gyp:counter' ],
+      'actions': [
+        {
+          'action_name': 'use_always_run_output',
+          'inputs': [
+            'subdir1/actions-out/action-counter.txt',
+            'subdir1/counter.py',
+          ],
+          'outputs': [
+            'subdir1/actions-out/action-counter_2.txt',
+          ],
+          'action': [
+            'python', 'subdir1/counter.py', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+
+    # Three deps which don't finish immediately.
+    # Each one has a small delay then creates a file.
+    # Delays are 1.0, 1.1, and 2.0 seconds.
+    {
+      'target_name': 'dep_1',
+      'type': 'none',
+      'actions': [{
+        'inputs': [ 'actions.gyp' ],
+        'outputs': [ 'dep_1.txt' ],
+        'action_name': 'dep_1',
+        'action': [ 'python', '-c',
+                    'import time; time.sleep(1); open(\'dep_1.txt\', \'w\')' ],
+        # Allows the test to run without hermetic cygwin on windows.
+        'msvs_cygwin_shell': 0,
+      }],
+    },
+    {
+      'target_name': 'dep_2',
+      'type': 'none',
+      'actions': [{
+        'inputs': [ 'actions.gyp' ],
+        'outputs': [ 'dep_2.txt' ],
+        'action_name': 'dep_2',
+        'action': [ 'python', '-c',
+                    'import time; time.sleep(1.1); open(\'dep_2.txt\', \'w\')' ],
+        # Allows the test to run without hermetic cygwin on windows.
+        'msvs_cygwin_shell': 0,
+      }],
+    },
+    {
+      'target_name': 'dep_3',
+      'type': 'none',
+      'actions': [{
+        'inputs': [ 'actions.gyp' ],
+        'outputs': [ 'dep_3.txt' ],
+        'action_name': 'dep_3',
+        'action': [ 'python', '-c',
+                    'import time; time.sleep(2.0); open(\'dep_3.txt\', \'w\')' ],
+        # Allows the test to run without hermetic cygwin on windows.
+        'msvs_cygwin_shell': 0,
+      }],
+    },
+
+    # An action which assumes the deps have completed.
+    # Does NOT list the output files of it's deps as inputs.
+    # On success create the file deps_all_done_first.txt.
+    {
+      'target_name': 'action_with_dependencies_123',
+      'type': 'none',
+      'dependencies': [ 'dep_1', 'dep_2', 'dep_3' ],
+      'actions': [{
+        'inputs': [ 'actions.gyp' ],
+        'outputs': [ 'deps_all_done_first_123.txt' ],
+        'action_name': 'action_with_dependencies_123',
+        'action': [ 'python', 'confirm-dep-files.py', '<(_outputs)' ],
+        # Allows the test to run without hermetic cygwin on windows.
+        'msvs_cygwin_shell': 0,
+      }],
+    },
+    # Same as above but with deps in reverse.
+    {
+      'target_name': 'action_with_dependencies_321',
+      'type': 'none',
+      'dependencies': [ 'dep_3', 'dep_2', 'dep_1' ],
+      'actions': [{
+        'inputs': [ 'actions.gyp' ],
+        'outputs': [ 'deps_all_done_first_321.txt' ],
+        'action_name': 'action_with_dependencies_321',
+        'action': [ 'python', 'confirm-dep-files.py', '<(_outputs)' ],
+        # Allows the test to run without hermetic cygwin on windows.
+        'msvs_cygwin_shell': 0,
+      }],
+    },
+
+  ],
+}
diff --git a/gyp/test/actions/src/confirm-dep-files.py b/gyp/test/actions/src/confirm-dep-files.py
new file mode 100755 (executable)
index 0000000..3b84630
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Confirms presence of files generated by our targets we depend on.
+If they exist, create a new file.
+
+Note target's input files are explicitly NOT defined in the gyp file
+so they can't easily be passed to this script as args.
+"""
+
+import os
+import sys
+
+outfile = sys.argv[1]  # Example value we expect: deps_all_done_first_123.txt
+if (os.path.exists("dep_1.txt") and
+    os.path.exists("dep_2.txt") and
+    os.path.exists("dep_3.txt")):
+  open(outfile, "w")
diff --git a/gyp/test/actions/src/subdir1/counter.py b/gyp/test/actions/src/subdir1/counter.py
new file mode 100755 (executable)
index 0000000..d888f2e
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+import time
+
+output = sys.argv[1]
+persistoutput = "%s.persist" % sys.argv[1]
+
+count = 0
+try:
+  count = open(persistoutput, 'r').read()
+except:
+  pass
+count = int(count) + 1
+
+if len(sys.argv) > 2:
+  max_count = int(sys.argv[2])
+  if count > max_count:
+    count = max_count
+
+oldcount = 0
+try:
+  oldcount = open(output, 'r').read()
+except:
+  pass
+
+# Save the count in a file that is undeclared, and thus hidden, to gyp. We need
+# to do this because, prior to running commands, some build systems deletes
+# any declared outputs, so we would lose our count if we just wrote to the
+# given output file.
+open(persistoutput, 'w').write('%d' % (count))
+
+# Only write the given output file if the count has changed.
+if int(oldcount) != count:
+  open(output, 'w').write('%d' % (count))
+  # Sleep so the next run changes the file time sufficiently to make the build
+  # detect the file as changed.
+  time.sleep(1)
+
+sys.exit(0)
diff --git a/gyp/test/actions/src/subdir1/executable.gyp b/gyp/test/actions/src/subdir1/executable.gyp
new file mode 100644 (file)
index 0000000..6a1ce4f
--- /dev/null
@@ -0,0 +1,74 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'program.c',
+      ],
+      'actions': [
+        {
+          'action_name': 'make-prog1',
+          'inputs': [
+            'make-prog1.py',
+          ],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/prog1.c',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+        {
+          'action_name': 'make-prog2',
+          'inputs': [
+            'make-prog2.py',
+          ],
+          'outputs': [
+            'actions-out/prog2.c',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+    {
+      'target_name': 'counter',
+      'type': 'none',
+      'actions': [
+        {
+          # This action should always run, regardless of whether or not it's
+          # inputs or the command-line change. We do this by creating a dummy
+          # first output, which is always missing, thus causing the build to
+          # always try to recreate it. Actual output files should be listed
+          # after the dummy one, and dependent targets should list the real
+          # output(s) in their inputs
+          # (see '../actions.gyp:depend_on_always_run_action').
+          'action_name': 'action_counter',
+          'inputs': [
+            'counter.py',
+          ],
+          'outputs': [
+            'actions-out/action-counter.txt.always',
+            'actions-out/action-counter.txt',
+          ],
+          'action': [
+            'python', '<(_inputs)', 'actions-out/action-counter.txt', '2',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/actions/src/subdir1/make-prog1.py b/gyp/test/actions/src/subdir1/make-prog1.py
new file mode 100755 (executable)
index 0000000..7ea1d8a
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = r"""
+#include <stdio.h>
+
+void prog1(void)
+{
+  printf("Hello from make-prog1.py\n");
+}
+"""
+
+open(sys.argv[1], 'w').write(contents)
+
+sys.exit(0)
diff --git a/gyp/test/actions/src/subdir1/make-prog2.py b/gyp/test/actions/src/subdir1/make-prog2.py
new file mode 100755 (executable)
index 0000000..0bfe497
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = r"""
+#include <stdio.h>
+
+void prog2(void)
+{
+  printf("Hello from make-prog2.py\n");
+}
+"""
+
+open(sys.argv[1], 'w').write(contents)
+
+sys.exit(0)
diff --git a/gyp/test/actions/src/subdir1/program.c b/gyp/test/actions/src/subdir1/program.c
new file mode 100644 (file)
index 0000000..c093153
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>\r
+\r
+extern void prog1(void);\r
+extern void prog2(void);\r
+\r
+int main(void)
+{\r
+  printf("Hello from program.c\n");\r
+  prog1();\r
+  prog2();\r
+  return 0;\r
+}\r
diff --git a/gyp/test/actions/src/subdir2/make-file.py b/gyp/test/actions/src/subdir2/make-file.py
new file mode 100755 (executable)
index 0000000..fff0653
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = "Hello from make-file.py\n"
+
+open(sys.argv[1], 'wb').write(contents)
diff --git a/gyp/test/actions/src/subdir2/none.gyp b/gyp/test/actions/src/subdir2/none.gyp
new file mode 100644 (file)
index 0000000..2caa97d
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'file',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'actions': [
+        {
+          'action_name': 'make-file',
+          'inputs': [
+            'make-file.py',
+          ],
+          'outputs': [
+            'file.out',
+            # TODO:  enhance testing infrastructure to test this
+            # without having to hard-code the intermediate dir paths.
+            #'<(INTERMEDIATE_DIR)/file.out',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        }
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/actions/src/subdir3/generate_main.py b/gyp/test/actions/src/subdir3/generate_main.py
new file mode 100755 (executable)
index 0000000..804d38d
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = """
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from generate_main.py\\n");
+  return 0;
+}
+"""
+
+open(sys.argv[1], 'w').write(contents)
+
+sys.exit(0)
diff --git a/gyp/test/actions/src/subdir3/null_input.gyp b/gyp/test/actions/src/subdir3/null_input.gyp
new file mode 100644 (file)
index 0000000..9b0bea5
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'null_input',
+      'type': 'executable',
+      'msvs_cygwin_shell': 0,
+      'actions': [
+        {
+          'action_name': 'generate_main',
+          'process_outputs_as_sources': 1,
+          'inputs': [],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/main.c',
+          ],
+          'action': [
+            # TODO:  we can't just use <(_outputs) here?!
+            'python', 'generate_main.py', '<(INTERMEDIATE_DIR)/main.c',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/additional-targets/gyptest-additional.py b/gyp/test/additional-targets/gyptest-additional.py
new file mode 100755 (executable)
index 0000000..a9bd402
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple actions when using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('all.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+
+# Build all.
+test.build('all.gyp', chdir='relocate/src')
+
+if test.format=='xcode':
+  chdir = 'relocate/src/dir1'
+else:
+  chdir = 'relocate/src'
+
+# Output is as expected.
+file_content = 'Hello from emit.py\n'
+test.built_file_must_match('out2.txt', file_content, chdir=chdir)
+
+test.built_file_must_not_exist('out.txt', chdir='relocate/src')
+test.built_file_must_not_exist('foolib1',
+                               type=test.SHARED_LIB,
+                               chdir=chdir)
+
+# TODO(mmoss) Make consistent with msvs, with 'dir1' before 'out/Default'?
+if test.format in ('make', 'ninja', 'android', 'cmake'):
+  chdir='relocate/src'
+else:
+  chdir='relocate/src/dir1'
+
+# Build the action explicitly.
+test.build('actions.gyp', 'action1_target', chdir=chdir)
+
+# Check that things got run.
+file_content = 'Hello from emit.py\n'
+test.built_file_must_exist('out.txt', chdir=chdir)
+
+# Build the shared library explicitly.
+test.build('actions.gyp', 'foolib1', chdir=chdir)
+
+test.built_file_must_exist('foolib1',
+                           type=test.SHARED_LIB,
+                           chdir=chdir,
+                           subdir='dir1')
+
+test.pass_test()
diff --git a/gyp/test/additional-targets/src/all.gyp b/gyp/test/additional-targets/src/all.gyp
new file mode 100644 (file)
index 0000000..21c8308
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'all_targets',
+      'type': 'none',
+      'dependencies': ['dir1/actions.gyp:*'],
+    },
+  ],
+}
diff --git a/gyp/test/additional-targets/src/dir1/actions.gyp b/gyp/test/additional-targets/src/dir1/actions.gyp
new file mode 100644 (file)
index 0000000..5089c80
--- /dev/null
@@ -0,0 +1,56 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'action1_target',
+      'type': 'none',
+      'suppress_wildcard': 1,
+      'actions': [
+        {
+          'action_name': 'action1',
+          'inputs': [
+            'emit.py',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/out.txt',
+          ],
+          'action': ['python', 'emit.py', '<(PRODUCT_DIR)/out.txt'],
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+    {
+      'target_name': 'action2_target',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'action2',
+          'inputs': [
+            'emit.py',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/out2.txt',
+          ],
+          'action': ['python', 'emit.py', '<(PRODUCT_DIR)/out2.txt'],
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+    {
+      'target_name': 'foolib1',
+      'type': 'shared_library',
+      'suppress_wildcard': 1,
+      'sources': ['lib1.c'],
+    },
+  ],
+  'conditions': [
+    ['OS=="linux"', {
+      'target_defaults': {
+        'cflags': ['-fPIC'],
+      },
+    }],
+  ],
+}
diff --git a/gyp/test/additional-targets/src/dir1/emit.py b/gyp/test/additional-targets/src/dir1/emit.py
new file mode 100755 (executable)
index 0000000..fd31387
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+f = open(sys.argv[1], 'wb')
+f.write('Hello from emit.py\n')
+f.close()
diff --git a/gyp/test/additional-targets/src/dir1/lib1.c b/gyp/test/additional-targets/src/dir1/lib1.c
new file mode 100644 (file)
index 0000000..df4cb10
--- /dev/null
@@ -0,0 +1,6 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int func1(void) {
+  return 42;
+}
diff --git a/gyp/test/analyzer/common.gypi b/gyp/test/analyzer/common.gypi
new file mode 100644 (file)
index 0000000..7c664e4
--- /dev/null
@@ -0,0 +1,6 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+}
diff --git a/gyp/test/analyzer/gyptest-analyzer.new.py b/gyp/test/analyzer/gyptest-analyzer.new.py
new file mode 100644 (file)
index 0000000..b736867
--- /dev/null
@@ -0,0 +1,229 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for analyzer
+"""
+
+import json
+import TestGyp
+
+# TODO(sky): when done migrating recipes rename to gyptest-analyzer and nuke
+# existing gyptest-analyzer.
+
+found = 'Found dependency'
+not_found = 'No dependencies'
+
+def _CreateTestFile(files, targets):
+  f = open('test_file', 'w')
+  to_write = {'files': files, 'targets': targets }
+  json.dump(to_write, f)
+  f.close()
+
+def _CreateBogusTestFile():
+  f = open('test_file','w')
+  f.write('bogus')
+  f.close()
+
+def _ReadOutputFileContents():
+  f = open('analyzer_output', 'r')
+  result = json.load(f)
+  f.close()
+  return result
+
+# NOTE: this would be clearer if it subclassed TestGypCustom, but that trips
+# over a bug in pylint (E1002).
+test = TestGyp.TestGypCustom(format='analyzer')
+
+def run_analyzer(*args, **kw):
+  """Runs the test specifying a particular config and output path."""
+  args += ('-Gconfig_path=test_file',
+           '-Ganalyzer_output_path=analyzer_output')
+  test.run_gyp('test.gyp', *args, **kw)
+
+def run_analyzer2(*args, **kw):
+  """Runs the test specifying a particular config and output path."""
+  args += ('-Gconfig_path=test_file',
+           '-Ganalyzer_output_path=analyzer_output')
+  test.run_gyp('test2.gyp', *args, **kw)
+
+def EnsureContains(targets=set(), matched=False):
+  """Verifies output contains |targets|."""
+  result = _ReadOutputFileContents()
+  if result.get('error', None):
+    print 'unexpected error', result.get('error')
+    test.fail_test()
+
+  if result.get('warning', None):
+    print 'unexpected warning', result.get('warning')
+    test.fail_test()
+
+  actual_targets = set(result['targets'])
+  if actual_targets != targets:
+    print 'actual targets:', actual_targets, '\nexpected targets:', targets
+    test.fail_test()
+
+  if matched and result['status'] != found:
+    print 'expected', found, 'got', result['status']
+    test.fail_test()
+  elif not matched and result['status'] != not_found:
+    print 'expected', not_found, 'got', result['status']
+    test.fail_test()
+
+def EnsureError(expected_error_string):
+  """Verifies output contains the error string."""
+  result = _ReadOutputFileContents()
+  if result.get('error', '').find(expected_error_string) == -1:
+    print 'actual error:', result.get('error', ''), '\nexpected error:', \
+        expected_error_string
+    test.fail_test()
+
+def EnsureWarning(expected_warning_string):
+  """Verifies output contains the warning string."""
+  result = _ReadOutputFileContents()
+  if result.get('warning', '').find(expected_warning_string) == -1:
+    print 'actual warning:', result.get('warning', ''), \
+        '\nexpected warning:', expected_warning_string
+    test.fail_test()
+
+# Verifies file_path must be specified.
+test.run_gyp('test.gyp',
+             stdout='Must specify files to analyze via file_path generator '
+             'flag\n')
+
+# Verifies config_path must point to a valid file.
+test.run_gyp('test.gyp', '-Gconfig_path=bogus_file',
+             '-Ganalyzer_output_path=analyzer_output')
+EnsureError('Unable to open file bogus_file')
+
+# Verify get error when bad target is specified.
+_CreateTestFile(['exe2.c'], ['bad_target'])
+run_analyzer()
+EnsureWarning('Unable to find all targets')
+
+# Verifies config_path must point to a valid json file.
+_CreateBogusTestFile()
+run_analyzer()
+EnsureError('Unable to parse config file test_file')
+
+# Trivial test of a source.
+_CreateTestFile(['foo.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Conditional source that is excluded.
+_CreateTestFile(['conditional_source.c'], [])
+run_analyzer()
+EnsureContains(matched=False)
+
+# Conditional source that is included by way of argument.
+_CreateTestFile(['conditional_source.c'], [])
+run_analyzer('-Dtest_variable=1')
+EnsureContains(matched=True)
+
+# Two unknown files.
+_CreateTestFile(['unknown1.c', 'unoknow2.cc'], [])
+run_analyzer()
+EnsureContains()
+
+# Two unknown files.
+_CreateTestFile(['unknown1.c', 'subdir/subdir_sourcex.c'], [])
+run_analyzer()
+EnsureContains()
+
+# Included dependency
+_CreateTestFile(['unknown1.c', 'subdir/subdir_source.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Included inputs to actions.
+_CreateTestFile(['action_input.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Don't consider outputs.
+_CreateTestFile(['action_output.c'], [])
+run_analyzer()
+EnsureContains(matched=False)
+
+# Rule inputs.
+_CreateTestFile(['rule_input.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Ignore path specified with PRODUCT_DIR.
+_CreateTestFile(['product_dir_input.c'], [])
+run_analyzer()
+EnsureContains(matched=False)
+
+# Path specified via a variable.
+_CreateTestFile(['subdir/subdir_source2.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Verifies paths with // are fixed up correctly.
+_CreateTestFile(['parent_source.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Verifies relative paths are resolved correctly.
+_CreateTestFile(['subdir/subdir_source.h'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Various permutations when passing in targets.
+_CreateTestFile(['exe2.c', 'subdir/subdir2b_source.c'], ['exe', 'exe3'])
+run_analyzer()
+EnsureContains(matched=True, targets={'exe3'})
+
+_CreateTestFile(['exe2.c', 'subdir/subdir2b_source.c'], ['exe'])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Verifies duplicates are ignored.
+_CreateTestFile(['exe2.c', 'subdir/subdir2b_source.c'], ['exe', 'exe'])
+run_analyzer()
+EnsureContains(matched=True)
+
+_CreateTestFile(['exe2.c'], ['exe'])
+run_analyzer()
+EnsureContains(matched=True)
+
+_CreateTestFile(['exe2.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+_CreateTestFile(['subdir/subdir2b_source.c', 'exe2.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+_CreateTestFile(['exe2.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Assertions when modifying build (gyp/gypi) files, especially when said files
+# are included.
+_CreateTestFile(['subdir2/d.cc'], ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, targets={'exe', 'foo'})
+
+_CreateTestFile(['subdir2/subdir.includes.gypi'],
+                ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, targets={'exe', 'foo'})
+
+_CreateTestFile(['subdir2/subdir.gyp'], ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, targets={'exe', 'foo'})
+
+_CreateTestFile(['test2.includes.gypi'], ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, targets={'exe', 'exe2', 'exe3'})
+
+# Verify modifying a file included makes all targets dirty.
+_CreateTestFile(['common.gypi'], ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2('-Icommon.gypi')
+EnsureContains(matched=True, targets={'exe', 'foo', 'exe2', 'exe3'})
+
+test.pass_test()
diff --git a/gyp/test/analyzer/gyptest-analyzer.py b/gyp/test/analyzer/gyptest-analyzer.py
new file mode 100644 (file)
index 0000000..e374627
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for analyzer
+"""
+
+import TestGyp
+
+found = 'Found dependency\n'
+not_found = 'No dependencies\n'
+
+def __CreateTestFile(files):
+  f = open('test_file', 'w')
+  for file in files:
+    f.write(file + '\n')
+  f.close()
+
+test = TestGyp.TestGypCustom(format='analyzer')
+
+# Verifies file_path must be specified.
+test.run_gyp('test.gyp',
+             stdout='Must specify files to analyze via file_path generator '
+             'flag\n')
+
+# Trivial test of a source.
+__CreateTestFile(['foo.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=found)
+
+# Conditional source that is excluded.
+__CreateTestFile(['conditional_source.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=not_found)
+
+# Conditional source that is included by way of argument.
+__CreateTestFile(['conditional_source.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', '-Dtest_variable=1',
+             stdout=found)
+
+# Two unknown files.
+__CreateTestFile(['unknown1.c', 'unoknow2.cc'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=not_found)
+
+# Two unknown files.
+__CreateTestFile(['unknown1.c', 'subdir/subdir_sourcex.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=not_found)
+
+# Included dependency
+__CreateTestFile(['unknown1.c', 'subdir/subdir_source.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=found)
+
+# Included inputs to actions.
+__CreateTestFile(['action_input.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=found)
+
+# Don't consider outputs.
+__CreateTestFile(['action_output.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=not_found)
+
+# Rule inputs.
+__CreateTestFile(['rule_input.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=found)
+
+# Ignore patch specified with PRODUCT_DIR.
+__CreateTestFile(['product_dir_input.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=not_found)
+
+# Path specified via a variable.
+__CreateTestFile(['subdir/subdir_source2.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=found)
+
+# Verifies paths with // are fixed up correctly.
+__CreateTestFile(['parent_source.c'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=found)
+
+# Verifies relative paths are resolved correctly.
+__CreateTestFile(['subdir/subdir_source.h'])
+test.run_gyp('test.gyp', '-Gfile_path=test_file', stdout=found)
+
+test.pass_test()
diff --git a/gyp/test/analyzer/subdir/subdir.gyp b/gyp/test/analyzer/subdir/subdir.gyp
new file mode 100644 (file)
index 0000000..bfa2df4
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'trailing_dir_path': '../',
+   },
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'static_library',
+      'sources': [
+        'subdir_source.c',
+        '<(trailing_dir_path)/parent_source.c',
+      ],
+    },
+    {
+      'target_name': 'subdir2a',
+      'type': 'static_library',
+      'sources': [
+        'subdir2_source.c',
+      ],
+      'dependencies': [
+        'subdir2b',
+      ],
+    },
+    {
+      'target_name': 'subdir2b',
+      'type': 'static_library',
+      'sources': [
+        'subdir2b_source.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/analyzer/subdir/subdir2/subdir2.gyp b/gyp/test/analyzer/subdir/subdir2/subdir2.gyp
new file mode 100644 (file)
index 0000000..e5aaa92
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'subdir2',
+      'type': 'static_library',
+      'sources': [
+        '../subdir_source.h',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/analyzer/subdir2/subdir.gyp b/gyp/test/analyzer/subdir2/subdir.gyp
new file mode 100644 (file)
index 0000000..d6c709c
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'static_library',
+      'sources': [
+        'subdir_source.c',
+      ],
+      'includes': [
+        'subdir.includes.gypi',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/analyzer/subdir2/subdir.includes.gypi b/gyp/test/analyzer/subdir2/subdir.includes.gypi
new file mode 100644 (file)
index 0000000..324e92b
--- /dev/null
@@ -0,0 +1,9 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'sources': [
+    'd.cc'
+  ],
+}
diff --git a/gyp/test/analyzer/test.gyp b/gyp/test/analyzer/test.gyp
new file mode 100644 (file)
index 0000000..afc312b
--- /dev/null
@@ -0,0 +1,83 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'test_variable%': 0,
+    'variable_path': 'subdir',
+   },
+  'targets': [
+    {
+      'target_name': 'exe',
+      'type': 'executable',
+      'dependencies': [
+        'subdir/subdir.gyp:foo',
+        'subdir/subdir2/subdir2.gyp:subdir2',
+      ],
+      'sources': [
+        'foo.c',
+        '<(variable_path)/subdir_source2.c',
+      ],
+      'conditions': [
+        ['test_variable==1', {
+          'sources': [
+            'conditional_source.c',
+          ],
+        }],
+      ],
+      'actions': [
+        {
+          'action_name': 'action',
+          'inputs': [
+            '<(PRODUCT_DIR)/product_dir_input.c',
+            'action_input.c',
+            '../bad_path1.h',
+            '../../bad_path2.h',
+          ],
+          'outputs': [
+            'action_output.c',
+          ],
+        },
+      ],
+      'rules': [
+        {
+          'rule_name': 'rule',
+          'extension': 'pdf',
+          'inputs': [
+            'rule_input.c',
+          ],
+          'outputs': [
+            'rule_output.pdf',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'exe2',
+      'type': 'executable',
+      'sources': [
+        'exe2.c',
+      ],
+    },
+    {
+      'target_name': 'exe3',
+      'type': 'executable',
+      'dependencies': [
+        'subdir/subdir.gyp:foo',
+        'subdir/subdir.gyp:subdir2a',
+      ],
+      'sources': [
+        'exe3.c',
+      ],
+    },
+    {
+      'target_name': 'all',
+      'type': 'executable',
+      'dependencies': [
+        'exe',
+        'exe3',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/analyzer/test2.gyp b/gyp/test/analyzer/test2.gyp
new file mode 100644 (file)
index 0000000..782b6e6
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'exe',
+      'type': 'executable',
+      'dependencies': [
+        'subdir2/subdir.gyp:foo',
+      ],
+    },
+    {
+      'target_name': 'exe2',
+      'type': 'executable',
+      'includes': [
+        'test2.includes.gypi',
+      ],
+    },
+  ],
+  'includes': [
+    'test2.toplevel_includes.gypi',
+  ],
+}
diff --git a/gyp/test/analyzer/test2.includes.gypi b/gyp/test/analyzer/test2.includes.gypi
new file mode 100644 (file)
index 0000000..3e21de2
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'sources': [
+    'a.cc',
+    'b.cc'
+  ],
+  'includes': [
+    'test2.includes.includes.gypi',
+  ],
+}
diff --git a/gyp/test/analyzer/test2.includes.includes.gypi b/gyp/test/analyzer/test2.includes.includes.gypi
new file mode 100644 (file)
index 0000000..de3a025
--- /dev/null
@@ -0,0 +1,9 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'sources': [
+    'c.cc'
+  ],
+}
diff --git a/gyp/test/analyzer/test2.toplevel_includes.gypi b/gyp/test/analyzer/test2.toplevel_includes.gypi
new file mode 100644 (file)
index 0000000..54fa453
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'exe3',
+      'type': 'executable',
+      'sources': [
+        'e.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/android/file.in b/gyp/test/android/file.in
new file mode 100644 (file)
index 0000000..68016f0
--- /dev/null
@@ -0,0 +1 @@
+A boring test file
diff --git a/gyp/test/android/gyptest-make-functions.py b/gyp/test/android/gyptest-make-functions.py
new file mode 100755 (executable)
index 0000000..cdf0e0e
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that it's possible for gyp actions to use the result of calling a make
+function with "$()".
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['android'])
+
+test.run_gyp('make_functions.gyp')
+
+test.build('make_functions.gyp', test.ALL)
+
+file_content = 'A boring test file\n'
+test.built_file_must_match('file.in', file_content)
+test.built_file_must_match('file.out', file_content)
+
+test.pass_test()
diff --git a/gyp/test/android/gyptest-noalias.py b/gyp/test/android/gyptest-noalias.py
new file mode 100755 (executable)
index 0000000..4840c4c
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that disabling target aliases works.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['android'])
+
+test.run_gyp('hello.gyp', '-G', 'write_alias_targets=0')
+
+test.build('hello.gyp', 'hello', status=2, stderr=None)
+
+test.build('hello.gyp', 'gyp_all_modules', status=2, stderr=None)
+
+test.pass_test()
diff --git a/gyp/test/android/gyptest-space-filenames.py b/gyp/test/android/gyptest-space-filenames.py
new file mode 100755 (executable)
index 0000000..c6caf26
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that action input/output filenames with spaces are rejected.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['android'])
+
+stderr = ('gyp: Action input filename "name with spaces" in target do_actions '
+          'contains a space\n')
+test.run_gyp('space_filenames.gyp', status=1, stderr=stderr)
+
+test.pass_test()
diff --git a/gyp/test/android/hello.c b/gyp/test/android/hello.c
new file mode 100644 (file)
index 0000000..e6bf622
--- /dev/null
@@ -0,0 +1,12 @@
+/* Copyright (c) 2014 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+int main()
+{
+  printf("Hello, world!\n");
+  return 0;
+}
diff --git a/gyp/test/android/hello.gyp b/gyp/test/android/hello.gyp
new file mode 100644 (file)
index 0000000..da58a2b
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/android/make_functions.gyp b/gyp/test/android/make_functions.gyp
new file mode 100644 (file)
index 0000000..4b617cc
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'file-in',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)',
+          'files': [ 'file.in' ],
+        },
+      ],
+    },
+    {
+      'target_name': 'file-out',
+      'type': 'none',
+      'dependencies': [ 'file-in' ],
+      'actions': [
+        {
+          'action_name': 'copy-file',
+          'inputs': [ '$(strip <(PRODUCT_DIR)/file.in)' ],
+          'outputs': [ '<(PRODUCT_DIR)/file.out' ],
+          'action': [ 'cp', '$(strip <(PRODUCT_DIR)/file.in)', '<(PRODUCT_DIR)/file.out' ],
+        }
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/android/space_filenames.gyp b/gyp/test/android/space_filenames.gyp
new file mode 100644 (file)
index 0000000..487ac55
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'do_actions',
+      'type': 'none',
+      'actions': [{
+        'action_name': 'should_be_forbidden',
+        'inputs': [ 'name with spaces' ],
+        'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/name with spaces' ],
+        'action': [ 'true' ],
+      }],
+    },
+  ],
+}
diff --git a/gyp/test/assembly/gyptest-assembly.py b/gyp/test/assembly/gyptest-assembly.py
new file mode 100755 (executable)
index 0000000..8a84310
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+A basic test of compiling assembler files.
+"""
+
+import sys
+import TestGyp
+
+if sys.platform != 'win32':
+  # TODO(bradnelson): get this working for windows.
+  test = TestGyp.TestGyp(formats=['!msvs'])
+
+  test.run_gyp('assembly.gyp', chdir='src')
+
+  test.relocate('src', 'relocate/src')
+
+  test.build('assembly.gyp', test.ALL, chdir='relocate/src')
+
+  expect = """\
+Hello from program.c
+Got 42.
+"""
+  test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+  test.pass_test()
diff --git a/gyp/test/assembly/gyptest-override.py b/gyp/test/assembly/gyptest-override.py
new file mode 100644 (file)
index 0000000..e84a23e
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure that manual rules on Windows override the built in ones.
+"""
+
+import sys
+import TestGyp
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+  CHDIR = 'src'
+  test.run_gyp('override.gyp', chdir=CHDIR)
+  test.build('override.gyp', test.ALL, chdir=CHDIR)
+  expect = """\
+Hello from program.c
+Got 42.
+"""
+  test.run_built_executable('program', chdir=CHDIR, stdout=expect)
+  test.pass_test()
diff --git a/gyp/test/assembly/src/as.bat b/gyp/test/assembly/src/as.bat
new file mode 100644 (file)
index 0000000..b796db9
--- /dev/null
@@ -0,0 +1,4 @@
+@echo off
+:: Mock windows assembler.
+cl /MD /c %1 /Fo"%2"
+
diff --git a/gyp/test/assembly/src/assembly.gyp b/gyp/test/assembly/src/assembly.gyp
new file mode 100644 (file)
index 0000000..565cb0f
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'conditions': [
+      ['OS=="win"', {
+        'defines': ['PLATFORM_WIN'],
+      }],
+      ['OS=="mac" or OS=="ios"', {
+        'defines': ['PLATFORM_MAC'],
+      }],
+      ['OS=="linux"', {
+        'defines': ['PLATFORM_LINUX'],
+      }],
+      ['OS=="android"', {
+        'defines': ['PLATFORM_ANDROID'],
+      }],
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'dependencies': ['lib1'],
+      'sources': [
+        'program.c',
+      ],
+    },
+    {
+      'target_name': 'lib1',
+      'type': 'static_library',
+      'sources': [
+        'lib1.S',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="win"', {
+      'target_defaults': {
+        'rules': [
+          {
+            'rule_name': 'assembler',
+            'msvs_cygwin_shell': 0,
+            'extension': 'S',
+            'inputs': [
+              'as.bat',
+            ],
+            'outputs': [
+              '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).obj',
+            ],
+            'action':
+              ['as.bat', 'lib1.c', '<(_outputs)'],
+            'message': 'Building assembly file <(RULE_INPUT_PATH)',
+            'process_outputs_as_sources': 1,
+          },
+        ],
+      },
+    },],
+  ],
+}
diff --git a/gyp/test/assembly/src/lib1.S b/gyp/test/assembly/src/lib1.S
new file mode 100644 (file)
index 0000000..7de9f19
--- /dev/null
@@ -0,0 +1,15 @@
+#if PLATFORM_WINDOWS || PLATFORM_MAC
+# define IDENTIFIER(n)  _##n
+#else /* Linux */
+# define IDENTIFIER(n)  n
+#endif
+
+.globl IDENTIFIER(lib1_function)
+IDENTIFIER(lib1_function):
+#if !defined(PLATFORM_ANDROID)
+  movl $42, %eax
+  ret
+#else /* Android (assuming ARM) */
+  mov r0, #42
+  bx lr
+#endif
diff --git a/gyp/test/assembly/src/lib1.c b/gyp/test/assembly/src/lib1.c
new file mode 100644 (file)
index 0000000..be21ecd
--- /dev/null
@@ -0,0 +1,3 @@
+int lib1_function(void) {
+  return 42;
+}
diff --git a/gyp/test/assembly/src/override.gyp b/gyp/test/assembly/src/override.gyp
new file mode 100644 (file)
index 0000000..39a4072
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'sources': [
+        'program.c',
+        'override_asm.asm',
+      ],
+      'rules': [
+      {
+        # Test that if there's a specific .asm rule, it overrides the
+        # built in one on Windows.
+        'rule_name': 'assembler',
+        'msvs_cygwin_shell': 0,
+        'extension': 'asm',
+        'inputs': [
+          'as.bat',
+        ],
+        'outputs': [
+          'output.obj',
+        ],
+        'action': ['as.bat', 'lib1.c', '<(_outputs)'],
+        'message': 'Building assembly file <(RULE_INPUT_PATH)',
+        'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/assembly/src/override_asm.asm b/gyp/test/assembly/src/override_asm.asm
new file mode 100644 (file)
index 0000000..be93b23
--- /dev/null
@@ -0,0 +1,8 @@
+; Copyright (c) 2012 Google Inc. All rights reserved.
+; Use of this source code is governed by a BSD-style license that can be
+; found in the LICENSE file.
+
+; This is a placeholder. It should not be referenced if overrides work
+; correctly.
+
+Bad stuff that shouldn't assemble.
diff --git a/gyp/test/assembly/src/program.c b/gyp/test/assembly/src/program.c
new file mode 100644 (file)
index 0000000..eee8627
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern int lib1_function(void);
+
+int main(void)
+{
+  fprintf(stdout, "Hello from program.c\n");
+  fflush(stdout);
+  fprintf(stdout, "Got %d.\n", lib1_function());
+  fflush(stdout);
+  return 0;
+}
diff --git a/gyp/test/build-option/gyptest-build.py b/gyp/test/build-option/gyptest-build.py
new file mode 100755 (executable)
index 0000000..6dfadb2
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using the default build target.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_default')
+
+if test.format == 'android':
+  # This test currently fails on android. Investigate why, fix the issues
+  # responsible, and reenable this test on android. See bug:
+  # https://code.google.com/p/gyp/issues/detail?id=436
+  test.skip_test(message='Test fails on android. Fix and reenable.\n')
+
+test.run_gyp('hello.gyp', '--build=Default')
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.up_to_date('hello.gyp', test.DEFAULT)
+
+test.pass_test()
diff --git a/gyp/test/build-option/hello.c b/gyp/test/build-option/hello.c
new file mode 100644 (file)
index 0000000..f6ad129
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello, world!\n");
+  return 0;
+}
diff --git a/gyp/test/build-option/hello.gyp b/gyp/test/build-option/hello.gyp
new file mode 100644 (file)
index 0000000..1974d51
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/builddir/gyptest-all.py b/gyp/test/builddir/gyptest-all.py
new file mode 100755 (executable)
index 0000000..f7294b5
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify the settings that cause a set of programs to be created in
+a specific build directory, and that no intermediate built files
+get created outside of that build directory hierarchy even when
+referred to with deeply-nested ../../.. paths.
+"""
+
+import TestGyp
+
+# TODO(mmoss): Make only supports (theoretically) a single, global build
+# directory (through GYP_GENERATOR_FLAGS 'output_dir'), rather than
+# gyp-file-specific settings (e.g. the stuff in builddir.gypi) that the other
+# generators support, so this doesn't work yet for make.
+# TODO(mmoss) Make also has the issue that the top-level Makefile is written to
+# the "--depth" location, which is one level above 'src', but then this test
+# moves 'src' somewhere else, leaving the Makefile behind, so make can't find
+# its sources. I'm not sure if make is wrong for writing outside the current
+# directory, or if the test is wrong for assuming everything generated is under
+# the current directory.
+# Android, Ninja, and CMake do not support setting the build directory.
+test = TestGyp.TestGyp(formats=['!make', '!ninja', '!android', '!cmake'])
+
+test.run_gyp('prog1.gyp', '--depth=..', chdir='src')
+if test.format == 'msvs':
+  if test.uses_msbuild:
+    test.must_contain('src/prog1.vcxproj',
+      '<OutDir>..\\builddir\\Default\\</OutDir>')
+  else:
+    test.must_contain('src/prog1.vcproj',
+      'OutputDirectory="..\\builddir\\Default\\"')
+
+test.relocate('src', 'relocate/src')
+
+test.subdir('relocate/builddir')
+
+# Make sure that all the built ../../etc. files only get put under builddir,
+# by making all of relocate read-only and then making only builddir writable.
+test.writable('relocate', False)
+test.writable('relocate/builddir', True)
+
+# Suppress the test infrastructure's setting SYMROOT on the command line.
+test.build('prog1.gyp', test.ALL, SYMROOT=None, chdir='relocate/src')
+
+expect1 = """\
+Hello from prog1.c
+Hello from func1.c
+"""
+
+expect2 = """\
+Hello from subdir2/prog2.c
+Hello from func2.c
+"""
+
+expect3 = """\
+Hello from subdir2/subdir3/prog3.c
+Hello from func3.c
+"""
+
+expect4 = """\
+Hello from subdir2/subdir3/subdir4/prog4.c
+Hello from func4.c
+"""
+
+expect5 = """\
+Hello from subdir2/subdir3/subdir4/subdir5/prog5.c
+Hello from func5.c
+"""
+
+def run_builddir(prog, expect):
+  dir = 'relocate/builddir/Default/'
+  test.run(program=test.workpath(dir + prog), stdout=expect)
+
+run_builddir('prog1', expect1)
+run_builddir('prog2', expect2)
+run_builddir('prog3', expect3)
+run_builddir('prog4', expect4)
+run_builddir('prog5', expect5)
+
+test.pass_test()
diff --git a/gyp/test/builddir/gyptest-default.py b/gyp/test/builddir/gyptest-default.py
new file mode 100755 (executable)
index 0000000..1b47443
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify the settings that cause a set of programs to be created in
+a specific build directory, and that no intermediate built files
+get created outside of that build directory hierarchy even when
+referred to with deeply-nested ../../.. paths.
+"""
+
+import TestGyp
+
+# TODO(mmoss): Make only supports (theoretically) a single, global build
+# directory (through GYP_GENERATOR_FLAGS 'output_dir'), rather than
+# gyp-file-specific settings (e.g. the stuff in builddir.gypi) that the other
+# generators support, so this doesn't work yet for make.
+# TODO(mmoss) Make also has the issue that the top-level Makefile is written to
+# the "--depth" location, which is one level above 'src', but then this test
+# moves 'src' somewhere else, leaving the Makefile behind, so make can't find
+# its sources. I'm not sure if make is wrong for writing outside the current
+# directory, or if the test is wrong for assuming everything generated is under
+# the current directory.
+# Android, Ninja, and CMake do not support setting the build directory.
+test = TestGyp.TestGyp(formats=['!make', '!ninja', '!android', '!cmake'])
+
+test.run_gyp('prog1.gyp', '--depth=..', chdir='src')
+if test.format == 'msvs':
+  if test.uses_msbuild:
+    test.must_contain('src/prog1.vcxproj',
+      '<OutDir>..\\builddir\\Default\\</OutDir>')
+  else:
+    test.must_contain('src/prog1.vcproj',
+      'OutputDirectory="..\\builddir\\Default\\"')
+
+test.relocate('src', 'relocate/src')
+
+test.subdir('relocate/builddir')
+
+# Make sure that all the built ../../etc. files only get put under builddir,
+# by making all of relocate read-only and then making only builddir writable.
+test.writable('relocate', False)
+test.writable('relocate/builddir', True)
+
+# Suppress the test infrastructure's setting SYMROOT on the command line.
+test.build('prog1.gyp', SYMROOT=None, chdir='relocate/src')
+
+expect1 = """\
+Hello from prog1.c
+Hello from func1.c
+"""
+
+expect2 = """\
+Hello from subdir2/prog2.c
+Hello from func2.c
+"""
+
+expect3 = """\
+Hello from subdir2/subdir3/prog3.c
+Hello from func3.c
+"""
+
+expect4 = """\
+Hello from subdir2/subdir3/subdir4/prog4.c
+Hello from func4.c
+"""
+
+expect5 = """\
+Hello from subdir2/subdir3/subdir4/subdir5/prog5.c
+Hello from func5.c
+"""
+
+def run_builddir(prog, expect):
+  dir = 'relocate/builddir/Default/'
+  test.run(program=test.workpath(dir + prog), stdout=expect)
+
+run_builddir('prog1', expect1)
+run_builddir('prog2', expect2)
+run_builddir('prog3', expect3)
+run_builddir('prog4', expect4)
+run_builddir('prog5', expect5)
+
+test.pass_test()
diff --git a/gyp/test/builddir/src/builddir.gypi b/gyp/test/builddir/src/builddir.gypi
new file mode 100644 (file)
index 0000000..ce175db
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'configurations': {
+      'Default': {
+        'msvs_configuration_attributes': {
+          'OutputDirectory': '<(DEPTH)\\builddir/Default',
+        },
+      },
+    },
+  },
+  'xcode_settings': {
+    'SYMROOT': '<(DEPTH)/builddir',
+  },
+}
diff --git a/gyp/test/builddir/src/func1.c b/gyp/test/builddir/src/func1.c
new file mode 100644 (file)
index 0000000..b8e6a06
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func1(void)
+{
+  printf("Hello from func1.c\n");
+}
diff --git a/gyp/test/builddir/src/func2.c b/gyp/test/builddir/src/func2.c
new file mode 100644 (file)
index 0000000..14aabac
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func2(void)
+{
+  printf("Hello from func2.c\n");
+}
diff --git a/gyp/test/builddir/src/func3.c b/gyp/test/builddir/src/func3.c
new file mode 100644 (file)
index 0000000..3b4edea
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func3(void)
+{
+  printf("Hello from func3.c\n");
+}
diff --git a/gyp/test/builddir/src/func4.c b/gyp/test/builddir/src/func4.c
new file mode 100644 (file)
index 0000000..732891b
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func4(void)
+{
+  printf("Hello from func4.c\n");
+}
diff --git a/gyp/test/builddir/src/func5.c b/gyp/test/builddir/src/func5.c
new file mode 100644 (file)
index 0000000..18fdfab
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func5(void)
+{
+  printf("Hello from func5.c\n");
+}
diff --git a/gyp/test/builddir/src/prog1.c b/gyp/test/builddir/src/prog1.c
new file mode 100644 (file)
index 0000000..a32aaf0
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void func1(void);
+
+int main(void)
+{
+  printf("Hello from prog1.c\n");
+  func1();
+  return 0;
+}
diff --git a/gyp/test/builddir/src/prog1.gyp b/gyp/test/builddir/src/prog1.gyp
new file mode 100644 (file)
index 0000000..5b96f03
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    'builddir.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'pull_in_all',
+      'type': 'none',
+      'dependencies': [
+        'prog1',
+        'subdir2/prog2.gyp:prog2',
+        'subdir2/subdir3/prog3.gyp:prog3',
+        'subdir2/subdir3/subdir4/prog4.gyp:prog4',
+        'subdir2/subdir3/subdir4/subdir5/prog5.gyp:prog5',
+      ],
+    },
+    {
+      'target_name': 'prog1',
+      'type': 'executable',
+      'sources': [
+        'prog1.c',
+        'func1.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/builddir/src/subdir2/prog2.c b/gyp/test/builddir/src/subdir2/prog2.c
new file mode 100644 (file)
index 0000000..9d682cd
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void func2(void);
+
+int main(void)
+{
+  printf("Hello from subdir2/prog2.c\n");
+  func2();
+  return 0;
+}
diff --git a/gyp/test/builddir/src/subdir2/prog2.gyp b/gyp/test/builddir/src/subdir2/prog2.gyp
new file mode 100644 (file)
index 0000000..96299b6
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../builddir.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'prog2',
+      'type': 'executable',
+      'sources': [
+        'prog2.c',
+        '../func2.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/builddir/src/subdir2/subdir3/prog3.c b/gyp/test/builddir/src/subdir2/subdir3/prog3.c
new file mode 100644 (file)
index 0000000..da74965
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void func3(void);
+
+int main(void)
+{
+  printf("Hello from subdir2/subdir3/prog3.c\n");
+  func3();
+  return 0;
+}
diff --git a/gyp/test/builddir/src/subdir2/subdir3/prog3.gyp b/gyp/test/builddir/src/subdir2/subdir3/prog3.gyp
new file mode 100644 (file)
index 0000000..d7df43c
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../../builddir.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'prog3',
+      'type': 'executable',
+      'sources': [
+        'prog3.c',
+        '../../func3.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c b/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c
new file mode 100644 (file)
index 0000000..5787d5f
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void func4(void);
+
+int main(void)
+{
+  printf("Hello from subdir2/subdir3/subdir4/prog4.c\n");
+  func4();
+  return 0;
+}
diff --git a/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.gyp b/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.gyp
new file mode 100644 (file)
index 0000000..862a8a1
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../../../builddir.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'prog4',
+      'type': 'executable',
+      'sources': [
+        'prog4.c',
+        '../../../func4.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c b/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c
new file mode 100644 (file)
index 0000000..c6e2ab5
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void func5(void);
+
+int main(void)
+{
+  printf("Hello from subdir2/subdir3/subdir4/subdir5/prog5.c\n");
+  func5();
+  return 0;
+}
diff --git a/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.gyp b/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.gyp
new file mode 100644 (file)
index 0000000..fe1c9cb
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../../../../builddir.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'prog5',
+      'type': 'executable',
+      'sources': [
+        'prog5.c',
+        '../../../../func5.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/cflags/cflags.c b/gyp/test/cflags/cflags.c
new file mode 100644 (file)
index 0000000..0a02ba9
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (c) 2010 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(void)
+{
+#ifdef FOO
+  printf("FOO defined\n");
+#else
+  printf("FOO not defined\n");
+#endif
+  return 0;
+}
diff --git a/gyp/test/cflags/cflags.gyp b/gyp/test/cflags/cflags.gyp
new file mode 100644 (file)
index 0000000..2840dc6
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'cflags',
+      'type': 'executable',
+      'sources': [
+        'cflags.c',
+      ],
+    },
+    {
+      'target_name': 'cflags_host',
+      'toolsets': ['host'],
+      'type': 'executable',
+      'sources': [
+        'cflags.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/cflags/gyptest-cflags.py b/gyp/test/cflags/gyptest-cflags.py
new file mode 100755 (executable)
index 0000000..0a87ed8
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies the use of the environment during regeneration when the gyp file
+changes, specifically via build of an executable with C preprocessor
+definition specified by CFLAGS.
+
+In this test, gyp and build both run in same local environment.
+"""
+
+import TestGyp
+
+# CPPFLAGS works in ninja but not make; CFLAGS works in both
+FORMATS = ('make', 'ninja')
+
+test = TestGyp.TestGyp(formats=FORMATS)
+
+# First set CFLAGS to blank in case the platform doesn't support unsetenv.
+with TestGyp.LocalEnv({'CFLAGS': '',
+                       'GYP_CROSSCOMPILE': '1'}):
+  test.run_gyp('cflags.gyp')
+  test.build('cflags.gyp')
+
+expect = """FOO not defined\n"""
+test.run_built_executable('cflags', stdout=expect)
+test.run_built_executable('cflags_host', stdout=expect)
+
+test.sleep()
+
+with TestGyp.LocalEnv({'CFLAGS': '-DFOO=1',
+                       'GYP_CROSSCOMPILE': '1'}):
+  test.run_gyp('cflags.gyp')
+  test.build('cflags.gyp')
+
+expect = """FOO defined\n"""
+test.run_built_executable('cflags', stdout=expect)
+
+# Environment variables shouldn't influence the flags for the host.
+expect = """FOO not defined\n"""
+test.run_built_executable('cflags_host', stdout=expect)
+
+test.sleep()
+
+with TestGyp.LocalEnv({'CFLAGS': ''}):
+  test.run_gyp('cflags.gyp')
+  test.build('cflags.gyp')
+
+expect = """FOO not defined\n"""
+test.run_built_executable('cflags', stdout=expect)
+
+test.sleep()
+
+with TestGyp.LocalEnv({'CFLAGS': '-DFOO=1'}):
+  test.run_gyp('cflags.gyp')
+  test.build('cflags.gyp')
+
+expect = """FOO defined\n"""
+test.run_built_executable('cflags', stdout=expect)
+
+test.pass_test()
diff --git a/gyp/test/compilable/gyptest-headers.py b/gyp/test/compilable/gyptest-headers.py
new file mode 100755 (executable)
index 0000000..9176021
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that .hpp files are ignored when included in the source list on all
+platforms.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('headers.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('headers.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Hello from lib1.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.pass_test()
diff --git a/gyp/test/compilable/src/headers.gyp b/gyp/test/compilable/src/headers.gyp
new file mode 100644 (file)
index 0000000..b6c2a88
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'dependencies': [
+        'lib1'
+      ],
+      'sources': [
+        'program.cpp',
+      ],
+    },
+    {
+      'target_name': 'lib1',
+      'type': 'static_library',
+      'sources': [
+        'lib1.hpp',
+        'lib1.cpp',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/compilable/src/lib1.cpp b/gyp/test/compilable/src/lib1.cpp
new file mode 100644 (file)
index 0000000..51bc31a
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "lib1.hpp"
+
+void lib1_function(void) {
+  fprintf(stdout, "Hello from lib1.c\n");
+  fflush(stdout);
+}
diff --git a/gyp/test/compilable/src/lib1.hpp b/gyp/test/compilable/src/lib1.hpp
new file mode 100644 (file)
index 0000000..72e63e8
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _lib1_hpp
+#define _lib1_hpp
+
+extern void lib1_function(void);
+
+#endif
diff --git a/gyp/test/compilable/src/program.cpp b/gyp/test/compilable/src/program.cpp
new file mode 100644 (file)
index 0000000..8af2c9b
--- /dev/null
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include "lib1.hpp"
+
+int main(void) {
+  fprintf(stdout, "Hello from program.c\n");
+  fflush(stdout);
+  lib1_function();
+  return 0;
+}
diff --git a/gyp/test/compiler-override/compiler-global-settings.gyp.in b/gyp/test/compiler-override/compiler-global-settings.gyp.in
new file mode 100644 (file)
index 0000000..ca13a53
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  # PYTHON and PWD are replaced by the test code before this
+  # gyp file runs
+  'make_global_settings': [
+    ['CC', r'$PYTHON $PWD/my_cc.py FOO'],
+    ['CXX', r'$PYTHON $PWD/my_cxx.py FOO'],
+    ['CC.host', r'$PYTHON $PWD/my_cc.py BAR'],
+    ['CXX.host', r'$PYTHON $PWD/my_cxx.py BAR'],
+
+    ['LD', r'$PYTHON $PWD/my_ld.py FOO_LINK'],
+    ['LD.host', r'$PYTHON $PWD/my_ld.py BAR_LINK'],
+    ['LINK', r'$PYTHON $PWD/my_ld.py FOO_LINK'],
+    ['LINK.host', r'$PYTHON $PWD/my_ld.py BAR_LINK'],
+  ],
+
+  # The above global settings should mean that
+  # that these targets are built using the fake
+  # toolchain above.
+  'targets': [
+    {
+      'toolset': '$TOOLSET',
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'test.c',
+        'cxxtest.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/compiler-override/compiler-host.gyp b/gyp/test/compiler-override/compiler-host.gyp
new file mode 100644 (file)
index 0000000..ab3d247
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'toolset': 'host',
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'test.c',
+        'cxxtest.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/compiler-override/compiler.gyp b/gyp/test/compiler-override/compiler.gyp
new file mode 100644 (file)
index 0000000..c2f3002
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'test.c',
+        'cxxtest.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/compiler-override/cxxtest.cc b/gyp/test/compiler-override/cxxtest.cc
new file mode 100644 (file)
index 0000000..517a353
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Deliberate C syntax error as this file should never be passed to
+// the actual compiler
+#error Should not be passed to a real compiler
diff --git a/gyp/test/compiler-override/gyptest-compiler-env.py b/gyp/test/compiler-override/gyptest-compiler-env.py
new file mode 100755 (executable)
index 0000000..d13d692
--- /dev/null
@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""
+Verifies that the user can override the compiler and linker using CC/CXX/LD
+environment variables.
+"""
+
+import TestGyp
+import os
+import copy
+import sys
+
+here = os.path.dirname(os.path.abspath(__file__))
+
+if sys.platform == 'win32':
+  # cross compiling not support by ninja on windows
+  # and make not supported on windows at all.
+  sys.exit(0)
+
+# Clear any existing compiler related env vars.
+for key in ['CC', 'CXX', 'LINK', 'CC_host', 'CXX_host', 'LINK_host']:
+  if key in os.environ:
+    del os.environ[key]
+
+
+def CheckCompiler(test, gypfile, check_for, run_gyp):
+  if run_gyp:
+    test.run_gyp(gypfile)
+  test.build(gypfile)
+
+  # We can't test to presence of my_ld.py in the output since
+  # ninja will use CXX_target as the linker regardless
+  test.must_contain_all_lines(test.stdout(), check_for)
+
+
+test = TestGyp.TestGyp(formats=['ninja', 'make'])
+
+def TestTargetOveride():
+  expected = ['my_cc.py', 'my_cxx.py', 'FOO' ]
+  if test.format != 'ninja':  # ninja just uses $CC / $CXX as linker.
+    expected.append('FOO_LINK')
+
+  # Check that CC, CXX and LD set target compiler
+  oldenv = os.environ.copy()
+  try:
+    os.environ['CC'] = 'python %s/my_cc.py FOO' % here
+    os.environ['CXX'] = 'python %s/my_cxx.py FOO' % here
+    os.environ['LINK'] = 'python %s/my_ld.py FOO_LINK' % here
+
+    CheckCompiler(test, 'compiler.gyp', expected,
+                  True)
+  finally:
+    os.environ.clear()
+    os.environ.update(oldenv)
+
+  # Run the same tests once the eviron has been restored.  The
+  # generated should have embedded all the settings in the
+  # project files so the results should be the same.
+  CheckCompiler(test, 'compiler.gyp', expected,
+                False)
+
+def TestTargetOverideCompilerOnly():
+  # Same test again but with that CC, CXX and not LD
+  oldenv = os.environ.copy()
+  try:
+    os.environ['CC'] = 'python %s/my_cc.py FOO' % here
+    os.environ['CXX'] = 'python %s/my_cxx.py FOO' % here
+
+    CheckCompiler(test, 'compiler.gyp',
+                  ['my_cc.py', 'my_cxx.py', 'FOO'],
+                  True)
+  finally:
+    os.environ.clear()
+    os.environ.update(oldenv)
+
+  # Run the same tests once the eviron has been restored.  The
+  # generated should have embedded all the settings in the
+  # project files so the results should be the same.
+  CheckCompiler(test, 'compiler.gyp',
+                ['my_cc.py', 'my_cxx.py', 'FOO'],
+                False)
+
+
+def TestHostOveride():
+  expected = ['my_cc.py', 'my_cxx.py', 'HOST' ]
+  if test.format != 'ninja':  # ninja just uses $CC / $CXX as linker.
+    expected.append('HOST_LINK')
+
+  # Check that CC_host sets host compilee
+  oldenv = os.environ.copy()
+  try:
+    os.environ['CC_host'] = 'python %s/my_cc.py HOST' % here
+    os.environ['CXX_host'] = 'python %s/my_cxx.py HOST' % here
+    os.environ['LINK_host'] = 'python %s/my_ld.py HOST_LINK' % here
+    CheckCompiler(test, 'compiler-host.gyp', expected, True)
+  finally:
+    os.environ.clear()
+    os.environ.update(oldenv)
+
+  # Run the same tests once the eviron has been restored.  The
+  # generated should have embedded all the settings in the
+  # project files so the results should be the same.
+  CheckCompiler(test, 'compiler-host.gyp', expected, False)
+
+
+TestTargetOveride()
+TestTargetOverideCompilerOnly()
+TestHostOveride()
+
+test.pass_test()
diff --git a/gyp/test/compiler-override/gyptest-compiler-global-settings.py b/gyp/test/compiler-override/gyptest-compiler-global-settings.py
new file mode 100755 (executable)
index 0000000..a4f5ddb
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""
+Verifies that make_global_settings can be used to override the
+compiler settings.
+"""
+
+import TestGyp
+import os
+import copy
+import sys
+from string import Template
+
+
+if sys.platform == 'win32':
+  # cross compiling not support by ninja on windows
+  # and make not supported on windows at all.
+  sys.exit(0)
+
+test = TestGyp.TestGyp(formats=['ninja', 'make'])
+
+gypfile = 'compiler-global-settings.gyp'
+
+replacements = { 'PYTHON': '/usr/bin/python', 'PWD': os.getcwd()}
+
+# Process the .in gyp file to produce the final gyp file
+# since we need to include absolute paths in the make_global_settings
+# section.
+replacements['TOOLSET'] = 'target'
+s = Template(open(gypfile + '.in').read())
+output = open(gypfile, 'w')
+output.write(s.substitute(replacements))
+output.close()
+
+old_env = dict(os.environ)
+os.environ['GYP_CROSSCOMPILE'] = '1'
+test.run_gyp(gypfile)
+os.environ.clear()
+os.environ.update(old_env)
+
+test.build(gypfile)
+test.must_contain_all_lines(test.stdout(), ['my_cc.py', 'my_cxx.py', 'FOO'])
+
+# Same again but with the host toolset.
+replacements['TOOLSET'] = 'host'
+s = Template(open(gypfile + '.in').read())
+output = open(gypfile, 'w')
+output.write(s.substitute(replacements))
+output.close()
+
+old_env = dict(os.environ)
+os.environ['GYP_CROSSCOMPILE'] = '1'
+test.run_gyp(gypfile)
+os.environ.clear()
+os.environ.update(old_env)
+
+test.build(gypfile)
+test.must_contain_all_lines(test.stdout(), ['my_cc.py', 'my_cxx.py', 'BAR'])
+
+# Check that CC_host overrides make_global_settings
+old_env = dict(os.environ)
+os.environ['CC_host'] = '%s %s/my_cc.py SECRET' % (replacements['PYTHON'],
+                                                   replacements['PWD'])
+test.run_gyp(gypfile)
+os.environ.clear()
+os.environ.update(old_env)
+
+test.build(gypfile)
+test.must_contain_all_lines(test.stdout(), ['SECRET', 'my_cxx.py', 'BAR'])
+
+test.pass_test()
diff --git a/gyp/test/compiler-override/my_cc.py b/gyp/test/compiler-override/my_cc.py
new file mode 100755 (executable)
index 0000000..e2f0bdd
--- /dev/null
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import sys
+print sys.argv
diff --git a/gyp/test/compiler-override/my_cxx.py b/gyp/test/compiler-override/my_cxx.py
new file mode 100755 (executable)
index 0000000..e2f0bdd
--- /dev/null
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import sys
+print sys.argv
diff --git a/gyp/test/compiler-override/my_ld.py b/gyp/test/compiler-override/my_ld.py
new file mode 100755 (executable)
index 0000000..e2f0bdd
--- /dev/null
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import sys
+print sys.argv
diff --git a/gyp/test/compiler-override/test.c b/gyp/test/compiler-override/test.c
new file mode 100644 (file)
index 0000000..517a353
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Deliberate C syntax error as this file should never be passed to
+// the actual compiler
+#error Should not be passed to a real compiler
diff --git a/gyp/test/configurations/basics/configurations.c b/gyp/test/configurations/basics/configurations.c
new file mode 100644 (file)
index 0000000..39e13c9
--- /dev/null
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+int main(void)
+{
+#ifdef FOO
+  printf("Foo configuration\n");
+#endif
+#ifdef DEBUG
+  printf("Debug configuration\n");
+#endif
+#ifdef RELEASE
+  printf("Release configuration\n");
+#endif
+  return 0;
+}
diff --git a/gyp/test/configurations/basics/configurations.gyp b/gyp/test/configurations/basics/configurations.gyp
new file mode 100644 (file)
index 0000000..93f1d8d
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'executable',
+      'sources': [
+        'configurations.c',
+      ],
+      'configurations': {
+        'Debug': {
+          'defines': [
+            'DEBUG',
+          ],
+        },
+        'Release': {
+          'defines': [
+            'RELEASE',
+          ],
+        },
+        'Foo': {
+          'defines': [
+            'FOO',
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/basics/gyptest-configurations.py b/gyp/test/configurations/basics/gyptest-configurations.py
new file mode 100755 (executable)
index 0000000..1cf1995
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable in three different configurations.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+if test.format == 'android':
+  # This test currently fails on android. Investigate why, fix the issues
+  # responsible, and reenable this test on android. See bug:
+  # https://code.google.com/p/gyp/issues/detail?id=436
+  test.skip_test(message='Test fails on android. Fix and reenable.\n')
+
+test.run_gyp('configurations.gyp')
+
+test.set_configuration('Release')
+test.build('configurations.gyp')
+test.run_built_executable('configurations', stdout="Release configuration\n")
+
+test.set_configuration('Debug')
+test.build('configurations.gyp')
+test.run_built_executable('configurations', stdout="Debug configuration\n")
+
+test.set_configuration('Foo')
+test.build('configurations.gyp')
+test.run_built_executable('configurations', stdout="Foo configuration\n")
+
+test.pass_test()
diff --git a/gyp/test/configurations/inheritance/configurations.c b/gyp/test/configurations/inheritance/configurations.c
new file mode 100644 (file)
index 0000000..ebb9f84
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdio.h>
+
+int main(void)
+{
+#ifdef BASE
+  printf("Base configuration\n");
+#endif
+#ifdef COMMON
+  printf("Common configuration\n");
+#endif
+#ifdef COMMON2
+  printf("Common2 configuration\n");
+#endif
+#ifdef DEBUG
+  printf("Debug configuration\n");
+#endif
+#ifdef RELEASE
+  printf("Release configuration\n");
+#endif
+  return 0;
+}
diff --git a/gyp/test/configurations/inheritance/configurations.gyp b/gyp/test/configurations/inheritance/configurations.gyp
new file mode 100644 (file)
index 0000000..9441376
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'configurations': {
+      'Base': {
+         'abstract': 1,
+         'defines': ['BASE'],
+      },
+      'Common': {
+         'abstract': 1,
+         'inherit_from': ['Base'],
+         'defines': ['COMMON'],
+      },
+      'Common2': {
+         'abstract': 1,
+         'defines': ['COMMON2'],
+      },
+      'Debug': {
+        'inherit_from': ['Common', 'Common2'],
+        'defines': ['DEBUG'],
+      },
+      'Release': {
+        'inherit_from': ['Common', 'Common2'],
+        'defines': ['RELEASE'],
+      },
+    },
+  },
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'executable',
+      'sources': [
+        'configurations.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/configurations/inheritance/duplicates.gyp b/gyp/test/configurations/inheritance/duplicates.gyp
new file mode 100644 (file)
index 0000000..6930ce3
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'default_configuration': 'A',
+    'configurations': {
+      'A': {
+        'defines': ['SOMETHING'],
+      },
+      'B': {
+        'inherit_from': ['A'],
+      },
+    },
+    'cflags': ['-g'],
+  },
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'executable',
+      'sources': [
+        'configurations.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/configurations/inheritance/duplicates.gypd.golden b/gyp/test/configurations/inheritance/duplicates.gypd.golden
new file mode 100644 (file)
index 0000000..719b708
--- /dev/null
@@ -0,0 +1,12 @@
+{'_DEPTH': '.',
+ 'included_files': ['duplicates.gyp'],
+ 'targets': [{'configurations': {'A': {'cflags': ['-g'],
+                                       'defines': ['SOMETHING']},
+                                 'B': {'cflags': ['-g'],
+                                       'defines': ['SOMETHING'],
+                                       'inherit_from': ['A']}},
+              'default_configuration': 'A',
+              'sources': ['configurations.c'],
+              'target_name': 'configurations',
+              'toolset': 'target',
+              'type': 'executable'}]}
diff --git a/gyp/test/configurations/inheritance/gyptest-duplicates.py b/gyp/test/configurations/inheritance/gyptest-duplicates.py
new file mode 100755 (executable)
index 0000000..46687b4
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that configurations do not duplicate other settings.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(format='gypd')
+
+test.run_gyp('duplicates.gyp')
+
+# Verify the duplicates.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system.  Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('duplicates.gypd').replace(
+    '\r', '').replace('\\\\', '/')
+expect = test.read('duplicates.gypd.golden').replace('\r', '')
+if not test.match(contents, expect):
+  print "Unexpected contents of `duplicates.gypd'"
+  test.diff(expect, contents, 'duplicates.gypd ')
+  test.fail_test()
+
+test.pass_test()
diff --git a/gyp/test/configurations/inheritance/gyptest-inheritance.py b/gyp/test/configurations/inheritance/gyptest-inheritance.py
new file mode 100755 (executable)
index 0000000..ecc9d08
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable in three different configurations.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+if test.format == 'android':
+  # This test currently fails on android. Investigate why, fix the issues
+  # responsible, and reenable this test on android. See bug:
+  # https://code.google.com/p/gyp/issues/detail?id=436
+  test.skip_test(message='Test fails on android. Fix and reenable.\n')
+
+test.run_gyp('configurations.gyp')
+
+test.set_configuration('Release')
+test.build('configurations.gyp')
+test.run_built_executable('configurations',
+                          stdout=('Base configuration\n'
+                                  'Common configuration\n'
+                                  'Common2 configuration\n'
+                                  'Release configuration\n'))
+
+test.set_configuration('Debug')
+test.build('configurations.gyp')
+test.run_built_executable('configurations',
+                          stdout=('Base configuration\n'
+                                  'Common configuration\n'
+                                  'Common2 configuration\n'
+                                  'Debug configuration\n'))
+
+test.pass_test()
diff --git a/gyp/test/configurations/invalid/actions.gyp b/gyp/test/configurations/invalid/actions.gyp
new file mode 100644 (file)
index 0000000..a6e4208
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'actions': [
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/invalid/all_dependent_settings.gyp b/gyp/test/configurations/invalid/all_dependent_settings.gyp
new file mode 100644 (file)
index 0000000..b16a245
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'all_dependent_settings': [
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/invalid/configurations.gyp b/gyp/test/configurations/invalid/configurations.gyp
new file mode 100644 (file)
index 0000000..2cfc960
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'configurations': [
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/invalid/dependencies.gyp b/gyp/test/configurations/invalid/dependencies.gyp
new file mode 100644 (file)
index 0000000..74633f3
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'dependencies': [
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/invalid/direct_dependent_settings.gyp b/gyp/test/configurations/invalid/direct_dependent_settings.gyp
new file mode 100644 (file)
index 0000000..8a0f2e9
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'direct_dependent_settings': [
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/invalid/gyptest-configurations.py b/gyp/test/configurations/invalid/gyptest-configurations.py
new file mode 100755 (executable)
index 0000000..bd844b9
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable in three different configurations.
+"""
+
+import TestGyp
+
+# Keys that do not belong inside a configuration dictionary.
+invalid_configuration_keys = [
+  'actions',
+  'all_dependent_settings',
+  'configurations',
+  'dependencies',
+  'direct_dependent_settings',
+  'libraries',
+  'link_settings',
+  'sources',
+  'standalone_static_library',
+  'target_name',
+  'type',
+]
+
+test = TestGyp.TestGyp()
+
+for test_key in invalid_configuration_keys:
+  test.run_gyp('%s.gyp' % test_key, status=1, stderr=None)
+  expect = ['%s not allowed in the Debug configuration, found in target '
+            '%s.gyp:configurations#target' % (test_key, test_key)]
+  test.must_contain_all_lines(test.stderr(), expect)
+
+test.pass_test()
diff --git a/gyp/test/configurations/invalid/libraries.gyp b/gyp/test/configurations/invalid/libraries.gyp
new file mode 100644 (file)
index 0000000..c4014ed
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'libraries': [
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/invalid/link_settings.gyp b/gyp/test/configurations/invalid/link_settings.gyp
new file mode 100644 (file)
index 0000000..2f0e1c4
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'link_settings': [
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/invalid/sources.gyp b/gyp/test/configurations/invalid/sources.gyp
new file mode 100644 (file)
index 0000000..b38cca0
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'sources': [
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/invalid/standalone_static_library.gyp b/gyp/test/configurations/invalid/standalone_static_library.gyp
new file mode 100644 (file)
index 0000000..2edb9fe
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'standalone_static_library': 1,
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/invalid/target_name.gyp b/gyp/test/configurations/invalid/target_name.gyp
new file mode 100644 (file)
index 0000000..83baad9
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'target_name': [
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/invalid/type.gyp b/gyp/test/configurations/invalid/type.gyp
new file mode 100644 (file)
index 0000000..bc55898
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'none',
+      'configurations': {
+        'Debug': {
+          'type': [
+          ],
+        },
+      }
+    },
+  ],
+}
diff --git a/gyp/test/configurations/target_platform/configurations.gyp b/gyp/test/configurations/target_platform/configurations.gyp
new file mode 100644 (file)
index 0000000..d15429f
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'configurations': {
+      'Debug_Win32': {
+        'msvs_configuration_platform': 'Win32',
+      },
+      'Debug_x64': {
+        'msvs_configuration_platform': 'x64',
+      },
+    },
+  },
+  'targets': [
+    {
+      'target_name': 'left',
+      'type': 'static_library',
+      'sources': [
+        'left.c',
+      ],
+      'configurations': {
+        'Debug_Win32': {
+          'msvs_target_platform': 'x64',
+        },
+      },
+    },
+    {
+      'target_name': 'right',
+      'type': 'static_library',
+      'sources': [
+        'right.c',
+      ],
+    },
+    {
+      'target_name': 'front_left',
+      'type': 'executable',
+      'dependencies': ['left'],
+      'sources': [
+        'front.c',
+      ],
+      'configurations': {
+        'Debug_Win32': {
+          'msvs_target_platform': 'x64',
+        },
+      },
+    },
+    {
+      'target_name': 'front_right',
+      'type': 'executable',
+      'dependencies': ['right'],
+      'sources': [
+        'front.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/configurations/target_platform/front.c b/gyp/test/configurations/target_platform/front.c
new file mode 100644 (file)
index 0000000..7a91689
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+const char *message(void);
+
+int main(void) {
+  printf("%s\n", message());
+  return 0;
+}
diff --git a/gyp/test/configurations/target_platform/gyptest-target_platform.py b/gyp/test/configurations/target_platform/gyptest-target_platform.py
new file mode 100755 (executable)
index 0000000..ae4e9e5
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests the msvs specific msvs_target_platform option.
+"""
+
+import TestGyp
+import TestCommon
+
+
+def RunX64(exe, stdout):
+  try:
+    test.run_built_executable(exe, stdout=stdout)
+  except WindowsError, e:
+    # Assume the exe is 64-bit if it can't load on 32-bit systems.
+    # Both versions of the error are required because different versions
+    # of python seem to return different errors for invalid exe type.
+    if e.errno != 193 and '[Error 193]' not in str(e):
+      raise
+
+
+test = TestGyp.TestGyp(formats=['msvs'])
+
+test.run_gyp('configurations.gyp')
+
+test.set_configuration('Debug|x64')
+test.build('configurations.gyp', rebuild=True)
+RunX64('front_left', stdout=('left\n'))
+RunX64('front_right', stdout=('right\n'))
+
+test.set_configuration('Debug|Win32')
+test.build('configurations.gyp', rebuild=True)
+RunX64('front_left', stdout=('left\n'))
+test.run_built_executable('front_right', stdout=('right\n'))
+
+test.pass_test()
diff --git a/gyp/test/configurations/target_platform/left.c b/gyp/test/configurations/target_platform/left.c
new file mode 100644 (file)
index 0000000..1ce2ea1
--- /dev/null
@@ -0,0 +1,3 @@
+const char *message(void) {
+  return "left";
+}
diff --git a/gyp/test/configurations/target_platform/right.c b/gyp/test/configurations/target_platform/right.c
new file mode 100644 (file)
index 0000000..b157849
--- /dev/null
@@ -0,0 +1,3 @@
+const char *message(void) {
+  return "right";
+}
diff --git a/gyp/test/configurations/x64/configurations.c b/gyp/test/configurations/x64/configurations.c
new file mode 100644 (file)
index 0000000..3701843
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int main(void) {
+  if (sizeof(void*) == 4) {
+    printf("Running Win32\n");
+  } else if (sizeof(void*) == 8) {
+    printf("Running x64\n");
+  } else {
+    printf("Unexpected platform\n");
+  }
+  return 0;
+}
diff --git a/gyp/test/configurations/x64/configurations.gyp b/gyp/test/configurations/x64/configurations.gyp
new file mode 100644 (file)
index 0000000..8b0139f
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'configurations': {
+      'Debug': {
+        'msvs_configuration_platform': 'Win32',
+      },
+      'Debug_x64': {
+        'inherit_from': ['Debug'],
+        'msvs_configuration_platform': 'x64',
+      },
+    },
+  },
+  'targets': [
+    {
+      'target_name': 'configurations',
+      'type': 'executable',
+      'sources': [
+        'configurations.c',
+      ],
+    },
+    {
+      'target_name': 'configurations64',
+      'type': 'executable',
+      'sources': [
+        'configurations.c',
+      ],
+      'configurations': {
+        'Debug': {
+          'msvs_target_platform': 'x64',
+        },
+      },
+    },
+  ],
+}
diff --git a/gyp/test/configurations/x64/gyptest-x86.py b/gyp/test/configurations/x64/gyptest-x86.py
new file mode 100755 (executable)
index 0000000..8675d8f
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable in three different configurations.
+"""
+
+import TestGyp
+
+import sys
+
+formats = ['msvs']
+if sys.platform == 'win32':
+  formats += ['ninja']
+test = TestGyp.TestGyp(formats=formats)
+
+test.run_gyp('configurations.gyp')
+test.set_configuration('Debug|Win32')
+test.build('configurations.gyp', test.ALL)
+
+for machine, suffix in [('14C machine (x86)', ''),
+                        ('8664 machine (x64)', '64')]:
+  output = test.run_dumpbin(
+      '/headers', test.built_file_path('configurations%s.exe' % suffix))
+  if machine not in output:
+    test.fail_test()
+
+test.pass_test()
diff --git a/gyp/test/copies/gyptest-all.py b/gyp/test/copies/gyptest-all.py
new file mode 100755 (executable)
index 0000000..8542ab7
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies file copies using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('copies.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('copies.gyp', test.ALL, chdir='relocate/src')
+
+test.must_match(['relocate', 'src', 'copies-out', 'file1'], 'file1 contents\n')
+
+test.built_file_must_match('copies-out/file2',
+                           'file2 contents\n',
+                           chdir='relocate/src')
+
+test.built_file_must_match('copies-out/directory/file3',
+                           'file3 contents\n',
+                           chdir='relocate/src')
+test.built_file_must_match('copies-out/directory/file4',
+                           'file4 contents\n',
+                           chdir='relocate/src')
+test.built_file_must_match('copies-out/directory/subdir/file5',
+                           'file5 contents\n',
+                           chdir='relocate/src')
+test.built_file_must_match('copies-out/subdir/file6',
+                           'file6 contents\n',
+                           chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/copies/gyptest-attribs.py b/gyp/test/copies/gyptest-attribs.py
new file mode 100644 (file)
index 0000000..70d717a
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that copying files preserves file attributes.
+"""
+
+import TestGyp
+
+import os
+import stat
+import sys
+
+
+def check_attribs(path, expected_exec_bit):
+  out_path = test.built_file_path(path, chdir='src')
+
+  in_stat = os.stat(os.path.join('src', path))
+  out_stat = os.stat(out_path)
+  if out_stat.st_mode & stat.S_IXUSR != expected_exec_bit:
+    test.fail_test()
+
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('copies-attribs.gyp', chdir='src')
+
+test.build('copies-attribs.gyp', chdir='src')
+
+if sys.platform != 'win32':
+  out_path = test.built_file_path('executable-file.sh', chdir='src')
+  test.must_contain(out_path,
+                    '#!/bin/bash\n'
+                    '\n'
+                    'echo echo echo echo cho ho o o\n')
+  check_attribs('executable-file.sh', expected_exec_bit=stat.S_IXUSR)
+
+test.pass_test()
diff --git a/gyp/test/copies/gyptest-default.py b/gyp/test/copies/gyptest-default.py
new file mode 100755 (executable)
index 0000000..a5d1bf9
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies file copies using the build tool default.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('copies.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('copies.gyp', chdir='relocate/src')
+
+test.must_match(['relocate', 'src', 'copies-out', 'file1'], 'file1 contents\n')
+
+test.built_file_must_match('copies-out/file2',
+                           'file2 contents\n',
+                           chdir='relocate/src')
+
+test.built_file_must_match('copies-out/directory/file3',
+                           'file3 contents\n',
+                           chdir='relocate/src')
+test.built_file_must_match('copies-out/directory/file4',
+                           'file4 contents\n',
+                           chdir='relocate/src')
+test.built_file_must_match('copies-out/directory/subdir/file5',
+                           'file5 contents\n',
+                           chdir='relocate/src')
+test.built_file_must_match('copies-out/subdir/file6',
+                           'file6 contents\n',
+                           chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/copies/gyptest-samedir.py b/gyp/test/copies/gyptest-samedir.py
new file mode 100755 (executable)
index 0000000..3f0c547
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies file copies where two copies sections in the same target have the
+same destination directory.
+"""
+
+import TestGyp
+
+# The Android build system doesn't allow output to go to arbitrary places.
+test = TestGyp.TestGyp(formats=['!android'])
+test.run_gyp('copies-samedir.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+test.build('copies-samedir.gyp', 'copies_samedir', chdir='relocate/src')
+
+test.built_file_must_match('copies-out-samedir/file1',
+                           'file1 contents\n',
+                           chdir='relocate/src')
+
+test.built_file_must_match('copies-out-samedir/file2',
+                           'file2 contents\n',
+                           chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/copies/gyptest-slash.py b/gyp/test/copies/gyptest-slash.py
new file mode 100755 (executable)
index 0000000..81a4f42
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies file copies with a trailing slash in the destination directory.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+test.run_gyp('copies-slash.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+test.build('copies-slash.gyp', chdir='relocate/src')
+
+test.built_file_must_match('copies-out-slash/directory/file3',
+                           'file3 contents\n',
+                           chdir='relocate/src')
+test.built_file_must_match('copies-out-slash/directory/file4',
+                           'file4 contents\n',
+                           chdir='relocate/src')
+test.built_file_must_match('copies-out-slash/directory/subdir/file5',
+                           'file5 contents\n',
+                           chdir='relocate/src')
+
+test.built_file_must_match('copies-out-slash-2/directory/file3',
+                           'file3 contents\n',
+                           chdir='relocate/src')
+test.built_file_must_match('copies-out-slash-2/directory/file4',
+                           'file4 contents\n',
+                           chdir='relocate/src')
+test.built_file_must_match('copies-out-slash-2/directory/subdir/file5',
+                           'file5 contents\n',
+                           chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/copies/gyptest-updir.py b/gyp/test/copies/gyptest-updir.py
new file mode 100755 (executable)
index 0000000..00b01c7
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies file copies where the destination is one level above an expansion that
+yields a make variable.
+"""
+
+import TestGyp
+
+# The Android build system doesn't allow output to go to arbitrary places.
+test = TestGyp.TestGyp(formats=['!android'])
+test.run_gyp('copies-updir.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+test.build('copies-updir.gyp', 'copies_up', chdir='relocate/src')
+
+test.built_file_must_match('../copies-out-updir/file1',
+                           'file1 contents\n',
+                           chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/copies/src/copies-attribs.gyp b/gyp/test/copies/src/copies-attribs.gyp
new file mode 100644 (file)
index 0000000..073e0d0
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'copies1',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)',
+          'files': [
+            'executable-file.sh',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/copies/src/copies-samedir.gyp b/gyp/test/copies/src/copies-samedir.gyp
new file mode 100644 (file)
index 0000000..2919ce5
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'copies_samedir',
+      'type': 'none',
+      'dependencies': [
+        'copies_samedir_dependency',
+      ],
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/copies-out-samedir',
+          'files': [
+            'file1',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'copies_samedir_dependency',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'copies': [
+          {
+            'destination': '<(PRODUCT_DIR)/copies-out-samedir',
+            'files': [
+              'file2',
+            ],
+          },
+        ],
+      },
+    },
+  ],
+}
diff --git a/gyp/test/copies/src/copies-slash.gyp b/gyp/test/copies/src/copies-slash.gyp
new file mode 100644 (file)
index 0000000..9bf54bd
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    # A trailing slash on the destination directory should be ignored.
+    {
+      'target_name': 'copies_recursive_trailing_slash',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/copies-out-slash/',
+          'files': [
+            'directory/',
+          ],
+        },
+      ],
+    },
+    # Even if the source directory is below <(PRODUCT_DIR).
+    {
+      'target_name': 'copies_recursive_trailing_slash_in_product_dir',
+      'type': 'none',
+      'dependencies': [ ':copies_recursive_trailing_slash' ],
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/copies-out-slash-2/',
+          'files': [
+            '<(PRODUCT_DIR)/copies-out-slash/directory/',
+          ],
+        },
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/copies/src/copies-updir.gyp b/gyp/test/copies/src/copies-updir.gyp
new file mode 100644 (file)
index 0000000..bd3bfdd
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'copies_up',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/../copies-out-updir',
+          'files': [
+            'file1',
+          ],
+        },
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/copies/src/copies.gyp b/gyp/test/copies/src/copies.gyp
new file mode 100644 (file)
index 0000000..ce2e0ca
--- /dev/null
@@ -0,0 +1,70 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'copies1',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': 'copies-out',
+          'files': [
+            'file1',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'copies2',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/copies-out',
+          'files': [
+            'file2',
+          ],
+        },
+      ],
+    },
+    # Copy a directory tree.
+    {
+      'target_name': 'copies_recursive',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/copies-out',
+          'files': [
+            'directory/',
+          ],
+        },
+      ],
+    },
+    # Copy a directory from deeper in the tree (this should not reproduce the
+    # entire directory path in the destination, only the final directory).
+    {
+      'target_name': 'copies_recursive_depth',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/copies-out',
+          'files': [
+            'parentdir/subdir/',
+          ],
+        },
+      ],
+    },
+    # Verify that a null 'files' list doesn't gag the generators.
+    {
+      'target_name': 'copies_null',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/copies-null',
+          'files': [],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/copies/src/directory/file3 b/gyp/test/copies/src/directory/file3
new file mode 100644 (file)
index 0000000..43f16f3
--- /dev/null
@@ -0,0 +1 @@
+file3 contents
diff --git a/gyp/test/copies/src/directory/file4 b/gyp/test/copies/src/directory/file4
new file mode 100644 (file)
index 0000000..5f7270a
--- /dev/null
@@ -0,0 +1 @@
+file4 contents
diff --git a/gyp/test/copies/src/directory/subdir/file5 b/gyp/test/copies/src/directory/subdir/file5
new file mode 100644 (file)
index 0000000..41f4718
--- /dev/null
@@ -0,0 +1 @@
+file5 contents
diff --git a/gyp/test/copies/src/executable-file.sh b/gyp/test/copies/src/executable-file.sh
new file mode 100755 (executable)
index 0000000..796953a
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo echo echo echo cho ho o o
diff --git a/gyp/test/copies/src/file1 b/gyp/test/copies/src/file1
new file mode 100644 (file)
index 0000000..84d55c5
--- /dev/null
@@ -0,0 +1 @@
+file1 contents
diff --git a/gyp/test/copies/src/file2 b/gyp/test/copies/src/file2
new file mode 100644 (file)
index 0000000..af1b8ae
--- /dev/null
@@ -0,0 +1 @@
+file2 contents
diff --git a/gyp/test/copies/src/parentdir/subdir/file6 b/gyp/test/copies/src/parentdir/subdir/file6
new file mode 100644 (file)
index 0000000..f5d5757
--- /dev/null
@@ -0,0 +1 @@
+file6 contents
diff --git a/gyp/test/custom-generator/gyptest-custom-generator.py b/gyp/test/custom-generator/gyptest-custom-generator.py
new file mode 100755 (executable)
index 0000000..85fd072
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Test that custom generators can be passed to --format
+"""
+
+import TestGyp
+
+test = TestGyp.TestGypCustom(format='mygenerator.py')
+test.run_gyp('test.gyp')
+
+# mygenerator.py should generate a file called MyBuildFile containing
+# "Testing..." alongside the gyp file.
+test.must_match('MyBuildFile', 'Testing...\n')
+
+test.pass_test()
diff --git a/gyp/test/custom-generator/mygenerator.py b/gyp/test/custom-generator/mygenerator.py
new file mode 100644 (file)
index 0000000..8eb4c2d
--- /dev/null
@@ -0,0 +1,14 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Custom gyp generator that doesn't do much."""
+
+import gyp.common
+
+generator_default_variables = {}
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  f = open("MyBuildFile", "wb")
+  f.write("Testing...\n")
+  f.close()
diff --git a/gyp/test/custom-generator/test.gyp b/gyp/test/custom-generator/test.gyp
new file mode 100644 (file)
index 0000000..aa5f864
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'exe',
+      'type': 'executable',
+      'sources': [
+        'main.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/cxxflags/cxxflags.cc b/gyp/test/cxxflags/cxxflags.cc
new file mode 100644 (file)
index 0000000..e70e39d
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (c) 2010 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(void)
+{
+#ifdef ABC
+  printf("With define\n");
+#else
+  printf("No define\n");
+#endif
+  return 0;
+}
diff --git a/gyp/test/cxxflags/cxxflags.gyp b/gyp/test/cxxflags/cxxflags.gyp
new file mode 100644 (file)
index 0000000..a082d49
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'cxxflags',
+      'type': 'executable',
+      'sources': [
+        'cxxflags.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/cxxflags/gyptest-cxxflags.py b/gyp/test/cxxflags/gyptest-cxxflags.py
new file mode 100755 (executable)
index 0000000..117a180
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies the use of the environment during regeneration when the gyp file
+changes, specifically via build of an executable with C++ flags specified by
+CXXFLAGS.
+
+In this test, gyp happens within a local environment, but build outside of it.
+"""
+
+import TestGyp
+
+FORMATS = ('ninja',)
+
+test = TestGyp.TestGyp(formats=FORMATS)
+
+# We reset the environ after calling gyp. When the auto-regeneration happens,
+# the same define should be reused anyway.
+with TestGyp.LocalEnv({'CXXFLAGS': ''}):
+  test.run_gyp('cxxflags.gyp')
+
+test.build('cxxflags.gyp')
+
+expect = """\
+No define
+"""
+test.run_built_executable('cxxflags', stdout=expect)
+
+test.sleep()
+
+with TestGyp.LocalEnv({'CXXFLAGS': '-DABC'}):
+  test.run_gyp('cxxflags.gyp')
+
+test.build('cxxflags.gyp')
+
+expect = """\
+With define
+"""
+test.run_built_executable('cxxflags', stdout=expect)
+
+test.pass_test()
diff --git a/gyp/test/defines-escaping/defines-escaping.c b/gyp/test/defines-escaping/defines-escaping.c
new file mode 100644 (file)
index 0000000..a0aa4c2
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (c) 2010 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(void)
+{
+  printf(TEST_FORMAT, TEST_ARGS);
+  return 0;
+}
diff --git a/gyp/test/defines-escaping/defines-escaping.gyp b/gyp/test/defines-escaping/defines-escaping.gyp
new file mode 100644 (file)
index 0000000..6f0f3fd
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'defines_escaping',
+      'type': 'executable',
+      'sources': [
+        'defines-escaping.c',
+      ],
+      'defines': [
+        'TEST_FORMAT="<(test_format)"',
+        'TEST_ARGS=<(test_args)',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/defines-escaping/gyptest-defines-escaping.py b/gyp/test/defines-escaping/gyptest-defines-escaping.py
new file mode 100755 (executable)
index 0000000..eb18a3d
--- /dev/null
@@ -0,0 +1,184 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable with C++ define specified by a gyp define using
+various special characters such as quotes, commas, etc.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# Tests string literals, percents, and backslash escapes.
+try:
+  os.environ['GYP_DEFINES'] = (
+      r"""test_format='\n%s\n' """
+      r"""test_args='"Simple test of %s with a literal"'""")
+  test.run_gyp('defines-escaping.gyp')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.build('defines-escaping.gyp')
+
+expect = """
+Simple test of %s with a literal
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test multiple comma-and-space-separated string literals.
+try:
+  os.environ['GYP_DEFINES'] = \
+      r"""test_format='\n%s and %s\n' test_args='"foo", "bar"'"""
+  test.run_gyp('defines-escaping.gyp')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = """
+foo and bar
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test string literals containing quotes.
+try:
+  os.environ['GYP_DEFINES'] = (
+      r"""test_format='\n%s %s %s %s %s\n' """
+      r"""test_args='"\"These,\"","""
+                r""" "\"words,\"","""
+                r""" "\"are,\"","""
+                r""" "\"in,\"","""
+                r""" "\"quotes.\""'""")
+  test.run_gyp('defines-escaping.gyp')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = """
+"These," "words," "are," "in," "quotes."
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test string literals containing single quotes.
+try:
+  os.environ['GYP_DEFINES'] = (
+      r"""test_format='\n%s %s %s %s %s\n' """
+      r"""test_args="\"'These,'\","""
+                r""" \"'words,'\","""
+                r""" \"'are,'\","""
+                r""" \"'in,'\","""
+                r""" \"'quotes.'\"" """)
+  test.run_gyp('defines-escaping.gyp')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = """
+'These,' 'words,' 'are,' 'in,' 'quotes.'
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test string literals containing different numbers of backslashes before quotes
+# (to exercise Windows' quoting behaviour).
+try:
+  os.environ['GYP_DEFINES'] = (
+      r"""test_format='\n%s\n%s\n%s\n' """
+      r"""test_args='"\\\"1 visible slash\\\"","""
+                r""" "\\\\\"2 visible slashes\\\\\"","""
+                r""" "\\\\\\\"3 visible slashes\\\\\\\""'""")
+  test.run_gyp('defines-escaping.gyp')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = r"""
+\"1 visible slash\"
+\\"2 visible slashes\\"
+\\\"3 visible slashes\\\"
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test that various scary sequences are passed unfettered.
+try:
+  os.environ['GYP_DEFINES'] = (
+      r"""test_format='\n%s\n' """
+      r"""test_args='"$foo, &quot; `foo`;"'""")
+  test.run_gyp('defines-escaping.gyp')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = """
+$foo, &quot; `foo`;
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# VisualStudio 2010 can't handle passing %PATH%
+if not (test.format == 'msvs' and test.uses_msbuild):
+  try:
+    os.environ['GYP_DEFINES'] = (
+        """test_format='%s' """
+        """test_args='"%PATH%"'""")
+    test.run_gyp('defines-escaping.gyp')
+  finally:
+    del os.environ['GYP_DEFINES']
+
+  test.sleep()
+  test.touch('defines-escaping.c')
+  test.build('defines-escaping.gyp')
+
+  expect = "%PATH%"
+  test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test commas and semi-colons preceded by backslashes (to exercise Windows'
+# quoting behaviour).
+try:
+  os.environ['GYP_DEFINES'] = (
+      r"""test_format='\n%s\n%s\n' """
+      r"""test_args='"\\, \\\\;","""
+                # Same thing again, but enclosed in visible quotes.
+                r""" "\"\\, \\\\;\""'""")
+  test.run_gyp('defines-escaping.gyp')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = r"""
+\, \\;
+"\, \\;"
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+# We deliberately do not test having an odd number of quotes in a string
+# literal because that isn't feasible in MSVS.
+
+test.pass_test()
diff --git a/gyp/test/defines/defines-env.gyp b/gyp/test/defines/defines-env.gyp
new file mode 100644 (file)
index 0000000..1781546
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'value%': '5',
+  },
+  'targets': [
+    {
+      'target_name': 'defines',
+      'type': 'executable',
+      'sources': [
+        'defines.c',
+      ],
+      'defines': [
+        'VALUE=<(value)',
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/defines/defines.c b/gyp/test/defines/defines.c
new file mode 100644 (file)
index 0000000..dda1392
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(void)
+{
+#ifdef FOO
+  printf("FOO is defined\n");
+#endif
+  printf("VALUE is %d\n", VALUE);
+
+#ifdef PAREN_VALUE
+  printf("2*PAREN_VALUE is %d\n", 2*PAREN_VALUE);
+#endif
+
+#ifdef HASH_VALUE
+  printf("HASH_VALUE is %s\n", HASH_VALUE);
+#endif
+
+  return 0;
+}
diff --git a/gyp/test/defines/defines.gyp b/gyp/test/defines/defines.gyp
new file mode 100644 (file)
index 0000000..90a755e
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'defines',
+      'type': 'executable',
+      'sources': [
+        'defines.c',
+      ],
+      'defines': [
+        'FOO',
+        'VALUE=1',
+        'PAREN_VALUE=(1+2+3)',
+        'HASH_VALUE="a#1"',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="fakeos"', {
+      'targets': [
+        {
+          'target_name': 'fakeosprogram',
+          'type': 'executable',
+          'sources': [
+            'defines.c',
+          ],
+          'defines': [
+            'FOO',
+            'VALUE=1',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/gyp/test/defines/gyptest-define-override.py b/gyp/test/defines/gyptest-define-override.py
new file mode 100755 (executable)
index 0000000..9730455
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a default gyp define can be overridden.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# CMake loudly warns about passing '#' to the compiler and drops the define.
+expect_stderr = ''
+if test.format == 'cmake':
+  expect_stderr = (
+"""WARNING: Preprocessor definitions containing '#' may not be passed on the"""
+""" compiler command line because many compilers do not support it.\n"""
+"""CMake is dropping a preprocessor definition: HASH_VALUE="a#1"\n"""
+"""Consider defining the macro in a (configured) header file.\n\n""")
+
+# Command-line define
+test.run_gyp('defines.gyp', '-D', 'OS=fakeos')
+test.build('defines.gyp', stderr=expect_stderr)
+test.built_file_must_exist('fakeosprogram', type=test.EXECUTABLE)
+# Clean up the exe so subsequent tests don't find an old exe.
+os.remove(test.built_file_path('fakeosprogram', type=test.EXECUTABLE))
+
+# Without "OS" override, fokeosprogram shouldn't be built.
+test.run_gyp('defines.gyp')
+test.build('defines.gyp', stderr=expect_stderr)
+test.built_file_must_not_exist('fakeosprogram', type=test.EXECUTABLE)
+
+# Environment define
+os.environ['GYP_DEFINES'] = 'OS=fakeos'
+test.run_gyp('defines.gyp')
+test.build('defines.gyp', stderr=expect_stderr)
+test.built_file_must_exist('fakeosprogram', type=test.EXECUTABLE)
+
+test.pass_test()
diff --git a/gyp/test/defines/gyptest-defines-env-regyp.py b/gyp/test/defines/gyptest-defines-env-regyp.py
new file mode 100755 (executable)
index 0000000..f2d931c
--- /dev/null
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable with C++ define specified by a gyp define, and
+the use of the environment during regeneration when the gyp file changes.
+"""
+
+import os
+import TestGyp
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
+
+try:
+  os.environ['GYP_DEFINES'] = 'value=50'
+  test.run_gyp('defines.gyp')
+finally:
+  # We clear the environ after calling gyp.  When the auto-regeneration happens,
+  # the same define should be reused anyway.  Reset to empty string first in
+  # case the platform doesn't support unsetenv.
+  os.environ['GYP_DEFINES'] = ''
+  del os.environ['GYP_DEFINES']
+
+test.build('defines.gyp')
+
+expect = """\
+FOO is defined
+VALUE is 1
+2*PAREN_VALUE is 12
+HASH_VALUE is a#1
+"""
+test.run_built_executable('defines', stdout=expect)
+
+# Sleep so that the changed gyp file will have a newer timestamp than the
+# previously generated build files.
+test.sleep()
+test.write('defines.gyp', test.read('defines-env.gyp'))
+
+test.build('defines.gyp', test.ALL)
+
+expect = """\
+VALUE is 50
+"""
+test.run_built_executable('defines', stdout=expect)
+
+test.pass_test()
diff --git a/gyp/test/defines/gyptest-defines-env.py b/gyp/test/defines/gyptest-defines-env.py
new file mode 100755 (executable)
index 0000000..6b4e717
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable with C++ define specified by a gyp define.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# With the value only given in environment, it should be used.
+try:
+  os.environ['GYP_DEFINES'] = 'value=10'
+  test.run_gyp('defines-env.gyp')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.build('defines-env.gyp')
+
+expect = """\
+VALUE is 10
+"""
+test.run_built_executable('defines', stdout=expect)
+
+
+# With the value given in both command line and environment,
+# command line should take precedence.
+try:
+  os.environ['GYP_DEFINES'] = 'value=20'
+  test.run_gyp('defines-env.gyp', '-Dvalue=25')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines.c')
+test.build('defines-env.gyp')
+
+expect = """\
+VALUE is 25
+"""
+test.run_built_executable('defines', stdout=expect)
+
+
+# With the value only given in environment, it should be ignored if
+# --ignore-environment is specified.
+try:
+  os.environ['GYP_DEFINES'] = 'value=30'
+  test.run_gyp('defines-env.gyp', '--ignore-environment')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines.c')
+test.build('defines-env.gyp')
+
+expect = """\
+VALUE is 5
+"""
+test.run_built_executable('defines', stdout=expect)
+
+
+# With the value given in both command line and environment, and
+# --ignore-environment also specified, command line should still be used.
+try:
+  os.environ['GYP_DEFINES'] = 'value=40'
+  test.run_gyp('defines-env.gyp', '--ignore-environment', '-Dvalue=45')
+finally:
+  del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines.c')
+test.build('defines-env.gyp')
+
+expect = """\
+VALUE is 45
+"""
+test.run_built_executable('defines', stdout=expect)
+
+
+test.pass_test()
diff --git a/gyp/test/defines/gyptest-defines.py b/gyp/test/defines/gyptest-defines.py
new file mode 100755 (executable)
index 0000000..77a3af5
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable with C++ defines.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('defines.gyp')
+
+expect = """\
+FOO is defined
+VALUE is 1
+2*PAREN_VALUE is 12
+"""
+
+#CMake loudly warns about passing '#' to the compiler and drops the define.
+expect_stderr = ''
+if test.format == 'cmake':
+  expect_stderr = (
+"""WARNING: Preprocessor definitions containing '#' may not be passed on the"""
+""" compiler command line because many compilers do not support it.\n"""
+"""CMake is dropping a preprocessor definition: HASH_VALUE="a#1"\n"""
+"""Consider defining the macro in a (configured) header file.\n\n""")
+else:
+  expect += """HASH_VALUE is a#1
+"""
+
+test.build('defines.gyp', stderr=expect_stderr)
+
+test.run_built_executable('defines', stdout=expect)
+
+test.pass_test()
diff --git a/gyp/test/dependencies/a.c b/gyp/test/dependencies/a.c
new file mode 100755 (executable)
index 0000000..3bba111
--- /dev/null
@@ -0,0 +1,9 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+extern int funcB();
+
+int funcA() {
+  return funcB();
+}
diff --git a/gyp/test/dependencies/b/b.c b/gyp/test/dependencies/b/b.c
new file mode 100755 (executable)
index 0000000..b5e771b
--- /dev/null
@@ -0,0 +1,3 @@
+int funcB() {
+  return 2;
+}
diff --git a/gyp/test/dependencies/b/b.gyp b/gyp/test/dependencies/b/b.gyp
new file mode 100755 (executable)
index 0000000..893dc64
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'b',
+      'type': 'static_library',
+      'sources': [
+        'b.c',
+      ],
+    },
+    {
+      'target_name': 'b3',
+      'type': 'static_library',
+      'sources': [
+        'b3.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/dependencies/b/b3.c b/gyp/test/dependencies/b/b3.c
new file mode 100755 (executable)
index 0000000..287f67f
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+int funcB() {
+  return 3;
+}
diff --git a/gyp/test/dependencies/c/c.c b/gyp/test/dependencies/c/c.c
new file mode 100644 (file)
index 0000000..4949daf
--- /dev/null
@@ -0,0 +1,4 @@
+int funcC() {
+  return 3
+  // Intentional syntax error. This file should never be compiled, so this
+  // shouldn't be a problem.
diff --git a/gyp/test/dependencies/c/c.gyp b/gyp/test/dependencies/c/c.gyp
new file mode 100644 (file)
index 0000000..eabebea
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'c_unused',
+      'type': 'static_library',
+      'sources': [
+        'c.c',
+      ],
+    },
+    {
+      'target_name': 'd',
+      'type': 'static_library',
+      'sources': [
+        'd.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/dependencies/c/d.c b/gyp/test/dependencies/c/d.c
new file mode 100644 (file)
index 0000000..05465fc
--- /dev/null
@@ -0,0 +1,3 @@
+int funcD() {
+  return 4;
+}
diff --git a/gyp/test/dependencies/double_dependency.gyp b/gyp/test/dependencies/double_dependency.gyp
new file mode 100644 (file)
index 0000000..c4a2d00
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'double_dependency',
+      'type': 'shared_library',
+      'dependencies': [
+        'double_dependent.gyp:double_dependent',
+      ],
+      'conditions': [
+        ['1==1', {
+          'dependencies': [
+            'double_dependent.gyp:*',
+          ],
+        }],
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/dependencies/double_dependent.gyp b/gyp/test/dependencies/double_dependent.gyp
new file mode 100644 (file)
index 0000000..334caff
--- /dev/null
@@ -0,0 +1,12 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'double_dependent',
+      'type': 'none',
+    },
+  ],
+}
diff --git a/gyp/test/dependencies/extra_targets.gyp b/gyp/test/dependencies/extra_targets.gyp
new file mode 100644 (file)
index 0000000..c1a26de
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'a',
+      'type': 'static_library',
+      'sources': [
+        'a.c',
+      ],
+      # This only depends on the "d" target; other targets in c.gyp
+      # should not become part of the build (unlike with 'c/c.gyp:*').
+      'dependencies': ['c/c.gyp:d'],
+    },
+  ],
+}
diff --git a/gyp/test/dependencies/gyptest-double-dependency.py b/gyp/test/dependencies/gyptest-double-dependency.py
new file mode 100644 (file)
index 0000000..7692740
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that pulling in a dependency a second time in a conditional works for
+shared_library targets. Regression test for http://crbug.com/122588
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('double_dependency.gyp')
+
+# If running gyp worked, all is well.
+test.pass_test()
diff --git a/gyp/test/dependencies/gyptest-extra-targets.py b/gyp/test/dependencies/gyptest-extra-targets.py
new file mode 100755 (executable)
index 0000000..3752f74
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that dependencies don't pull unused targets into the build.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('extra_targets.gyp')
+
+# This should fail if it tries to build 'c_unused' since 'c/c.c' has a syntax
+# error and won't compile.
+test.build('extra_targets.gyp', test.ALL)
+
+test.pass_test()
diff --git a/gyp/test/dependencies/gyptest-lib-only.py b/gyp/test/dependencies/gyptest-lib-only.py
new file mode 100755 (executable)
index 0000000..283c29e
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that a link time only dependency will get pulled into the set of built
+targets, even if no executable uses it.
+"""
+
+import TestGyp
+
+import sys
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('lib_only.gyp')
+
+test.build('lib_only.gyp', test.ALL)
+
+test.built_file_must_exist('a', type=test.STATIC_LIB)
+
+# TODO(bradnelson/mark):
+# On linux and windows a library target will at least pull its link dependencies
+# into the generated project, since not doing so confuses users.
+# This is not currently implemented on mac, which has the opposite behavior.
+if sys.platform == 'darwin':
+  if test.format == 'xcode':
+    test.built_file_must_not_exist('b', type=test.STATIC_LIB)
+  else:
+    assert test.format in ('make', 'ninja')
+    test.built_file_must_exist('b', type=test.STATIC_LIB)
+else:
+  # Make puts the resulting library in a directory matching the input gyp file;
+  # for the 'b' library, that is in the 'b' subdirectory.
+  test.built_file_must_exist('b', type=test.STATIC_LIB, subdir='b')
+
+test.pass_test()
diff --git a/gyp/test/dependencies/gyptest-none-traversal.py b/gyp/test/dependencies/gyptest-none-traversal.py
new file mode 100755 (executable)
index 0000000..c09063d
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that static library dependencies don't traverse none targets, unless
+explicitly specified.
+"""
+
+import TestGyp
+
+import sys
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('none_traversal.gyp')
+
+test.build('none_traversal.gyp', test.ALL)
+
+test.run_built_executable('needs_chain', stdout="2\n")
+test.run_built_executable('doesnt_need_chain', stdout="3\n")
+
+test.pass_test()
diff --git a/gyp/test/dependencies/gyptest-sharedlib-linksettings.py b/gyp/test/dependencies/gyptest-sharedlib-linksettings.py
new file mode 100644 (file)
index 0000000..87428af
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that link_settings in a shared_library are not propagated to targets
+that depend on the shared_library, but are used in the shared_library itself.
+"""
+
+import TestGyp
+import sys
+
+CHDIR='sharedlib-linksettings'
+
+test = TestGyp.TestGyp()
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', test.ALL, chdir=CHDIR)
+test.run_built_executable('program', stdout="1\n2\n", chdir=CHDIR)
+test.pass_test()
diff --git a/gyp/test/dependencies/lib_only.gyp b/gyp/test/dependencies/lib_only.gyp
new file mode 100755 (executable)
index 0000000..f6c84de
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'a',
+      'type': 'static_library',
+      'sources': [
+        'a.c',
+      ],
+      'dependencies': ['b/b.gyp:b'],
+    },
+  ],
+}
diff --git a/gyp/test/dependencies/main.c b/gyp/test/dependencies/main.c
new file mode 100644 (file)
index 0000000..185bd48
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+extern int funcA();
+
+int main() {
+  printf("%d\n", funcA());
+  return 0;
+}
diff --git a/gyp/test/dependencies/none_traversal.gyp b/gyp/test/dependencies/none_traversal.gyp
new file mode 100755 (executable)
index 0000000..3d8ab30
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'needs_chain',
+      'type': 'executable',
+      'sources': [
+        'a.c',
+        'main.c',
+      ],
+      'dependencies': ['chain'],
+    },
+    {
+      'target_name': 'chain',
+      'type': 'none',
+      'dependencies': ['b/b.gyp:b'],
+    },
+    {
+      'target_name': 'doesnt_need_chain',
+      'type': 'executable',
+      'sources': [
+        'main.c',
+      ],
+      'dependencies': ['no_chain', 'other_chain'],
+    },
+    {
+      'target_name': 'no_chain',
+      'type': 'none',
+      'sources': [
+      ],
+      'dependencies': ['b/b.gyp:b'],
+      'dependencies_traverse': 0,
+    },
+    {
+      'target_name': 'other_chain',
+      'type': 'static_library',
+      'sources': [
+        'a.c',
+      ],
+      'dependencies': ['b/b.gyp:b3'],
+    },
+  ],
+}
diff --git a/gyp/test/dependencies/sharedlib-linksettings/program.c b/gyp/test/dependencies/sharedlib-linksettings/program.c
new file mode 100644 (file)
index 0000000..b7c15ed
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2013 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+/*
+ * This will fail to compile if TEST_DEFINE was propagated from sharedlib to
+ * program.
+ */
+#ifdef TEST_DEFINE
+#error TEST_DEFINE is already defined!
+#endif
+
+#define TEST_DEFINE 2
+
+extern int staticLibFunc();
+
+int main() {
+  printf("%d\n", staticLibFunc());
+  printf("%d\n", TEST_DEFINE);
+  return 0;
+}
diff --git a/gyp/test/dependencies/sharedlib-linksettings/sharedlib.c b/gyp/test/dependencies/sharedlib-linksettings/sharedlib.c
new file mode 100644 (file)
index 0000000..3199bcc
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2013 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sharedLibFunc() {
+  /*
+   * This will fail to compile if TEST_DEFINE was not obtained from sharedlib's
+   * link_settings.
+   */
+  return TEST_DEFINE;
+}
diff --git a/gyp/test/dependencies/sharedlib-linksettings/staticlib.c b/gyp/test/dependencies/sharedlib-linksettings/staticlib.c
new file mode 100644 (file)
index 0000000..e889b41
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * This will fail to compile if TEST_DEFINE was propagated from sharedlib to
+ * staticlib.
+ */
+#ifdef TEST_DEFINE
+#error TEST_DEFINE is defined!
+#endif
+
+#ifdef _WIN32
+__declspec(dllimport)
+#else
+extern
+#endif
+int sharedLibFunc();
+
+int staticLibFunc() {
+  return sharedLibFunc();
+}
diff --git a/gyp/test/dependencies/sharedlib-linksettings/test.gyp b/gyp/test/dependencies/sharedlib-linksettings/test.gyp
new file mode 100644 (file)
index 0000000..830ce32
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'allow_sharedlib_linksettings_propagation': 0,
+  },
+  'targets': [
+    {
+      'target_name': 'sharedlib',
+      'type': 'shared_library',
+      'sources': [ 'sharedlib.c' ],
+      'link_settings': {
+        'defines': [ 'TEST_DEFINE=1' ],
+      },
+      'conditions': [
+        ['OS=="linux"', {
+          # Support 64-bit shared libs (also works fine for 32-bit).
+          'cflags': ['-fPIC'],
+        }],
+      ],
+    },
+    {
+      'target_name': 'staticlib',
+      'type': 'static_library',
+      'sources': [ 'staticlib.c' ],
+      'dependencies': [ 'sharedlib' ],
+    },
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'sources': [ 'program.c' ],
+      'dependencies': [ 'staticlib' ],
+    },
+  ],
+}
diff --git a/gyp/test/dependency-copy/gyptest-copy.py b/gyp/test/dependency-copy/gyptest-copy.py
new file mode 100755 (executable)
index 0000000..5ba7c73
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies dependencies do the copy step.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('copies.gyp', chdir='src')
+
+test.build('copies.gyp', 'proj2', chdir='src')
+
+test.run_built_executable('proj1',
+                          chdir='src',
+                          stdout="Hello from file1.c\n")
+test.run_built_executable('proj2',
+                          chdir='src',
+                          stdout="Hello from file2.c\n")
+
+test.pass_test()
diff --git a/gyp/test/dependency-copy/src/copies.gyp b/gyp/test/dependency-copy/src/copies.gyp
new file mode 100644 (file)
index 0000000..4176b18
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'proj1',
+      'type': 'executable',
+      'sources': [
+        'file1.c',
+      ],
+    },
+    {
+      'target_name': 'proj2',
+      'type': 'executable',
+      'sources': [
+        'file2.c',
+      ],
+      'dependencies': [
+        'proj1',
+      ]
+    },
+  ],
+}
diff --git a/gyp/test/dependency-copy/src/file1.c b/gyp/test/dependency-copy/src/file1.c
new file mode 100644 (file)
index 0000000..d7c3159
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from file1.c\n");
+  return 0;
+}
diff --git a/gyp/test/dependency-copy/src/file2.c b/gyp/test/dependency-copy/src/file2.c
new file mode 100644 (file)
index 0000000..cf40f57
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from file2.c\n");
+  return 0;
+}
diff --git a/gyp/test/errors/duplicate_basenames.gyp b/gyp/test/errors/duplicate_basenames.gyp
new file mode 100644 (file)
index 0000000..b3dceb3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'static_library',
+      'sources': ['foo.c', 'foo.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/errors/duplicate_node.gyp b/gyp/test/errors/duplicate_node.gyp
new file mode 100644 (file)
index 0000000..d609609
--- /dev/null
@@ -0,0 +1,12 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    { 'target_name' : 'foo', 'type': 'executable' },
+  ],
+  'targets': [
+    { 'target_name' : 'bar', 'type': 'executable' },
+  ]
+}
diff --git a/gyp/test/errors/duplicate_rule.gyp b/gyp/test/errors/duplicate_rule.gyp
new file mode 100644 (file)
index 0000000..dab98e9
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'executable',
+      'rules': [
+        {
+          'rule_name': 'bar',
+          'extension': '',
+        },
+        {
+          'rule_name': 'bar',
+          'extension': '',
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/errors/duplicate_targets.gyp b/gyp/test/errors/duplicate_targets.gyp
new file mode 100644 (file)
index 0000000..aec470e
--- /dev/null
@@ -0,0 +1,14 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'foo'
+    },
+    {
+      'target_name': 'foo'
+    },
+  ]
+}
diff --git a/gyp/test/errors/gyptest-errors.py b/gyp/test/errors/gyptest-errors.py
new file mode 100755 (executable)
index 0000000..5f66bac
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test that two targets with the same name generates an error.
+"""
+
+import os
+import sys
+
+import TestGyp
+import TestCmd
+
+# TODO(sbc): Remove the use of match_re below, done because scons
+# error messages were not consistent with other generators.
+# Also remove input.py:generator_wants_absolute_build_file_paths.
+
+test = TestGyp.TestGyp()
+
+stderr = ('gyp: Duplicate target definitions for '
+          '.*duplicate_targets.gyp:foo#target\n')
+test.run_gyp('duplicate_targets.gyp', status=1, stderr=stderr,
+             match=TestCmd.match_re)
+
+stderr = ('.*: Unable to find targets in build file .*missing_targets.gyp.*')
+test.run_gyp('missing_targets.gyp', status=1, stderr=stderr,
+             match=TestCmd.match_re_dotall)
+
+stderr = ('gyp: rule bar exists in duplicate, target '
+          '.*duplicate_rule.gyp:foo#target\n')
+test.run_gyp('duplicate_rule.gyp', status=1, stderr=stderr,
+             match=TestCmd.match_re)
+
+stderr = ("gyp: Key 'targets' repeated at level 1 with key path '' while "
+          "reading .*duplicate_node.gyp.*")
+test.run_gyp('duplicate_node.gyp', '--check', status=1, stderr=stderr,
+             match=TestCmd.match_re_dotall)
+
+stderr = 'gyp: Duplicate basenames in sources section, see list above\n'
+test.run_gyp('duplicate_basenames.gyp', status=1, stderr=stderr)
+
+# Check if '--no-duplicate-basename-check' works.
+if ((test.format == 'make' and sys.platform == 'darwin') or
+    (test.format == 'msvs' and
+        int(os.environ.get('GYP_MSVS_VERSION', 2010)) < 2010)):
+  stderr = 'gyp: Duplicate basenames in sources section, see list above\n'
+  test.run_gyp('duplicate_basenames.gyp', '--no-duplicate-basename-check',
+               status=1, stderr=stderr)
+else:
+  test.run_gyp('duplicate_basenames.gyp', '--no-duplicate-basename-check')
+
+stderr = ("gyp: Dependency '.*missing_dep.gyp:missing.gyp#target' not found "
+          "while trying to load target .*missing_dep.gyp:foo#target\n")
+test.run_gyp('missing_dep.gyp', status=1, stderr=stderr,
+             match=TestCmd.match_re)
+
+test.pass_test()
diff --git a/gyp/test/errors/missing_dep.gyp b/gyp/test/errors/missing_dep.gyp
new file mode 100644 (file)
index 0000000..08746be
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'static_library',
+      'dependencies': [
+        'missing.gyp'
+      ]
+    },
+  ]
+}
diff --git a/gyp/test/errors/missing_targets.gyp b/gyp/test/errors/missing_targets.gyp
new file mode 100644 (file)
index 0000000..13d4f92
--- /dev/null
@@ -0,0 +1,8 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+  },
+}
diff --git a/gyp/test/escaping/colon/test.gyp b/gyp/test/escaping/colon/test.gyp
new file mode 100644 (file)
index 0000000..715f954
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'colon',
+      'type': 'executable',
+      'sources': [
+        'a:b.c',
+      ],
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/',
+          # MSVS2008 gets confused if the same file is in 'sources' and 'copies'
+          'files': [ 'a:b.c-d', ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/escaping/gyptest-colon.py b/gyp/test/escaping/gyptest-colon.py
new file mode 100644 (file)
index 0000000..f5275db
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests that filenames that contain colons are handled correctly.
+(This is important for absolute paths on Windows.)
+"""
+
+import os
+import sys
+import TestGyp
+
+# TODO: Make colons in filenames work with make, if required.
+test = TestGyp.TestGyp(formats=['!make', '!android'])
+CHDIR = 'colon'
+
+source_name = 'colon/a:b.c'
+copies_name = 'colon/a:b.c-d'
+if sys.platform == 'win32':
+  # Windows uses : as drive separator and doesn't allow it in regular filenames.
+  # Use abspath() to create a path that contains a colon instead.
+  abs_source = os.path.abspath('colon/file.c')
+  test.write('colon/test.gyp',
+             test.read('colon/test.gyp').replace("'a:b.c'", repr(abs_source)))
+  source_name = abs_source
+
+  abs_copies = os.path.abspath('colon/file.txt')
+  test.write('colon/test.gyp',
+             test.read('colon/test.gyp').replace("'a:b.c-d'", repr(abs_copies)))
+  copies_name = abs_copies
+
+# Create the file dynamically, Windows is unhappy if a file with a colon in
+# its name is checked in.
+test.write(source_name, 'int main() {}')
+test.write(copies_name, 'foo')
+
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', test.ALL, chdir=CHDIR)
+test.built_file_must_exist(os.path.basename(copies_name), chdir=CHDIR)
+test.pass_test()
diff --git a/gyp/test/exclusion/exclusion.gyp b/gyp/test/exclusion/exclusion.gyp
new file mode 100644 (file)
index 0000000..1232dab
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+        'bogus.c',
+        'also/not/real.c',
+        'also/not/real2.c',
+      ],
+      'sources!': [
+        'bogus.c',
+        'also/not/real.c',
+        'also/not/real2.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/exclusion/gyptest-exclusion.py b/gyp/test/exclusion/gyptest-exclusion.py
new file mode 100755 (executable)
index 0000000..1fc32bf
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that exclusions (e.g. sources!) are respected.  Excluded sources
+that do not exist should not prevent the build from succeeding.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('exclusion.gyp')
+test.build('exclusion.gyp')
+
+# executables
+test.built_file_must_exist('hello' + test._exe, test.EXECUTABLE, bare=True)
+
+test.pass_test()
diff --git a/gyp/test/exclusion/hello.c b/gyp/test/exclusion/hello.c
new file mode 100644 (file)
index 0000000..6e7dc8e
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (c) 2010 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int func1(void) {
+  return 42;
+}
+
+int main(void) {
+  printf("Hello, world!\n");
+  printf("%d\n", func1());
+  return 0;
+}
diff --git a/gyp/test/external-cross-compile/gyptest-cross.py b/gyp/test/external-cross-compile/gyptest-cross.py
new file mode 100755 (executable)
index 0000000..a837ec5
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that actions can be + a source scanner can be used to implement,
+cross-compiles (for Native Client at this point).
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('cross.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('cross.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+From test1.cc
+From test2.c
+From test3.cc
+From test4.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.pass_test()
diff --git a/gyp/test/external-cross-compile/src/bogus1.cc b/gyp/test/external-cross-compile/src/bogus1.cc
new file mode 100644 (file)
index 0000000..1b8d011
--- /dev/null
@@ -0,0 +1 @@
+From bogus1.cc
diff --git a/gyp/test/external-cross-compile/src/bogus2.c b/gyp/test/external-cross-compile/src/bogus2.c
new file mode 100644 (file)
index 0000000..cbf4a12
--- /dev/null
@@ -0,0 +1 @@
+From bogus2.c
diff --git a/gyp/test/external-cross-compile/src/cross.gyp b/gyp/test/external-cross-compile/src/cross.gyp
new file mode 100644 (file)
index 0000000..aeda76b
--- /dev/null
@@ -0,0 +1,83 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': ['cross_compile.gypi'],
+  'target_defaults': {
+    'variables': {
+      'nix_lame%': 0,
+    },
+    'target_conditions': [
+      ['nix_lame==1', {
+        'sources/': [
+          ['exclude', 'lame'],
+        ],
+      }],
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'dependencies': [
+        'program_inc',
+      ],
+      'include_dirs': [
+        '<(SHARED_INTERMEDIATE_DIR)',
+      ],
+      'sources': [
+        'program.cc',
+      ],
+    },
+    {
+      'target_name': 'program_inc',
+      'type': 'none',
+      'dependencies': ['cross_program'],
+      'actions': [
+        {
+          'action_name': 'program_inc',
+          'inputs': ['<(SHARED_INTERMEDIATE_DIR)/cross_program.fake'],
+          'outputs': ['<(SHARED_INTERMEDIATE_DIR)/cross_program.h'],
+          'action': ['python', 'tochar.py', '<@(_inputs)', '<@(_outputs)'],
+        },
+      ],
+      # Allows the test to run without hermetic cygwin on windows.
+      'msvs_cygwin_shell': 0,
+    },
+    {
+      'target_name': 'cross_program',
+      'type': 'none',
+      'variables': {
+        'cross': 1,
+        'nix_lame': 1,
+      },
+      'dependencies': ['cross_lib'],
+      'sources': [
+        'test1.cc',
+        'test2.c',
+        'very_lame.cc',
+        '<(SHARED_INTERMEDIATE_DIR)/cross_lib.fake',
+      ],
+    },
+    {
+      'target_name': 'cross_lib',
+      'type': 'none',
+      'variables': {
+        'cross': 1,
+        'nix_lame': 1,
+      },
+      'sources': [
+        'test3.cc',
+        'test4.c',
+        'bogus1.cc',
+        'bogus2.c',
+        'sort_of_lame.cc',
+      ],
+      'sources!': [
+        'bogus1.cc',
+        'bogus2.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/external-cross-compile/src/cross_compile.gypi b/gyp/test/external-cross-compile/src/cross_compile.gypi
new file mode 100644 (file)
index 0000000..36e6519
--- /dev/null
@@ -0,0 +1,23 @@
+{
+  'target_defaults': {
+    'variables': {
+      'cross%': 0,
+    },
+    'target_conditions': [
+      ['cross==1', {
+        'actions': [
+          {
+            'action_name': 'cross compile >(_target_name)',
+            'inputs': ['^@(_sources)'],
+            'outputs': ['<(SHARED_INTERMEDIATE_DIR)/>(_target_name).fake'],
+            'action': [
+              'python', 'fake_cross.py', '>@(_outputs)', '^@(_sources)',
+            ],
+            # Allows the test to run without hermetic cygwin on windows.
+            'msvs_cygwin_shell': 0,
+          },
+        ],
+      }],
+    ],
+  },
+}
diff --git a/gyp/test/external-cross-compile/src/fake_cross.py b/gyp/test/external-cross-compile/src/fake_cross.py
new file mode 100644 (file)
index 0000000..05eacc6
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+fh = open(sys.argv[1], 'w')
+
+filenames = sys.argv[2:]
+
+for filename in filenames:
+  subfile = open(filename)
+  data = subfile.read()
+  subfile.close()
+  fh.write(data)
+
+fh.close()
diff --git a/gyp/test/external-cross-compile/src/program.cc b/gyp/test/external-cross-compile/src/program.cc
new file mode 100644 (file)
index 0000000..5172ae9
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+static char data[] = {
+#include "cross_program.h"
+};
+
+int main(void) {
+  fwrite(data, 1, sizeof(data), stdout);
+  return 0;
+}
diff --git a/gyp/test/external-cross-compile/src/test1.cc b/gyp/test/external-cross-compile/src/test1.cc
new file mode 100644 (file)
index 0000000..b584c31
--- /dev/null
@@ -0,0 +1 @@
+From test1.cc
diff --git a/gyp/test/external-cross-compile/src/test2.c b/gyp/test/external-cross-compile/src/test2.c
new file mode 100644 (file)
index 0000000..367ae19
--- /dev/null
@@ -0,0 +1 @@
+From test2.c
diff --git a/gyp/test/external-cross-compile/src/test3.cc b/gyp/test/external-cross-compile/src/test3.cc
new file mode 100644 (file)
index 0000000..9eb6473
--- /dev/null
@@ -0,0 +1 @@
+From test3.cc
diff --git a/gyp/test/external-cross-compile/src/test4.c b/gyp/test/external-cross-compile/src/test4.c
new file mode 100644 (file)
index 0000000..8ecc33e
--- /dev/null
@@ -0,0 +1 @@
+From test4.c
diff --git a/gyp/test/external-cross-compile/src/tochar.py b/gyp/test/external-cross-compile/src/tochar.py
new file mode 100644 (file)
index 0000000..c0780d9
--- /dev/null
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+src = open(sys.argv[1])
+dst = open(sys.argv[2], 'w')
+for ch in src.read():
+  dst.write('%d,\n' % ord(ch))
+src.close()
+dst.close()
diff --git a/gyp/test/generator-output/actions/actions.gyp b/gyp/test/generator-output/actions/actions.gyp
new file mode 100644 (file)
index 0000000..dded59a
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'pull_in_all_actions',
+      'type': 'none',
+      'dependencies': [
+        'subdir1/executable.gyp:*',
+        'subdir2/none.gyp:*',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/actions/build/README.txt b/gyp/test/generator-output/actions/build/README.txt
new file mode 100644 (file)
index 0000000..1b052c9
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the\r
+test script can verify that .xcodeproj files are not created in\r
+their normal location by making the src/ read-only, and then\r
+selectively making this build directory writable.\r
diff --git a/gyp/test/generator-output/actions/subdir1/actions-out/README.txt b/gyp/test/generator-output/actions/subdir1/actions-out/README.txt
new file mode 100644 (file)
index 0000000..1b052c9
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the\r
+test script can verify that .xcodeproj files are not created in\r
+their normal location by making the src/ read-only, and then\r
+selectively making this build directory writable.\r
diff --git a/gyp/test/generator-output/actions/subdir1/build/README.txt b/gyp/test/generator-output/actions/subdir1/build/README.txt
new file mode 100644 (file)
index 0000000..1b052c9
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the\r
+test script can verify that .xcodeproj files are not created in\r
+their normal location by making the src/ read-only, and then\r
+selectively making this build directory writable.\r
diff --git a/gyp/test/generator-output/actions/subdir1/executable.gyp b/gyp/test/generator-output/actions/subdir1/executable.gyp
new file mode 100644 (file)
index 0000000..6bdd60a
--- /dev/null
@@ -0,0 +1,44 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'program.c',
+      ],
+      'actions': [
+        {
+          'action_name': 'make-prog1',
+          'inputs': [
+            'make-prog1.py',
+          ],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/prog1.c',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+        {
+          'action_name': 'make-prog2',
+          'inputs': [
+            'make-prog2.py',
+          ],
+          'outputs': [
+            'actions-out/prog2.c',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/actions/subdir1/make-prog1.py b/gyp/test/generator-output/actions/subdir1/make-prog1.py
new file mode 100755 (executable)
index 0000000..7ea1d8a
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = r"""
+#include <stdio.h>
+
+void prog1(void)
+{
+  printf("Hello from make-prog1.py\n");
+}
+"""
+
+open(sys.argv[1], 'w').write(contents)
+
+sys.exit(0)
diff --git a/gyp/test/generator-output/actions/subdir1/make-prog2.py b/gyp/test/generator-output/actions/subdir1/make-prog2.py
new file mode 100755 (executable)
index 0000000..0bfe497
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = r"""
+#include <stdio.h>
+
+void prog2(void)
+{
+  printf("Hello from make-prog2.py\n");
+}
+"""
+
+open(sys.argv[1], 'w').write(contents)
+
+sys.exit(0)
diff --git a/gyp/test/generator-output/actions/subdir1/program.c b/gyp/test/generator-output/actions/subdir1/program.c
new file mode 100644 (file)
index 0000000..c093153
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>\r
+\r
+extern void prog1(void);\r
+extern void prog2(void);\r
+\r
+int main(void)
+{\r
+  printf("Hello from program.c\n");\r
+  prog1();\r
+  prog2();\r
+  return 0;\r
+}\r
diff --git a/gyp/test/generator-output/actions/subdir2/actions-out/README.txt b/gyp/test/generator-output/actions/subdir2/actions-out/README.txt
new file mode 100644 (file)
index 0000000..1b052c9
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the\r
+test script can verify that .xcodeproj files are not created in\r
+their normal location by making the src/ read-only, and then\r
+selectively making this build directory writable.\r
diff --git a/gyp/test/generator-output/actions/subdir2/build/README.txt b/gyp/test/generator-output/actions/subdir2/build/README.txt
new file mode 100644 (file)
index 0000000..1b052c9
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the\r
+test script can verify that .xcodeproj files are not created in\r
+their normal location by making the src/ read-only, and then\r
+selectively making this build directory writable.\r
diff --git a/gyp/test/generator-output/actions/subdir2/make-file.py b/gyp/test/generator-output/actions/subdir2/make-file.py
new file mode 100755 (executable)
index 0000000..fff0653
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = "Hello from make-file.py\n"
+
+open(sys.argv[1], 'wb').write(contents)
diff --git a/gyp/test/generator-output/actions/subdir2/none.gyp b/gyp/test/generator-output/actions/subdir2/none.gyp
new file mode 100644 (file)
index 0000000..f98f527
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'file',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'actions': [
+        {
+          'action_name': 'make-file',
+          'inputs': [
+            'make-file.py',
+          ],
+          'outputs': [
+            'actions-out/file.out',
+            # TODO:  enhance testing infrastructure to test this
+            # without having to hard-code the intermediate dir paths.
+            #'<(INTERMEDIATE_DIR)/file.out',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        }
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/copies/build/README.txt b/gyp/test/generator-output/copies/build/README.txt
new file mode 100644 (file)
index 0000000..90ef886
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/gyp/test/generator-output/copies/copies-out/README.txt b/gyp/test/generator-output/copies/copies-out/README.txt
new file mode 100644 (file)
index 0000000..90ef886
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/gyp/test/generator-output/copies/copies.gyp b/gyp/test/generator-output/copies/copies.gyp
new file mode 100644 (file)
index 0000000..479a3d9
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'pull_in_subdir',
+      'type': 'none',
+      'dependencies': [
+        'subdir/subdir.gyp:*',
+      ],
+    },
+    {
+      'target_name': 'copies1',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': 'copies-out',
+          'files': [
+            'file1',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'copies2',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/copies-out',
+          'files': [
+            'file2',
+          ],
+        },
+      ],
+    },
+    # Verify that a null 'files' list doesn't gag the generators.
+    {
+      'target_name': 'copies_null',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/copies-null',
+          'files': [],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/copies/file1 b/gyp/test/generator-output/copies/file1
new file mode 100644 (file)
index 0000000..84d55c5
--- /dev/null
@@ -0,0 +1 @@
+file1 contents
diff --git a/gyp/test/generator-output/copies/file2 b/gyp/test/generator-output/copies/file2
new file mode 100644 (file)
index 0000000..af1b8ae
--- /dev/null
@@ -0,0 +1 @@
+file2 contents
diff --git a/gyp/test/generator-output/copies/subdir/build/README.txt b/gyp/test/generator-output/copies/subdir/build/README.txt
new file mode 100644 (file)
index 0000000..90ef886
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/gyp/test/generator-output/copies/subdir/copies-out/README.txt b/gyp/test/generator-output/copies/subdir/copies-out/README.txt
new file mode 100644 (file)
index 0000000..90ef886
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/gyp/test/generator-output/copies/subdir/file3 b/gyp/test/generator-output/copies/subdir/file3
new file mode 100644 (file)
index 0000000..43f16f3
--- /dev/null
@@ -0,0 +1 @@
+file3 contents
diff --git a/gyp/test/generator-output/copies/subdir/file4 b/gyp/test/generator-output/copies/subdir/file4
new file mode 100644 (file)
index 0000000..5f7270a
--- /dev/null
@@ -0,0 +1 @@
+file4 contents
diff --git a/gyp/test/generator-output/copies/subdir/subdir.gyp b/gyp/test/generator-output/copies/subdir/subdir.gyp
new file mode 100644 (file)
index 0000000..af031d2
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'copies3',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': 'copies-out',
+          'files': [
+            'file3',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'copies4',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/copies-out',
+          'files': [
+            'file4',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/gyptest-actions.py b/gyp/test/generator-output/gyptest-actions.py
new file mode 100755 (executable)
index 0000000..8c912e4
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies --generator-output= behavior when using actions.
+"""
+
+import TestGyp
+
+# Android doesn't support --generator-output.
+test = TestGyp.TestGyp(formats=['!android'])
+
+# All the generated files should go under 'gypfiles'. The source directory
+# ('actions') should be untouched.
+test.writable(test.workpath('actions'), False)
+test.run_gyp('actions.gyp',
+             '--generator-output=' + test.workpath('gypfiles'),
+             '-G', 'xcode_ninja_target_pattern=^pull_in_all_actions$',
+             chdir='actions')
+
+test.writable(test.workpath('actions'), True)
+
+test.relocate('actions', 'relocate/actions')
+test.relocate('gypfiles', 'relocate/gypfiles')
+
+test.writable(test.workpath('relocate/actions'), False)
+
+# Some of the action outputs use "pure" relative paths (i.e. without prefixes
+# like <(INTERMEDIATE_DIR) or <(PROGRAM_DIR)). Even though we are building under
+# 'gypfiles', such outputs will still be created relative to the original .gyp
+# sources. Projects probably wouldn't normally do this, since it kind of defeats
+# the purpose of '--generator-output', but it is supported behaviour.
+test.writable(test.workpath('relocate/actions/build'), True)
+test.writable(test.workpath('relocate/actions/subdir1/build'), True)
+test.writable(test.workpath('relocate/actions/subdir1/actions-out'), True)
+test.writable(test.workpath('relocate/actions/subdir2/build'), True)
+test.writable(test.workpath('relocate/actions/subdir2/actions-out'), True)
+
+test.build('actions.gyp', test.ALL, chdir='relocate/gypfiles')
+
+expect = """\
+Hello from program.c
+Hello from make-prog1.py
+Hello from make-prog2.py
+"""
+
+if test.format == 'xcode':
+  chdir = 'relocate/actions/subdir1'
+else:
+  chdir = 'relocate/gypfiles'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+test.must_match('relocate/actions/subdir2/actions-out/file.out',
+                "Hello from make-file.py\n")
+
+test.pass_test()
diff --git a/gyp/test/generator-output/gyptest-copies.py b/gyp/test/generator-output/gyptest-copies.py
new file mode 100755 (executable)
index 0000000..909aebf
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies file copies with --generator-output using an explicit build
+target of 'all'.
+"""
+
+import TestGyp
+
+# Android doesn't support --generator-output.
+test = TestGyp.TestGyp(formats=['!android'])
+
+test.writable(test.workpath('copies'), False)
+
+test.run_gyp('copies.gyp',
+             '--generator-output=' + test.workpath('gypfiles'),
+             '-G', 'xcode_ninja_target_pattern=^(?!copies_null)',
+             chdir='copies')
+
+test.writable(test.workpath('copies'), True)
+
+test.relocate('copies', 'relocate/copies')
+test.relocate('gypfiles', 'relocate/gypfiles')
+
+test.writable(test.workpath('relocate/copies'), False)
+
+test.writable(test.workpath('relocate/copies/build'), True)
+test.writable(test.workpath('relocate/copies/copies-out'), True)
+test.writable(test.workpath('relocate/copies/subdir/build'), True)
+test.writable(test.workpath('relocate/copies/subdir/copies-out'), True)
+
+test.build('copies.gyp', test.ALL, chdir='relocate/gypfiles')
+
+test.must_match(['relocate', 'copies', 'copies-out', 'file1'],
+                "file1 contents\n")
+
+if test.format == 'xcode':
+  chdir = 'relocate/copies/build'
+elif test.format in ['make', 'ninja', 'xcode-ninja', 'cmake']:
+  chdir = 'relocate/gypfiles/out'
+else:
+  chdir = 'relocate/gypfiles'
+test.must_match([chdir, 'Default', 'copies-out', 'file2'], "file2 contents\n")
+
+test.must_match(['relocate', 'copies', 'subdir', 'copies-out', 'file3'],
+                "file3 contents\n")
+
+if test.format == 'xcode':
+  chdir = 'relocate/copies/subdir/build'
+elif test.format in ['make', 'ninja', 'xcode-ninja', 'cmake']:
+  chdir = 'relocate/gypfiles/out'
+else:
+  chdir = 'relocate/gypfiles'
+test.must_match([chdir, 'Default', 'copies-out', 'file4'], "file4 contents\n")
+
+test.pass_test()
diff --git a/gyp/test/generator-output/gyptest-depth.py b/gyp/test/generator-output/gyptest-depth.py
new file mode 100755 (executable)
index 0000000..ee59a11
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a project hierarchy created when the --generator-output=
+and --depth= options is used to put the build configuration files in a separate
+directory tree.
+"""
+
+import TestGyp
+import os
+
+# This is a regression test for the make generator only.
+test = TestGyp.TestGyp(formats=['make'])
+
+test.writable(test.workpath('src'), False)
+
+toplevel_dir = os.path.basename(test.workpath())
+
+test.run_gyp(os.path.join(toplevel_dir, 'src', 'prog1.gyp'),
+             '-Dset_symroot=1',
+             '--generator-output=gypfiles',
+             depth=toplevel_dir,
+             chdir='..')
+
+test.writable(test.workpath('src/build'), True)
+test.writable(test.workpath('src/subdir2/build'), True)
+test.writable(test.workpath('src/subdir3/build'), True)
+
+test.build('prog1.gyp', test.ALL, chdir='gypfiles')
+
+chdir = 'gypfiles'
+
+expect = """\
+Hello from %s
+Hello from inc.h
+Hello from inc1/include1.h
+Hello from inc2/include2.h
+Hello from inc3/include3.h
+Hello from subdir2/deeper/deeper.h
+"""
+
+if test.format == 'xcode':
+  chdir = 'src'
+test.run_built_executable('prog1', chdir=chdir, stdout=expect % 'prog1.c')
+
+if test.format == 'xcode':
+  chdir = 'src/subdir2'
+test.run_built_executable('prog2', chdir=chdir, stdout=expect % 'prog2.c')
+
+if test.format == 'xcode':
+  chdir = 'src/subdir3'
+test.run_built_executable('prog3', chdir=chdir, stdout=expect % 'prog3.c')
+
+test.pass_test()
diff --git a/gyp/test/generator-output/gyptest-mac-bundle.py b/gyp/test/generator-output/gyptest-mac-bundle.py
new file mode 100644 (file)
index 0000000..840e1ec
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies mac bundles work with --generator-output.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=[])
+
+  MAC_BUNDLE_DIR = 'mac-bundle'
+  GYPFILES_DIR = 'gypfiles'
+  test.writable(test.workpath(MAC_BUNDLE_DIR), False)
+  test.run_gyp('test.gyp',
+               '--generator-output=' + test.workpath(GYPFILES_DIR),
+               chdir=MAC_BUNDLE_DIR)
+  test.writable(test.workpath(MAC_BUNDLE_DIR), True)
+
+  test.build('test.gyp', test.ALL, chdir=GYPFILES_DIR)
+
+  test.pass_test()
diff --git a/gyp/test/generator-output/gyptest-relocate.py b/gyp/test/generator-output/gyptest-relocate.py
new file mode 100755 (executable)
index 0000000..4d60a1e
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a project hierarchy created with the --generator-output=
+option can be built even when it's relocated to a different path.
+"""
+
+import TestGyp
+
+# Android doesn't support --generator-output.
+test = TestGyp.TestGyp(formats=['!android'])
+
+test.writable(test.workpath('src'), False)
+
+test.run_gyp('prog1.gyp',
+             '-Dset_symroot=1',
+             '--generator-output=' + test.workpath('gypfiles'),
+             chdir='src')
+
+test.writable(test.workpath('src'), True)
+
+test.relocate('src', 'relocate/src')
+test.relocate('gypfiles', 'relocate/gypfiles')
+
+test.writable(test.workpath('relocate/src'), False)
+
+test.writable(test.workpath('relocate/src/build'), True)
+test.writable(test.workpath('relocate/src/subdir2/build'), True)
+test.writable(test.workpath('relocate/src/subdir3/build'), True)
+
+test.build('prog1.gyp', test.ALL, chdir='relocate/gypfiles')
+
+chdir = 'relocate/gypfiles'
+
+expect = """\
+Hello from %s
+Hello from inc.h
+Hello from inc1/include1.h
+Hello from inc2/include2.h
+Hello from inc3/include3.h
+Hello from subdir2/deeper/deeper.h
+"""
+
+if test.format == 'xcode':
+  chdir = 'relocate/src'
+test.run_built_executable('prog1', chdir=chdir, stdout=expect % 'prog1.c')
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir2'
+test.run_built_executable('prog2', chdir=chdir, stdout=expect % 'prog2.c')
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir3'
+test.run_built_executable('prog3', chdir=chdir, stdout=expect % 'prog3.c')
+
+test.pass_test()
diff --git a/gyp/test/generator-output/gyptest-rules.py b/gyp/test/generator-output/gyptest-rules.py
new file mode 100755 (executable)
index 0000000..b95e005
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies --generator-output= behavior when using rules.
+"""
+
+import TestGyp
+
+# Android doesn't support --generator-output.
+test = TestGyp.TestGyp(formats=['!android'])
+
+test.writable(test.workpath('rules'), False)
+
+test.run_gyp('rules.gyp',
+             '--generator-output=' + test.workpath('gypfiles'),
+             '-G', 'xcode_ninja_target_pattern=^pull_in_all_actions$',
+             chdir='rules')
+
+test.writable(test.workpath('rules'), True)
+
+test.relocate('rules', 'relocate/rules')
+test.relocate('gypfiles', 'relocate/gypfiles')
+
+test.writable(test.workpath('relocate/rules'), False)
+
+test.writable(test.workpath('relocate/rules/build'), True)
+test.writable(test.workpath('relocate/rules/subdir1/build'), True)
+test.writable(test.workpath('relocate/rules/subdir2/build'), True)
+test.writable(test.workpath('relocate/rules/subdir2/rules-out'), True)
+
+test.build('rules.gyp', test.ALL, chdir='relocate/gypfiles')
+
+expect = """\
+Hello from program.c
+Hello from function1.in1
+Hello from function2.in1
+Hello from define3.in0
+Hello from define4.in0
+"""
+
+if test.format == 'xcode':
+  chdir = 'relocate/rules/subdir1'
+else:
+  chdir = 'relocate/gypfiles'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+test.must_match('relocate/rules/subdir2/rules-out/file1.out',
+                "Hello from file1.in0\n")
+test.must_match('relocate/rules/subdir2/rules-out/file2.out',
+                "Hello from file2.in0\n")
+test.must_match('relocate/rules/subdir2/rules-out/file3.out',
+                "Hello from file3.in1\n")
+test.must_match('relocate/rules/subdir2/rules-out/file4.out',
+                "Hello from file4.in1\n")
+
+test.pass_test()
diff --git a/gyp/test/generator-output/gyptest-subdir2-deep.py b/gyp/test/generator-output/gyptest-subdir2-deep.py
new file mode 100755 (executable)
index 0000000..305e178
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target from a .gyp file a few subdirectories
+deep when the --generator-output= option is used to put the build
+configuration files in a separate directory tree.
+"""
+
+import TestGyp
+
+# Android doesn't support --generator-output.
+test = TestGyp.TestGyp(formats=['!android'])
+
+test.writable(test.workpath('src'), False)
+
+test.writable(test.workpath('src/subdir2/deeper/build'), True)
+
+test.run_gyp('deeper.gyp',
+             '-Dset_symroot=1',
+             '--generator-output=' + test.workpath('gypfiles'),
+             chdir='src/subdir2/deeper')
+
+test.build('deeper.gyp', test.ALL, chdir='gypfiles')
+
+chdir = 'gypfiles'
+
+if test.format == 'xcode':
+  chdir = 'src/subdir2/deeper'
+test.run_built_executable('deeper',
+                          chdir=chdir,
+                          stdout="Hello from deeper.c\n")
+
+test.pass_test()
diff --git a/gyp/test/generator-output/gyptest-symlink.py b/gyp/test/generator-output/gyptest-symlink.py
new file mode 100755 (executable)
index 0000000..7390fcd
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target when the --generator-output= option is used to put
+the build configuration files in a separate directory tree referenced by a
+symlink.
+"""
+
+import TestGyp
+import os
+
+# Android doesn't support --generator-output.
+test = TestGyp.TestGyp(formats=['!android'])
+if not hasattr(os, 'symlink'):
+  test.skip_test('Missing os.symlink -- skipping test.\n')
+
+test.writable(test.workpath('src'), False)
+
+test.writable(test.workpath('src/subdir2/deeper/build'), True)
+
+test.subdir(test.workpath('build'))
+test.subdir(test.workpath('build/deeper'))
+test.symlink('build/deeper', test.workpath('symlink'))
+
+test.writable(test.workpath('build/deeper'), True)
+test.run_gyp('deeper.gyp',
+             '-Dset_symroot=2',
+             '--generator-output=' + test.workpath('symlink'),
+             chdir='src/subdir2/deeper')
+
+chdir = 'symlink'
+test.build('deeper.gyp', test.ALL, chdir=chdir)
+
+if test.format == 'xcode':
+  chdir = 'src/subdir2/deeper'
+test.run_built_executable('deeper',
+                          chdir=chdir,
+                          stdout="Hello from deeper.c\n")
+test.pass_test()
diff --git a/gyp/test/generator-output/gyptest-top-all.py b/gyp/test/generator-output/gyptest-top-all.py
new file mode 100755 (executable)
index 0000000..c1d9f60
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a project hierarchy created when the --generator-output=
+option is used to put the build configuration files in a separate
+directory tree.
+"""
+
+import TestGyp
+
+# Android doesn't support --generator-output.
+test = TestGyp.TestGyp(formats=['!android'])
+
+test.writable(test.workpath('src'), False)
+
+test.run_gyp('prog1.gyp',
+             '-Dset_symroot=1',
+             '--generator-output=' + test.workpath('gypfiles'),
+             chdir='src')
+
+test.writable(test.workpath('src/build'), True)
+test.writable(test.workpath('src/subdir2/build'), True)
+test.writable(test.workpath('src/subdir3/build'), True)
+
+test.build('prog1.gyp', test.ALL, chdir='gypfiles')
+
+chdir = 'gypfiles'
+
+expect = """\
+Hello from %s
+Hello from inc.h
+Hello from inc1/include1.h
+Hello from inc2/include2.h
+Hello from inc3/include3.h
+Hello from subdir2/deeper/deeper.h
+"""
+
+if test.format == 'xcode':
+  chdir = 'src'
+test.run_built_executable('prog1', chdir=chdir, stdout=expect % 'prog1.c')
+
+if test.format == 'xcode':
+  chdir = 'src/subdir2'
+test.run_built_executable('prog2', chdir=chdir, stdout=expect % 'prog2.c')
+
+if test.format == 'xcode':
+  chdir = 'src/subdir3'
+test.run_built_executable('prog3', chdir=chdir, stdout=expect % 'prog3.c')
+
+test.pass_test()
diff --git a/gyp/test/generator-output/mac-bundle/Info.plist b/gyp/test/generator-output/mac-bundle/Info.plist
new file mode 100644 (file)
index 0000000..8cb142e
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.google.${PRODUCT_NAME}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>ause</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+       <key>NSMainNibFile</key>
+       <string>MainMenu</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/gyp/test/generator-output/mac-bundle/app.order b/gyp/test/generator-output/mac-bundle/app.order
new file mode 100644 (file)
index 0000000..4eb9e89
--- /dev/null
@@ -0,0 +1 @@
+_main
diff --git a/gyp/test/generator-output/mac-bundle/header.h b/gyp/test/generator-output/mac-bundle/header.h
new file mode 100644 (file)
index 0000000..7ed7775
--- /dev/null
@@ -0,0 +1 @@
+int f();
diff --git a/gyp/test/generator-output/mac-bundle/main.c b/gyp/test/generator-output/mac-bundle/main.c
new file mode 100644 (file)
index 0000000..237c8ce
--- /dev/null
@@ -0,0 +1 @@
+int main() {}
diff --git a/gyp/test/generator-output/mac-bundle/resource.sb b/gyp/test/generator-output/mac-bundle/resource.sb
new file mode 100644 (file)
index 0000000..731befc
--- /dev/null
@@ -0,0 +1 @@
+A text file.
diff --git a/gyp/test/generator-output/mac-bundle/test.gyp b/gyp/test/generator-output/mac-bundle/test.gyp
new file mode 100644 (file)
index 0000000..35ac674
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test App Gyp',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'main.c',
+      ],
+      'mac_bundle_resources': [
+        'resource.sb',
+      ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+        'ORDER_FILE': 'app.order',
+        'GCC_PREFIX_HEADER': 'header.h',
+        'GCC_PRECOMPILE_PREFIX_HEADER': 'YES',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/rules/build/README.txt b/gyp/test/generator-output/rules/build/README.txt
new file mode 100644 (file)
index 0000000..1b052c9
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the\r
+test script can verify that .xcodeproj files are not created in\r
+their normal location by making the src/ read-only, and then\r
+selectively making this build directory writable.\r
diff --git a/gyp/test/generator-output/rules/copy-file.py b/gyp/test/generator-output/rules/copy-file.py
new file mode 100755 (executable)
index 0000000..938c336
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = open(sys.argv[1], 'r').read()
+open(sys.argv[2], 'wb').write(contents)
+
+sys.exit(0)
diff --git a/gyp/test/generator-output/rules/rules.gyp b/gyp/test/generator-output/rules/rules.gyp
new file mode 100644 (file)
index 0000000..dded59a
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'pull_in_all_actions',
+      'type': 'none',
+      'dependencies': [
+        'subdir1/executable.gyp:*',
+        'subdir2/none.gyp:*',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/rules/subdir1/build/README.txt b/gyp/test/generator-output/rules/subdir1/build/README.txt
new file mode 100644 (file)
index 0000000..1b052c9
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the\r
+test script can verify that .xcodeproj files are not created in\r
+their normal location by making the src/ read-only, and then\r
+selectively making this build directory writable.\r
diff --git a/gyp/test/generator-output/rules/subdir1/define3.in0 b/gyp/test/generator-output/rules/subdir1/define3.in0
new file mode 100644 (file)
index 0000000..cc29c64
--- /dev/null
@@ -0,0 +1 @@
+#define STRING3 "Hello from define3.in0\n"
diff --git a/gyp/test/generator-output/rules/subdir1/define4.in0 b/gyp/test/generator-output/rules/subdir1/define4.in0
new file mode 100644 (file)
index 0000000..c9b0467
--- /dev/null
@@ -0,0 +1 @@
+#define STRING4 "Hello from define4.in0\n"
diff --git a/gyp/test/generator-output/rules/subdir1/executable.gyp b/gyp/test/generator-output/rules/subdir1/executable.gyp
new file mode 100644 (file)
index 0000000..42bee4d
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'program.c',
+        'function1.in1',
+        'function2.in1',
+        'define3.in0',
+        'define4.in0',
+      ],
+      'include_dirs': [
+        '<(INTERMEDIATE_DIR)',
+      ],
+      'rules': [
+        {
+          'rule_name': 'copy_file_0',
+          'extension': 'in0',
+          'inputs': [
+            '../copy-file.py',
+          ],
+          'outputs': [
+            # TODO:  fix Make to support generated files not
+            # in a variable-named path like <(INTERMEDIATE_DIR)
+            #'<(RULE_INPUT_ROOT).c',
+            '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).h',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 0,
+        },
+        {
+          'rule_name': 'copy_file_1',
+          'extension': 'in1',
+          'inputs': [
+            '../copy-file.py',
+          ],
+          'outputs': [
+            # TODO:  fix Make to support generated files not
+            # in a variable-named path like <(INTERMEDIATE_DIR)
+            #'<(RULE_INPUT_ROOT).c',
+            '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).c',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/rules/subdir1/function1.in1 b/gyp/test/generator-output/rules/subdir1/function1.in1
new file mode 100644 (file)
index 0000000..545e7ca
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void function1(void)
+{
+  printf("Hello from function1.in1\n");
+}
diff --git a/gyp/test/generator-output/rules/subdir1/function2.in1 b/gyp/test/generator-output/rules/subdir1/function2.in1
new file mode 100644 (file)
index 0000000..6bad43f
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void function2(void)
+{
+  printf("Hello from function2.in1\n");
+}
diff --git a/gyp/test/generator-output/rules/subdir1/program.c b/gyp/test/generator-output/rules/subdir1/program.c
new file mode 100644 (file)
index 0000000..56b3206
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include "define3.h"
+#include "define4.h"
+
+extern void function1(void);
+extern void function2(void);
+extern void function3(void);
+extern void function4(void);
+
+int main(void)
+{
+  printf("Hello from program.c\n");
+  function1();
+  function2();
+  printf("%s", STRING3);
+  printf("%s", STRING4);
+  return 0;
+}
diff --git a/gyp/test/generator-output/rules/subdir2/build/README.txt b/gyp/test/generator-output/rules/subdir2/build/README.txt
new file mode 100644 (file)
index 0000000..1b052c9
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the\r
+test script can verify that .xcodeproj files are not created in\r
+their normal location by making the src/ read-only, and then\r
+selectively making this build directory writable.\r
diff --git a/gyp/test/generator-output/rules/subdir2/file1.in0 b/gyp/test/generator-output/rules/subdir2/file1.in0
new file mode 100644 (file)
index 0000000..7aca64f
--- /dev/null
@@ -0,0 +1 @@
+Hello from file1.in0
diff --git a/gyp/test/generator-output/rules/subdir2/file2.in0 b/gyp/test/generator-output/rules/subdir2/file2.in0
new file mode 100644 (file)
index 0000000..80a281a
--- /dev/null
@@ -0,0 +1 @@
+Hello from file2.in0
diff --git a/gyp/test/generator-output/rules/subdir2/file3.in1 b/gyp/test/generator-output/rules/subdir2/file3.in1
new file mode 100644 (file)
index 0000000..60ae2e7
--- /dev/null
@@ -0,0 +1 @@
+Hello from file3.in1
diff --git a/gyp/test/generator-output/rules/subdir2/file4.in1 b/gyp/test/generator-output/rules/subdir2/file4.in1
new file mode 100644 (file)
index 0000000..5a3c307
--- /dev/null
@@ -0,0 +1 @@
+Hello from file4.in1
diff --git a/gyp/test/generator-output/rules/subdir2/none.gyp b/gyp/test/generator-output/rules/subdir2/none.gyp
new file mode 100644 (file)
index 0000000..664cbd9
--- /dev/null
@@ -0,0 +1,49 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'files',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'file1.in0',
+        'file2.in0',
+        'file3.in1',
+        'file4.in1',
+      ],
+      'rules': [
+        {
+          'rule_name': 'copy_file_0',
+          'extension': 'in0',
+          'inputs': [
+            '../copy-file.py',
+          ],
+          'outputs': [
+            'rules-out/<(RULE_INPUT_ROOT).out',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 0,
+        },
+        {
+          'rule_name': 'copy_file_1',
+          'extension': 'in1',
+          'inputs': [
+            '../copy-file.py',
+          ],
+          'outputs': [
+            'rules-out/<(RULE_INPUT_ROOT).out',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/rules/subdir2/rules-out/README.txt b/gyp/test/generator-output/rules/subdir2/rules-out/README.txt
new file mode 100644 (file)
index 0000000..1b052c9
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the\r
+test script can verify that .xcodeproj files are not created in\r
+their normal location by making the src/ read-only, and then\r
+selectively making this build directory writable.\r
diff --git a/gyp/test/generator-output/src/build/README.txt b/gyp/test/generator-output/src/build/README.txt
new file mode 100644 (file)
index 0000000..90ef886
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/gyp/test/generator-output/src/inc.h b/gyp/test/generator-output/src/inc.h
new file mode 100644 (file)
index 0000000..57aa1a5
--- /dev/null
@@ -0,0 +1 @@
+#define INC_STRING      "inc.h"
diff --git a/gyp/test/generator-output/src/inc1/include1.h b/gyp/test/generator-output/src/inc1/include1.h
new file mode 100644 (file)
index 0000000..1d59065
--- /dev/null
@@ -0,0 +1 @@
+#define INCLUDE1_STRING "inc1/include1.h"
diff --git a/gyp/test/generator-output/src/prog1.c b/gyp/test/generator-output/src/prog1.c
new file mode 100644 (file)
index 0000000..bf7c2a1
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+#include "inc.h"
+#include "include1.h"
+#include "include2.h"
+#include "include3.h"
+#include "deeper.h"
+
+int main(void)
+{
+  printf("Hello from prog1.c\n");
+  printf("Hello from %s\n", INC_STRING);
+  printf("Hello from %s\n", INCLUDE1_STRING);
+  printf("Hello from %s\n", INCLUDE2_STRING);
+  printf("Hello from %s\n", INCLUDE3_STRING);
+  printf("Hello from %s\n", DEEPER_STRING);
+  return 0;
+}
diff --git a/gyp/test/generator-output/src/prog1.gyp b/gyp/test/generator-output/src/prog1.gyp
new file mode 100644 (file)
index 0000000..d50e6fb
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    'symroot.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'prog1',
+      'type': 'executable',
+      'dependencies': [
+        'subdir2/prog2.gyp:prog2',
+      ],
+      'include_dirs': [
+        '.',
+        'inc1',
+        'subdir2/inc2',
+        'subdir3/inc3',
+        'subdir2/deeper',
+      ],
+      'sources': [
+        'prog1.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/src/subdir2/build/README.txt b/gyp/test/generator-output/src/subdir2/build/README.txt
new file mode 100644 (file)
index 0000000..90ef886
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/gyp/test/generator-output/src/subdir2/deeper/build/README.txt b/gyp/test/generator-output/src/subdir2/deeper/build/README.txt
new file mode 100644 (file)
index 0000000..90ef886
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/gyp/test/generator-output/src/subdir2/deeper/deeper.c b/gyp/test/generator-output/src/subdir2/deeper/deeper.c
new file mode 100644 (file)
index 0000000..843505c
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from deeper.c\n");
+  return 0;
+}
diff --git a/gyp/test/generator-output/src/subdir2/deeper/deeper.gyp b/gyp/test/generator-output/src/subdir2/deeper/deeper.gyp
new file mode 100644 (file)
index 0000000..8648770
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../../symroot.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'deeper',
+      'type': 'executable',
+      'sources': [
+        'deeper.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/src/subdir2/deeper/deeper.h b/gyp/test/generator-output/src/subdir2/deeper/deeper.h
new file mode 100644 (file)
index 0000000..f6484a0
--- /dev/null
@@ -0,0 +1 @@
+#define DEEPER_STRING   "subdir2/deeper/deeper.h"
diff --git a/gyp/test/generator-output/src/subdir2/inc2/include2.h b/gyp/test/generator-output/src/subdir2/inc2/include2.h
new file mode 100644 (file)
index 0000000..1ccfa5d
--- /dev/null
@@ -0,0 +1 @@
+#define INCLUDE2_STRING "inc2/include2.h"
diff --git a/gyp/test/generator-output/src/subdir2/prog2.c b/gyp/test/generator-output/src/subdir2/prog2.c
new file mode 100644 (file)
index 0000000..d80d871
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+#include "inc.h"
+#include "include1.h"
+#include "include2.h"
+#include "include3.h"
+#include "deeper.h"
+
+int main(void)
+{
+  printf("Hello from prog2.c\n");
+  printf("Hello from %s\n", INC_STRING);
+  printf("Hello from %s\n", INCLUDE1_STRING);
+  printf("Hello from %s\n", INCLUDE2_STRING);
+  printf("Hello from %s\n", INCLUDE3_STRING);
+  printf("Hello from %s\n", DEEPER_STRING);
+  return 0;
+}
diff --git a/gyp/test/generator-output/src/subdir2/prog2.gyp b/gyp/test/generator-output/src/subdir2/prog2.gyp
new file mode 100644 (file)
index 0000000..7176ed8
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../symroot.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'prog2',
+      'type': 'executable',
+      'include_dirs': [
+        '..',
+        '../inc1',
+        'inc2',
+        '../subdir3/inc3',
+        'deeper',
+      ],
+      'dependencies': [
+        '../subdir3/prog3.gyp:prog3',
+      ],
+      'sources': [
+        'prog2.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/src/subdir3/build/README.txt b/gyp/test/generator-output/src/subdir3/build/README.txt
new file mode 100644 (file)
index 0000000..90ef886
--- /dev/null
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/gyp/test/generator-output/src/subdir3/inc3/include3.h b/gyp/test/generator-output/src/subdir3/inc3/include3.h
new file mode 100644 (file)
index 0000000..bf53bf1
--- /dev/null
@@ -0,0 +1 @@
+#define INCLUDE3_STRING "inc3/include3.h"
diff --git a/gyp/test/generator-output/src/subdir3/prog3.c b/gyp/test/generator-output/src/subdir3/prog3.c
new file mode 100644 (file)
index 0000000..c72233d
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+#include "inc.h"
+#include "include1.h"
+#include "include2.h"
+#include "include3.h"
+#include "deeper.h"
+
+int main(void)
+{
+  printf("Hello from prog3.c\n");
+  printf("Hello from %s\n", INC_STRING);
+  printf("Hello from %s\n", INCLUDE1_STRING);
+  printf("Hello from %s\n", INCLUDE2_STRING);
+  printf("Hello from %s\n", INCLUDE3_STRING);
+  printf("Hello from %s\n", DEEPER_STRING);
+  return 0;
+}
diff --git a/gyp/test/generator-output/src/subdir3/prog3.gyp b/gyp/test/generator-output/src/subdir3/prog3.gyp
new file mode 100644 (file)
index 0000000..46c5e00
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../symroot.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'prog3',
+      'type': 'executable',
+      'include_dirs': [
+        '..',
+        '../inc1',
+        '../subdir2/inc2',
+        'inc3',
+        '../subdir2/deeper',
+      ],
+      'sources': [
+        'prog3.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/generator-output/src/symroot.gypi b/gyp/test/generator-output/src/symroot.gypi
new file mode 100644 (file)
index 0000000..5199164
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'set_symroot%': 0,
+  },
+  'conditions': [
+    ['set_symroot == 1', {
+      'xcode_settings': {
+        'SYMROOT': '<(DEPTH)/build',
+      },
+    }],
+  ],
+}
diff --git a/gyp/test/gyp-defines/defines.gyp b/gyp/test/gyp-defines/defines.gyp
new file mode 100644 (file)
index 0000000..f59bbd2
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'test_target',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'test_action',
+          'inputs': [],
+          'outputs': [ 'action.txt' ],
+          'action': [
+            'python',
+            'echo.py',
+            '<(key)',
+            '<(_outputs)',
+          ],
+          'msvs_cygwin_shell': 0,
+        }
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/gyp-defines/echo.py b/gyp/test/gyp-defines/echo.py
new file mode 100644 (file)
index 0000000..b85add1
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+f = open(sys.argv[2], 'w+')
+f.write(sys.argv[1])
+f.close()
diff --git a/gyp/test/gyp-defines/gyptest-multiple-values.py b/gyp/test/gyp-defines/gyptest-multiple-values.py
new file mode 100644 (file)
index 0000000..7c38257
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that when multiple values are supplied for a gyp define, the last one
+is used.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+os.environ['GYP_DEFINES'] = 'key=value1 key=value2 key=value3'
+test.run_gyp('defines.gyp')
+test.build('defines.gyp')
+test.must_contain('action.txt', 'value3')
+
+# The last occurrence of a repeated set should take precedence over other
+# values.
+os.environ['GYP_DEFINES'] = 'key=repeated_value key=value1 key=repeated_value'
+test.run_gyp('defines.gyp')
+if test.format == 'msvs' and not test.uses_msbuild:
+  # msvs versions before 2010 don't detect build rule changes not reflected
+  # in file system timestamps. Rebuild to see differences.
+  test.build('defines.gyp', rebuild=True)
+elif test.format == 'android':
+  # The Android build system doesn't currently have a way to get files whose
+  # build rules have changed (but whose timestamps haven't) to be rebuilt.
+  # See bug http://code.google.com/p/gyp/issues/detail?id=308
+  test.unlink('action.txt')
+  test.build('defines.gyp')
+else:
+  test.build('defines.gyp')
+test.must_contain('action.txt', 'repeated_value')
+
+test.pass_test()
diff --git a/gyp/test/gyp-defines/gyptest-regyp.py b/gyp/test/gyp-defines/gyptest-regyp.py
new file mode 100644 (file)
index 0000000..0895d81
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that when the same value is repeated for a gyp define, duplicates are
+stripped from the regeneration rule.
+"""
+
+import os
+import TestGyp
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
+
+os.environ['GYP_DEFINES'] = 'key=repeated_value key=value1 key=repeated_value'
+test.run_gyp('defines.gyp')
+test.build('defines.gyp')
+
+# The last occurrence of a repeated set should take precedence over other
+# values. See gyptest-multiple-values.py.
+test.must_contain('action.txt', 'repeated_value')
+
+# So the regeneration rule needs to use the correct order.
+test.must_not_contain(
+    'Makefile', '"-Dkey=repeated_value" "-Dkey=value1" "-Dkey=repeated_value"')
+test.must_contain('Makefile', '"-Dkey=value1" "-Dkey=repeated_value"')
+
+# Sleep so that the changed gyp file will have a newer timestamp than the
+# previously generated build files.
+test.sleep()
+os.utime("defines.gyp", None)
+
+test.build('defines.gyp')
+test.must_contain('action.txt', 'repeated_value')
+
+test.pass_test()
diff --git a/gyp/test/hard_dependency/gyptest-exported-hard-dependency.py b/gyp/test/hard_dependency/gyptest-exported-hard-dependency.py
new file mode 100755 (executable)
index 0000000..ba51528
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that a hard_dependency that is exported is pulled in as a dependency
+for a target if the target is a static library and if the generator will
+remove dependencies between static libraries.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+if test.format == 'dump_dependency_json':
+  test.skip_test('Skipping test; dependency JSON does not adjust ' \
+                 'static libraries.\n')
+
+test.run_gyp('hard_dependency.gyp', chdir='src')
+
+chdir = 'relocate/src'
+test.relocate('src', chdir)
+
+test.build('hard_dependency.gyp', 'c', chdir=chdir)
+
+# The 'a' static library should be built, as it has actions with side-effects
+# that are necessary to compile 'c'. Even though 'c' does not directly depend
+# on 'a', because 'a' is a hard_dependency that 'b' exports, 'c' should import
+# it as a hard_dependency and ensure it is built before building 'c'.
+test.built_file_must_exist('a', type=test.STATIC_LIB, chdir=chdir)
+test.built_file_must_not_exist('b', type=test.STATIC_LIB, chdir=chdir)
+test.built_file_must_exist('c', type=test.STATIC_LIB, chdir=chdir)
+test.built_file_must_not_exist('d', type=test.STATIC_LIB, chdir=chdir)
+
+test.pass_test()
diff --git a/gyp/test/hard_dependency/gyptest-no-exported-hard-dependency.py b/gyp/test/hard_dependency/gyptest-no-exported-hard-dependency.py
new file mode 100755 (executable)
index 0000000..10774ca
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that a hard_dependency that is not exported is not pulled in as a
+dependency for a target if the target does not explicitly specify a dependency
+and none of its dependencies export the hard_dependency.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+if test.format == 'dump_dependency_json':
+  test.skip_test('Skipping test; dependency JSON does not adjust ' \
+                 'static libaries.\n')
+
+test.run_gyp('hard_dependency.gyp', chdir='src')
+
+chdir = 'relocate/src'
+test.relocate('src', chdir)
+
+test.build('hard_dependency.gyp', 'd', chdir=chdir)
+
+# Because 'c' does not export a hard_dependency, only the target 'd' should
+# be built. This is because the 'd' target does not need the generated headers
+# in order to be compiled.
+test.built_file_must_not_exist('a', type=test.STATIC_LIB, chdir=chdir)
+test.built_file_must_not_exist('b', type=test.STATIC_LIB, chdir=chdir)
+test.built_file_must_not_exist('c', type=test.STATIC_LIB, chdir=chdir)
+test.built_file_must_exist('d', type=test.STATIC_LIB, chdir=chdir)
+
+test.pass_test()
diff --git a/gyp/test/hard_dependency/src/a.c b/gyp/test/hard_dependency/src/a.c
new file mode 100644 (file)
index 0000000..0fa0223
--- /dev/null
@@ -0,0 +1,9 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include "a.h"
+
+int funcA() {
+  return 42;
+}
diff --git a/gyp/test/hard_dependency/src/a.h b/gyp/test/hard_dependency/src/a.h
new file mode 100644 (file)
index 0000000..854a065
--- /dev/null
@@ -0,0 +1,12 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#ifndef A_H_
+#define A_H_
+
+#include "generated.h"
+
+int funcA();
+
+#endif  // A_H_
diff --git a/gyp/test/hard_dependency/src/b.c b/gyp/test/hard_dependency/src/b.c
new file mode 100644 (file)
index 0000000..0baace9
--- /dev/null
@@ -0,0 +1,9 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include "a.h"
+
+int funcB() {
+  return funcA();
+}
diff --git a/gyp/test/hard_dependency/src/b.h b/gyp/test/hard_dependency/src/b.h
new file mode 100644 (file)
index 0000000..22b48ce
--- /dev/null
@@ -0,0 +1,12 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#ifndef B_H_
+#define B_H_
+
+#include "a.h"
+
+int funcB();
+
+#endif  // B_H_
diff --git a/gyp/test/hard_dependency/src/c.c b/gyp/test/hard_dependency/src/c.c
new file mode 100644 (file)
index 0000000..7d00682
--- /dev/null
@@ -0,0 +1,10 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include "b.h"
+#include "c.h"
+
+int funcC() {
+  return funcB();
+}
diff --git a/gyp/test/hard_dependency/src/c.h b/gyp/test/hard_dependency/src/c.h
new file mode 100644 (file)
index 0000000..f4ea7fe
--- /dev/null
@@ -0,0 +1,10 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#ifndef C_H_
+#define C_H_
+
+int funcC();
+
+#endif  // C_H_
diff --git a/gyp/test/hard_dependency/src/d.c b/gyp/test/hard_dependency/src/d.c
new file mode 100644 (file)
index 0000000..d016c3c
--- /dev/null
@@ -0,0 +1,9 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include "c.h"
+
+int funcD() {
+  return funcC();
+}
diff --git a/gyp/test/hard_dependency/src/emit.py b/gyp/test/hard_dependency/src/emit.py
new file mode 100755 (executable)
index 0000000..2df74b7
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+f = open(sys.argv[1], 'wb')
+f.write('/* Hello World */\n')
+f.close()
diff --git a/gyp/test/hard_dependency/src/hard_dependency.gyp b/gyp/test/hard_dependency/src/hard_dependency.gyp
new file mode 100644 (file)
index 0000000..4479c5f
--- /dev/null
@@ -0,0 +1,78 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'a',
+      'type': 'static_library',
+      'sources': [
+        'a.c',
+        'a.h',
+      ],
+      'hard_dependency': 1,
+      'actions': [
+        {
+          'action_name': 'generate_headers',
+          'inputs': [
+            'emit.py'
+          ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/generated.h'
+          ],
+          'action': [
+            'python',
+            'emit.py',
+            '<(SHARED_INTERMEDIATE_DIR)/generated.h',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+      'include_dirs': [
+        '<(SHARED_INTERMEDIATE_DIR)',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '<(SHARED_INTERMEDIATE_DIR)',
+        ],
+      },
+    },
+    {
+      'target_name': 'b',
+      'type': 'static_library',
+      'sources': [
+        'b.c',
+        'b.h',
+      ],
+      'dependencies': [
+        'a',
+      ],
+      'export_dependent_settings': [
+        'a',
+      ],
+    },
+    {
+      'target_name': 'c',
+      'type': 'static_library',
+      'sources': [
+        'c.c',
+        'c.h',
+      ],
+      'dependencies': [
+        'b',
+      ],
+    },
+    {
+      'target_name': 'd',
+      'type': 'static_library',
+      'sources': [
+        'd.c',
+      ],
+      'dependencies': [
+        'c',
+      ],
+    }
+  ],
+}
diff --git a/gyp/test/hello/gyptest-all.py b/gyp/test/hello/gyptest-all.py
new file mode 100755 (executable)
index 0000000..1739b68
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_all')
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp', test.ALL)
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.up_to_date('hello.gyp', test.ALL)
+
+test.pass_test()
diff --git a/gyp/test/hello/gyptest-default.py b/gyp/test/hello/gyptest-default.py
new file mode 100755 (executable)
index 0000000..22377e7
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using the default build target.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_default')
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp')
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.up_to_date('hello.gyp', test.DEFAULT)
+
+test.pass_test()
diff --git a/gyp/test/hello/gyptest-disable-regyp.py b/gyp/test/hello/gyptest-disable-regyp.py
new file mode 100755 (executable)
index 0000000..1e4b306
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that Makefiles don't get rebuilt when a source gyp file changes and
+the disable_regeneration generator flag is set.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('hello.gyp', '-Gauto_regeneration=0')
+
+test.build('hello.gyp', test.ALL)
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+# Sleep so that the changed gyp file will have a newer timestamp than the
+# previously generated build files.
+test.sleep()
+test.write('hello.gyp', test.read('hello2.gyp'))
+
+test.build('hello.gyp', test.ALL)
+
+# Should still be the old executable, as regeneration was disabled.
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.pass_test()
diff --git a/gyp/test/hello/gyptest-regyp-output.py b/gyp/test/hello/gyptest-regyp-output.py
new file mode 100644 (file)
index 0000000..5e698b1
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that Makefiles get rebuilt when a source gyp file changes and
+--generator-output is used.
+"""
+
+import TestGyp
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make and Android generators, and --generator-output is not supported
+# by Android and ninja, so we can only test for make.
+test = TestGyp.TestGyp(formats=['make'])
+
+CHDIR='generator-output'
+
+test.run_gyp('hello.gyp', '--generator-output=%s' % CHDIR)
+
+test.build('hello.gyp', test.ALL, chdir=CHDIR)
+
+test.run_built_executable('hello', stdout="Hello, world!\n", chdir=CHDIR)
+
+# Sleep so that the changed gyp file will have a newer timestamp than the
+# previously generated build files.
+test.sleep()
+test.write('hello.gyp', test.read('hello2.gyp'))
+
+test.build('hello.gyp', test.ALL, chdir=CHDIR)
+
+test.run_built_executable('hello', stdout="Hello, two!\n", chdir=CHDIR)
+
+test.pass_test()
diff --git a/gyp/test/hello/gyptest-regyp.py b/gyp/test/hello/gyptest-regyp.py
new file mode 100755 (executable)
index 0000000..b513edc
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that Makefiles get rebuilt when a source gyp file changes.
+"""
+
+import TestGyp
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp', test.ALL)
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+# Sleep so that the changed gyp file will have a newer timestamp than the
+# previously generated build files.
+test.sleep()
+test.write('hello.gyp', test.read('hello2.gyp'))
+
+test.build('hello.gyp', test.ALL)
+
+test.run_built_executable('hello', stdout="Hello, two!\n")
+
+test.pass_test()
diff --git a/gyp/test/hello/gyptest-target.py b/gyp/test/hello/gyptest-target.py
new file mode 100755 (executable)
index 0000000..1abaf70
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using an explicit build target of 'hello'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_target')
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp', 'hello')
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.up_to_date('hello.gyp', 'hello')
+
+test.pass_test()
diff --git a/gyp/test/hello/hello.c b/gyp/test/hello/hello.c
new file mode 100644 (file)
index 0000000..0a4c806
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello, world!\n");
+  return 0;
+}
diff --git a/gyp/test/hello/hello.gyp b/gyp/test/hello/hello.gyp
new file mode 100644 (file)
index 0000000..1974d51
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/hello/hello2.c b/gyp/test/hello/hello2.c
new file mode 100644 (file)
index 0000000..b14299c
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello, two!\n");
+  return 0;
+}
diff --git a/gyp/test/hello/hello2.gyp b/gyp/test/hello/hello2.gyp
new file mode 100644 (file)
index 0000000..25b08ca
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello2.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/home_dot_gyp/gyptest-home-includes-config-arg.py b/gyp/test/home_dot_gyp/gyptest-home-includes-config-arg.py
new file mode 100755 (executable)
index 0000000..82e39f9
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies inclusion of $HOME/.gyp/include.gypi works when --config-dir is
+specified.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+os.environ['HOME'] = os.path.abspath('home2')
+
+test.run_gyp('all.gyp', '--config-dir=~/.gyp_new', chdir='src')
+
+# After relocating, we should still be able to build (build file shouldn't
+# contain relative reference to ~/.gyp/include.gypi)
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('printfoo',
+                          chdir='relocate/src',
+                          stdout='FOO is fromhome3\n')
+
+test.pass_test()
diff --git a/gyp/test/home_dot_gyp/gyptest-home-includes-config-env.py b/gyp/test/home_dot_gyp/gyptest-home-includes-config-env.py
new file mode 100755 (executable)
index 0000000..6f4b299
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies inclusion of $HOME/.gyp_new/include.gypi works when GYP_CONFIG_DIR
+is set.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+os.environ['HOME'] = os.path.abspath('home')
+os.environ['GYP_CONFIG_DIR'] = os.path.join(os.path.abspath('home2'),
+                                            '.gyp_new')
+
+test.run_gyp('all.gyp', chdir='src')
+
+# After relocating, we should still be able to build (build file shouldn't
+# contain relative reference to ~/.gyp_new/include.gypi)
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('printfoo',
+                          chdir='relocate/src',
+                          stdout='FOO is fromhome3\n')
+
+test.pass_test()
diff --git a/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py b/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py
new file mode 100755 (executable)
index 0000000..fdf8b14
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies inclusion of $HOME/.gyp/include.gypi works properly with relocation
+and with regeneration.
+"""
+
+import os
+import TestGyp
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
+
+os.environ['HOME'] = os.path.abspath('home')
+
+test.run_gyp('all.gyp', chdir='src')
+
+# After relocating, we should still be able to build (build file shouldn't
+# contain relative reference to ~/.gyp/include.gypi)
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('printfoo',
+                          chdir='relocate/src',
+                          stdout='FOO is fromhome\n')
+
+# Building should notice any changes to ~/.gyp/include.gypi and regyp.
+test.sleep()
+
+test.write('home/.gyp/include.gypi', test.read('home2/.gyp/include.gypi'))
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('printfoo',
+                          chdir='relocate/src',
+                          stdout='FOO is fromhome2\n')
+
+test.pass_test()
diff --git a/gyp/test/home_dot_gyp/gyptest-home-includes.py b/gyp/test/home_dot_gyp/gyptest-home-includes.py
new file mode 100755 (executable)
index 0000000..8ad5255
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies inclusion of $HOME/.gyp/include.gypi works.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+os.environ['HOME'] = os.path.abspath('home')
+
+test.run_gyp('all.gyp', chdir='src')
+
+# After relocating, we should still be able to build (build file shouldn't
+# contain relative reference to ~/.gyp/include.gypi)
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('printfoo',
+                          chdir='relocate/src',
+                          stdout='FOO is fromhome\n')
+
+test.pass_test()
diff --git a/gyp/test/home_dot_gyp/home/.gyp/include.gypi b/gyp/test/home_dot_gyp/home/.gyp/include.gypi
new file mode 100644 (file)
index 0000000..fcfb39b
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  'variables': {
+    'foo': '"fromhome"',
+  },
+}
diff --git a/gyp/test/home_dot_gyp/home2/.gyp/include.gypi b/gyp/test/home_dot_gyp/home2/.gyp/include.gypi
new file mode 100644 (file)
index 0000000..f0d84b3
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  'variables': {
+    'foo': '"fromhome2"',
+  },
+}
diff --git a/gyp/test/home_dot_gyp/home2/.gyp_new/include.gypi b/gyp/test/home_dot_gyp/home2/.gyp_new/include.gypi
new file mode 100644 (file)
index 0000000..4094dfd
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  'variables': {
+    'foo': '"fromhome3"',
+  },
+}
diff --git a/gyp/test/home_dot_gyp/src/all.gyp b/gyp/test/home_dot_gyp/src/all.gyp
new file mode 100644 (file)
index 0000000..14b6aea
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'foo%': '"fromdefault"',
+  },
+  'targets': [
+    {
+      'target_name': 'printfoo',
+      'type': 'executable',
+      'sources': [
+        'printfoo.c',
+      ],
+      'defines': [
+        'FOO=<(foo)',
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/home_dot_gyp/src/printfoo.c b/gyp/test/home_dot_gyp/src/printfoo.c
new file mode 100644 (file)
index 0000000..9bb6718
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("FOO is %s\n", FOO);
+  return 0;
+}
diff --git a/gyp/test/include_dirs/gyptest-all.py b/gyp/test/include_dirs/gyptest-all.py
new file mode 100755 (executable)
index 0000000..d64bc6a
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies use of include_dirs when using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('includes.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('includes.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from includes.c
+Hello from inc.h
+Hello from include1.h
+Hello from subdir/inc2/include2.h
+Hello from shadow2/shadow.h
+"""
+test.run_built_executable('includes', stdout=expect, chdir='relocate/src')
+
+if test.format == 'xcode':
+  chdir='relocate/src/subdir'
+else:
+  chdir='relocate/src'
+
+expect = """\
+Hello from subdir/subdir_includes.c
+Hello from subdir/inc.h
+Hello from include1.h
+Hello from subdir/inc2/include2.h
+"""
+test.run_built_executable('subdir_includes', stdout=expect, chdir=chdir)
+
+test.pass_test()
diff --git a/gyp/test/include_dirs/gyptest-default.py b/gyp/test/include_dirs/gyptest-default.py
new file mode 100755 (executable)
index 0000000..fc61415
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies use of include_dirs when using the default build target.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('includes.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('includes.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from includes.c
+Hello from inc.h
+Hello from include1.h
+Hello from subdir/inc2/include2.h
+Hello from shadow2/shadow.h
+"""
+test.run_built_executable('includes', stdout=expect, chdir='relocate/src')
+
+if test.format == 'xcode':
+  chdir='relocate/src/subdir'
+else:
+  chdir='relocate/src'
+
+expect = """\
+Hello from subdir/subdir_includes.c
+Hello from subdir/inc.h
+Hello from include1.h
+Hello from subdir/inc2/include2.h
+"""
+test.run_built_executable('subdir_includes', stdout=expect, chdir=chdir)
+
+test.pass_test()
diff --git a/gyp/test/include_dirs/src/inc.h b/gyp/test/include_dirs/src/inc.h
new file mode 100644 (file)
index 0000000..0398d69
--- /dev/null
@@ -0,0 +1 @@
+#define INC_STRING "inc.h"
diff --git a/gyp/test/include_dirs/src/inc1/include1.h b/gyp/test/include_dirs/src/inc1/include1.h
new file mode 100644 (file)
index 0000000..43356b5
--- /dev/null
@@ -0,0 +1 @@
+#define INCLUDE1_STRING "include1.h"
diff --git a/gyp/test/include_dirs/src/includes.c b/gyp/test/include_dirs/src/includes.c
new file mode 100644 (file)
index 0000000..6e2a23c
--- /dev/null
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+#include "inc.h"
+#include "include1.h"
+#include "include2.h"
+#include "shadow.h"
+
+int main(void)
+{
+  printf("Hello from includes.c\n");
+  printf("Hello from %s\n", INC_STRING);
+  printf("Hello from %s\n", INCLUDE1_STRING);
+  printf("Hello from %s\n", INCLUDE2_STRING);
+  /* Test that include_dirs happen first: The gyp file has a -Ishadow1
+     cflag and an include_dir of shadow2.  Including shadow.h should get
+     the shadow.h from the include_dir. */
+  printf("Hello from %s\n", SHADOW_STRING);
+  return 0;
+}
diff --git a/gyp/test/include_dirs/src/includes.gyp b/gyp/test/include_dirs/src/includes.gyp
new file mode 100644 (file)
index 0000000..3592690
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'includes',
+      'type': 'executable',
+      'dependencies': [
+        'subdir/subdir_includes.gyp:subdir_includes',
+      ],
+      'cflags': [
+        '-Ishadow1',
+      ],
+      'include_dirs': [
+        '.',
+        'inc1',
+        'shadow2',
+        'subdir/inc2',
+      ],
+      'sources': [
+        'includes.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/include_dirs/src/shadow1/shadow.h b/gyp/test/include_dirs/src/shadow1/shadow.h
new file mode 100644 (file)
index 0000000..80f6de2
--- /dev/null
@@ -0,0 +1 @@
+#define SHADOW_STRING "shadow1/shadow.h"
diff --git a/gyp/test/include_dirs/src/shadow2/shadow.h b/gyp/test/include_dirs/src/shadow2/shadow.h
new file mode 100644 (file)
index 0000000..fad5ccd
--- /dev/null
@@ -0,0 +1 @@
+#define SHADOW_STRING "shadow2/shadow.h"
diff --git a/gyp/test/include_dirs/src/subdir/inc.h b/gyp/test/include_dirs/src/subdir/inc.h
new file mode 100644 (file)
index 0000000..0a68d7b
--- /dev/null
@@ -0,0 +1 @@
+#define INC_STRING "subdir/inc.h"
diff --git a/gyp/test/include_dirs/src/subdir/inc2/include2.h b/gyp/test/include_dirs/src/subdir/inc2/include2.h
new file mode 100644 (file)
index 0000000..721577e
--- /dev/null
@@ -0,0 +1 @@
+#define INCLUDE2_STRING "subdir/inc2/include2.h"
diff --git a/gyp/test/include_dirs/src/subdir/subdir_includes.c b/gyp/test/include_dirs/src/subdir/subdir_includes.c
new file mode 100644 (file)
index 0000000..4623543
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+#include "inc.h"
+#include "include1.h"
+#include "include2.h"
+
+int main(void)
+{
+  printf("Hello from subdir/subdir_includes.c\n");
+  printf("Hello from %s\n", INC_STRING);
+  printf("Hello from %s\n", INCLUDE1_STRING);
+  printf("Hello from %s\n", INCLUDE2_STRING);
+  return 0;
+}
diff --git a/gyp/test/include_dirs/src/subdir/subdir_includes.gyp b/gyp/test/include_dirs/src/subdir/subdir_includes.gyp
new file mode 100644 (file)
index 0000000..257d052
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'subdir_includes',
+      'type': 'executable',
+      'include_dirs': [
+        '.',
+        '../inc1',
+        'inc2',
+      ],
+      'sources': [
+        'subdir_includes.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/intermediate_dir/gyptest-intermediate-dir.py b/gyp/test/intermediate_dir/gyptest-intermediate-dir.py
new file mode 100755 (executable)
index 0000000..0e1020e
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that targets have independent INTERMEDIATE_DIRs.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('test.gyp', chdir='src')
+test.build('test.gyp', 'target1', chdir='src')
+# Check stuff exists.
+intermediate_file1 = test.read('src/outfile.txt')
+test.must_contain(intermediate_file1, 'target1')
+
+shared_intermediate_file1 = test.read('src/shared_outfile.txt')
+test.must_contain(shared_intermediate_file1, 'shared_target1')
+
+test.run_gyp('test2.gyp', chdir='src')
+# Force the shared intermediate to be rebuilt.
+test.sleep()
+test.touch('src/shared_infile.txt')
+test.build('test2.gyp', 'target2', chdir='src')
+# Check INTERMEDIATE_DIR file didn't get overwritten but SHARED_INTERMEDIATE_DIR
+# file did.
+intermediate_file2 = test.read('src/outfile.txt')
+test.must_contain(intermediate_file1, 'target1')
+test.must_contain(intermediate_file2, 'target2')
+
+shared_intermediate_file2 = test.read('src/shared_outfile.txt')
+if shared_intermediate_file1 != shared_intermediate_file2:
+  test.fail_test(shared_intermediate_file1 + ' != ' + shared_intermediate_file2)
+
+test.must_contain(shared_intermediate_file1, 'shared_target2')
+test.must_contain(shared_intermediate_file2, 'shared_target2')
+
+test.pass_test()
diff --git a/gyp/test/intermediate_dir/src/script.py b/gyp/test/intermediate_dir/src/script.py
new file mode 100755 (executable)
index 0000000..7abc7ee
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Takes 3 arguments. Writes the 1st argument to the file in the 2nd argument,
+# and writes the absolute path to the file in the 2nd argument to the file in
+# the 3rd argument.
+
+import os
+import shlex
+import sys
+
+if len(sys.argv) == 3 and ' ' in sys.argv[2]:
+  sys.argv[2], fourth = shlex.split(sys.argv[2].replace('\\', '\\\\'))
+  sys.argv.append(fourth)
+
+#print >>sys.stderr, sys.argv
+
+with open(sys.argv[2], 'w') as f:
+  f.write(sys.argv[1])
+
+with open(sys.argv[3], 'w') as f:
+  f.write(os.path.abspath(sys.argv[2]))
diff --git a/gyp/test/intermediate_dir/src/shared_infile.txt b/gyp/test/intermediate_dir/src/shared_infile.txt
new file mode 100644 (file)
index 0000000..e2aba15
--- /dev/null
@@ -0,0 +1 @@
+dummy input
diff --git a/gyp/test/intermediate_dir/src/test.gyp b/gyp/test/intermediate_dir/src/test.gyp
new file mode 100644 (file)
index 0000000..b61e7e8
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'target1',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'intermediate',
+          'inputs': [],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/intermediate_out.txt',
+            'outfile.txt',
+          ],
+          'action': [
+            'python', 'script.py', 'target1', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+        {
+          'action_name': 'shared_intermediate',
+          'inputs': [
+            'shared_infile.txt',
+          ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/intermediate_out.txt',
+            'shared_outfile.txt',
+          ],
+          'action': [
+            'python', 'script.py', 'shared_target1', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/intermediate_dir/src/test2.gyp b/gyp/test/intermediate_dir/src/test2.gyp
new file mode 100644 (file)
index 0000000..41f5564
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'target2',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'intermediate',
+          'inputs': [],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/intermediate_out.txt',
+            'outfile.txt',
+          ],
+          'action': [
+            'python', 'script.py', 'target2', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+        {
+          'action_name': 'shared_intermediate',
+          'inputs': [
+            'shared_infile.txt',
+          ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/intermediate_out.txt',
+            'shared_outfile.txt',
+          ],
+          'action': [
+            'python', 'script.py', 'shared_target2', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/ios/app-bundle/TestApp/English.lproj/InfoPlist-error.strings b/gyp/test/ios/app-bundle/TestApp/English.lproj/InfoPlist-error.strings
new file mode 100644 (file)
index 0000000..452e7fa
--- /dev/null
@@ -0,0 +1,3 @@
+/* Localized versions of Info.plist keys */
+
+NSHumanReadableCopyright = "Copyright Â©2011 Google Inc."
diff --git a/gyp/test/ios/app-bundle/TestApp/English.lproj/InfoPlist.strings b/gyp/test/ios/app-bundle/TestApp/English.lproj/InfoPlist.strings
new file mode 100644 (file)
index 0000000..35bd33a
--- /dev/null
@@ -0,0 +1,3 @@
+/* Localized versions of Info.plist keys */
+
+NSHumanReadableCopyright = "Copyright Â©2011 Google Inc.";
diff --git a/gyp/test/ios/app-bundle/TestApp/English.lproj/MainMenu.xib b/gyp/test/ios/app-bundle/TestApp/English.lproj/MainMenu.xib
new file mode 100644 (file)
index 0000000..4524596
--- /dev/null
@@ -0,0 +1,4119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
+       <data>
+               <int key="IBDocument.SystemTarget">1060</int>
+               <string key="IBDocument.SystemVersion">10A324</string>
+               <string key="IBDocument.InterfaceBuilderVersion">719</string>
+               <string key="IBDocument.AppKitVersion">1015</string>
+               <string key="IBDocument.HIToolboxVersion">418.00</string>
+               <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+                       <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+                       <string key="NS.object.0">719</string>
+               </object>
+               <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+                       <bool key="EncodedWithXMLCoder">YES</bool>
+                       <integer value="371"/>
+                       <integer value="29"/>
+               </object>
+               <object class="NSArray" key="IBDocument.PluginDependencies">
+                       <bool key="EncodedWithXMLCoder">YES</bool>
+                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+               </object>
+               <object class="NSMutableDictionary" key="IBDocument.Metadata">
+                       <bool key="EncodedWithXMLCoder">YES</bool>
+                       <object class="NSArray" key="dict.sortedKeys" id="0">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                       </object>
+                       <object class="NSMutableArray" key="dict.values">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                       </object>
+               </object>
+               <object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
+                       <bool key="EncodedWithXMLCoder">YES</bool>
+                       <object class="NSCustomObject" id="1021">
+                               <string key="NSClassName">NSApplication</string>
+                       </object>
+                       <object class="NSCustomObject" id="1014">
+                               <string key="NSClassName">FirstResponder</string>
+                       </object>
+                       <object class="NSCustomObject" id="1050">
+                               <string key="NSClassName">NSApplication</string>
+                       </object>
+                       <object class="NSMenu" id="649796088">
+                               <string key="NSTitle">AMainMenu</string>
+                               <object class="NSMutableArray" key="NSMenuItems">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                       <object class="NSMenuItem" id="694149608">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">TestApp</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSKeyEquivModMask">1048576</int>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <object class="NSCustomResource" key="NSOnImage" id="35465992">
+                                                       <string key="NSClassName">NSImage</string>
+                                                       <string key="NSResourceName">NSMenuCheckmark</string>
+                                               </object>
+                                               <object class="NSCustomResource" key="NSMixedImage" id="502551668">
+                                                       <string key="NSClassName">NSImage</string>
+                                                       <string key="NSResourceName">NSMenuMixedState</string>
+                                               </object>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="110575045">
+                                                       <string key="NSTitle">TestApp</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="238522557">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">About TestApp</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="304266470">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="609285721">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Preferences…</string>
+                                                                       <string key="NSKeyEquiv">,</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="481834944">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1046388886">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Services</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="752062318">
+                                                                               <string key="NSTitle">Services</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                               </object>
+                                                                               <string key="NSName">_NSServicesMenu</string>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="646227648">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="755159360">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Hide TestApp</string>
+                                                                       <string key="NSKeyEquiv">h</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="342932134">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Hide Others</string>
+                                                                       <string key="NSKeyEquiv">h</string>
+                                                                       <int key="NSKeyEquivModMask">1572864</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="908899353">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Show All</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1056857174">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="632727374">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Quit TestApp</string>
+                                                                       <string key="NSKeyEquiv">q</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                       </object>
+                                                       <string key="NSName">_NSAppleMenu</string>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="379814623">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">File</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSKeyEquivModMask">1048576</int>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="720053764">
+                                                       <string key="NSTitle">File</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="705341025">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">New</string>
+                                                                       <string key="NSKeyEquiv">n</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="722745758">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Open…</string>
+                                                                       <string key="NSKeyEquiv">o</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1025936716">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Open Recent</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="1065607017">
+                                                                               <string key="NSTitle">Open Recent</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="759406840">
+                                                                                               <reference key="NSMenu" ref="1065607017"/>
+                                                                                               <string key="NSTitle">Clear Menu</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                               <string key="NSName">_NSRecentDocumentsMenu</string>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="425164168">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="776162233">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Close</string>
+                                                                       <string key="NSKeyEquiv">w</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1023925487">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Save</string>
+                                                                       <string key="NSKeyEquiv">s</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="117038363">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Save As…</string>
+                                                                       <string key="NSKeyEquiv">S</string>
+                                                                       <int key="NSKeyEquivModMask">1179648</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="579971712">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Revert to Saved</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1010469920">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="294629803">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Page Setup...</string>
+                                                                       <string key="NSKeyEquiv">P</string>
+                                                                       <int key="NSKeyEquivModMask">1179648</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSToolTip"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="49223823">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Print…</string>
+                                                                       <string key="NSKeyEquiv">p</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                       </object>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="952259628">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">Edit</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSKeyEquivModMask">1048576</int>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="789758025">
+                                                       <string key="NSTitle">Edit</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="1058277027">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Undo</string>
+                                                                       <string key="NSKeyEquiv">z</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="790794224">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Redo</string>
+                                                                       <string key="NSKeyEquiv">Z</string>
+                                                                       <int key="NSKeyEquivModMask">1179648</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1040322652">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="296257095">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Cut</string>
+                                                                       <string key="NSKeyEquiv">x</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="860595796">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Copy</string>
+                                                                       <string key="NSKeyEquiv">c</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="29853731">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Paste</string>
+                                                                       <string key="NSKeyEquiv">v</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="82994268">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Paste and Match Style</string>
+                                                                       <string key="NSKeyEquiv">V</string>
+                                                                       <int key="NSKeyEquivModMask">1572864</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="437104165">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Delete</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="583158037">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Select All</string>
+                                                                       <string key="NSKeyEquiv">a</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="212016141">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="892235320">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Find</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="963351320">
+                                                                               <string key="NSTitle">Find</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="447796847">
+                                                                                               <reference key="NSMenu" ref="963351320"/>
+                                                                                               <string key="NSTitle">Find…</string>
+                                                                                               <string key="NSKeyEquiv">f</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">1</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="326711663">
+                                                                                               <reference key="NSMenu" ref="963351320"/>
+                                                                                               <string key="NSTitle">Find Next</string>
+                                                                                               <string key="NSKeyEquiv">g</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">2</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="270902937">
+                                                                                               <reference key="NSMenu" ref="963351320"/>
+                                                                                               <string key="NSTitle">Find Previous</string>
+                                                                                               <string key="NSKeyEquiv">G</string>
+                                                                                               <int key="NSKeyEquivModMask">1179648</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">3</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="159080638">
+                                                                                               <reference key="NSMenu" ref="963351320"/>
+                                                                                               <string key="NSTitle">Use Selection for Find</string>
+                                                                                               <string key="NSKeyEquiv">e</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">7</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="88285865">
+                                                                                               <reference key="NSMenu" ref="963351320"/>
+                                                                                               <string key="NSTitle">Jump to Selection</string>
+                                                                                               <string key="NSKeyEquiv">j</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="972420730">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Spelling and Grammar</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="769623530">
+                                                                               <string key="NSTitle">Spelling and Grammar</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="679648819">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <string key="NSTitle">Show Spelling and Grammar</string>
+                                                                                               <string key="NSKeyEquiv">:</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="96193923">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <string key="NSTitle">Check Document Now</string>
+                                                                                               <string key="NSKeyEquiv">;</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="859480356">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="948374510">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <string key="NSTitle">Check Spelling While Typing</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="967646866">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <string key="NSTitle">Check Grammar With Spelling</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="795346622">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <string key="NSTitle">Correct Spelling Automatically</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="507821607">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Substitutions</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="698887838">
+                                                                               <string key="NSTitle">Substitutions</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="65139061">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Show Substitutions</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="19036812">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="605118523">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Smart Copy/Paste</string>
+                                                                                               <string key="NSKeyEquiv">f</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">1</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="197661976">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Smart Quotes</string>
+                                                                                               <string key="NSKeyEquiv">g</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">2</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="672708820">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Smart Dashes</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="708854459">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Smart Links</string>
+                                                                                               <string key="NSKeyEquiv">G</string>
+                                                                                               <int key="NSKeyEquivModMask">1179648</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">3</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="537092702">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Text Replacement</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="288088188">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Transformations</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="579392910">
+                                                                               <string key="NSTitle">Transformations</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="1060694897">
+                                                                                               <reference key="NSMenu" ref="579392910"/>
+                                                                                               <string key="NSTitle">Make Upper Case</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="879586729">
+                                                                                               <reference key="NSMenu" ref="579392910"/>
+                                                                                               <string key="NSTitle">Make Lower Case</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="56570060">
+                                                                                               <reference key="NSMenu" ref="579392910"/>
+                                                                                               <string key="NSTitle">Capitalize</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="676164635">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Speech</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="785027613">
+                                                                               <string key="NSTitle">Speech</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="731782645">
+                                                                                               <reference key="NSMenu" ref="785027613"/>
+                                                                                               <string key="NSTitle">Start Speaking</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="680220178">
+                                                                                               <reference key="NSMenu" ref="785027613"/>
+                                                                                               <string key="NSTitle">Stop Speaking</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                       </object>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="302598603">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">Format</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="941447902">
+                                                       <string key="NSTitle">Format</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="792887677">
+                                                                       <reference key="NSMenu" ref="941447902"/>
+                                                                       <string key="NSTitle">Font</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="786677654">
+                                                                               <string key="NSTitle">Font</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="159677712">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Show Fonts</string>
+                                                                                               <string key="NSKeyEquiv">t</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="305399458">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Bold</string>
+                                                                                               <string key="NSKeyEquiv">b</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">2</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="814362025">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Italic</string>
+                                                                                               <string key="NSKeyEquiv">i</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">1</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="330926929">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Underline</string>
+                                                                                               <string key="NSKeyEquiv">u</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="533507878">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="158063935">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Bigger</string>
+                                                                                               <string key="NSKeyEquiv">+</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">3</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="885547335">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Smaller</string>
+                                                                                               <string key="NSKeyEquiv">-</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">4</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="901062459">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="767671776">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Kern</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <string key="NSAction">submenuAction:</string>
+                                                                                               <object class="NSMenu" key="NSSubmenu" id="175441468">
+                                                                                                       <string key="NSTitle">Kern</string>
+                                                                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                                               <object class="NSMenuItem" id="252969304">
+                                                                                                                       <reference key="NSMenu" ref="175441468"/>
+                                                                                                                       <string key="NSTitle">Use Default</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="766922938">
+                                                                                                                       <reference key="NSMenu" ref="175441468"/>
+                                                                                                                       <string key="NSTitle">Use None</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="677519740">
+                                                                                                                       <reference key="NSMenu" ref="175441468"/>
+                                                                                                                       <string key="NSTitle">Tighten</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="238351151">
+                                                                                                                       <reference key="NSMenu" ref="175441468"/>
+                                                                                                                       <string key="NSTitle">Loosen</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                       </object>
+                                                                                               </object>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="691570813">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Ligature</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <string key="NSAction">submenuAction:</string>
+                                                                                               <object class="NSMenu" key="NSSubmenu" id="1058217995">
+                                                                                                       <string key="NSTitle">Ligature</string>
+                                                                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                                               <object class="NSMenuItem" id="706297211">
+                                                                                                                       <reference key="NSMenu" ref="1058217995"/>
+                                                                                                                       <string key="NSTitle">Use Default</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="568384683">
+                                                                                                                       <reference key="NSMenu" ref="1058217995"/>
+                                                                                                                       <string key="NSTitle">Use None</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="663508465">
+                                                                                                                       <reference key="NSMenu" ref="1058217995"/>
+                                                                                                                       <string key="NSTitle">Use All</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                       </object>
+                                                                                               </object>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="769124883">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Baseline</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <string key="NSAction">submenuAction:</string>
+                                                                                               <object class="NSMenu" key="NSSubmenu" id="18263474">
+                                                                                                       <string key="NSTitle">Baseline</string>
+                                                                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                                               <object class="NSMenuItem" id="257962622">
+                                                                                                                       <reference key="NSMenu" ref="18263474"/>
+                                                                                                                       <string key="NSTitle">Use Default</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="644725453">
+                                                                                                                       <reference key="NSMenu" ref="18263474"/>
+                                                                                                                       <string key="NSTitle">Superscript</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="1037576581">
+                                                                                                                       <reference key="NSMenu" ref="18263474"/>
+                                                                                                                       <string key="NSTitle">Subscript</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="941806246">
+                                                                                                                       <reference key="NSMenu" ref="18263474"/>
+                                                                                                                       <string key="NSTitle">Raise</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="1045724900">
+                                                                                                                       <reference key="NSMenu" ref="18263474"/>
+                                                                                                                       <string key="NSTitle">Lower</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                       </object>
+                                                                                               </object>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="739652853">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="1012600125">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Show Colors</string>
+                                                                                               <string key="NSKeyEquiv">C</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="214559597">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="596732606">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Copy Style</string>
+                                                                                               <string key="NSKeyEquiv">c</string>
+                                                                                               <int key="NSKeyEquivModMask">1572864</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="393423671">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Paste Style</string>
+                                                                                               <string key="NSKeyEquiv">v</string>
+                                                                                               <int key="NSKeyEquivModMask">1572864</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                               <string key="NSName">_NSFontMenu</string>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="215659978">
+                                                                       <reference key="NSMenu" ref="941447902"/>
+                                                                       <string key="NSTitle">Text</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="446991534">
+                                                                               <string key="NSTitle">Text</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="875092757">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Align Left</string>
+                                                                                               <string key="NSKeyEquiv">{</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="630155264">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Center</string>
+                                                                                               <string key="NSKeyEquiv">|</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="945678886">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Justify</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="512868991">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Align Right</string>
+                                                                                               <string key="NSKeyEquiv">}</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="163117631">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="31516759">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Writing Direction</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <string key="NSAction">submenuAction:</string>
+                                                                                               <object class="NSMenu" key="NSSubmenu" id="956096989">
+                                                                                                       <string key="NSTitle">Writing Direction</string>
+                                                                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                                               <object class="NSMenuItem" id="257099033">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                                                                       <string key="NSTitle">Paragraph</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="551969625">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="249532473">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="607364498">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="508151438">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                                                                       <string key="NSTitle"/>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="981751889">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                                                                       <string key="NSTitle">Selection</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="380031999">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="825984362">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="560145579">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                       </object>
+                                                                                               </object>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="908105787">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="644046920">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Show Ruler</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="231811626">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Copy Ruler</string>
+                                                                                               <string key="NSKeyEquiv">c</string>
+                                                                                               <int key="NSKeyEquivModMask">1310720</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="883618387">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Paste Ruler</string>
+                                                                                               <string key="NSKeyEquiv">v</string>
+                                                                                               <int key="NSKeyEquivModMask">1310720</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                       </object>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="586577488">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">View</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSKeyEquivModMask">1048576</int>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="466310130">
+                                                       <string key="NSTitle">View</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="102151532">
+                                                                       <reference key="NSMenu" ref="466310130"/>
+                                                                       <string key="NSTitle">Show Toolbar</string>
+                                                                       <string key="NSKeyEquiv">t</string>
+                                                                       <int key="NSKeyEquivModMask">1572864</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="237841660">
+                                                                       <reference key="NSMenu" ref="466310130"/>
+                                                                       <string key="NSTitle">Customize Toolbar…</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                       </object>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="713487014">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">Window</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSKeyEquivModMask">1048576</int>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="835318025">
+                                                       <string key="NSTitle">Window</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="1011231497">
+                                                                       <reference key="NSMenu" ref="835318025"/>
+                                                                       <string key="NSTitle">Minimize</string>
+                                                                       <string key="NSKeyEquiv">m</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="575023229">
+                                                                       <reference key="NSMenu" ref="835318025"/>
+                                                                       <string key="NSTitle">Zoom</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="299356726">
+                                                                       <reference key="NSMenu" ref="835318025"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="625202149">
+                                                                       <reference key="NSMenu" ref="835318025"/>
+                                                                       <string key="NSTitle">Bring All to Front</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                       </object>
+                                                       <string key="NSName">_NSWindowsMenu</string>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="448692316">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">Help</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="992780483">
+                                                       <string key="NSTitle">Help</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="105068016">
+                                                                       <reference key="NSMenu" ref="992780483"/>
+                                                                       <string key="NSTitle">TestApp Help</string>
+                                                                       <string key="NSKeyEquiv">?</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                       </object>
+                                                       <string key="NSName">_NSHelpMenu</string>
+                                               </object>
+                                       </object>
+                               </object>
+                               <string key="NSName">_NSMainMenu</string>
+                       </object>
+                       <object class="NSWindowTemplate" id="972006081">
+                               <int key="NSWindowStyleMask">15</int>
+                               <int key="NSWindowBacking">2</int>
+                               <string key="NSWindowRect">{{335, 390}, {480, 360}}</string>
+                               <int key="NSWTFlags">1954021376</int>
+                               <string key="NSWindowTitle">TestApp</string>
+                               <string key="NSWindowClass">NSWindow</string>
+                               <nil key="NSViewClass"/>
+                               <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
+                               <object class="NSView" key="NSWindowView" id="439893737">
+                                       <reference key="NSNextResponder"/>
+                                       <int key="NSvFlags">256</int>
+                                       <string key="NSFrameSize">{480, 360}</string>
+                                       <reference key="NSSuperview"/>
+                               </object>
+                               <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
+                               <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
+                       </object>
+                       <object class="NSCustomObject" id="976324537">
+                               <string key="NSClassName">TestAppAppDelegate</string>
+                       </object>
+                       <object class="NSCustomObject" id="755631768">
+                               <string key="NSClassName">NSFontManager</string>
+                       </object>
+               </object>
+               <object class="IBObjectContainer" key="IBDocument.Objects">
+                       <object class="NSMutableArray" key="connectionRecords">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performMiniaturize:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1011231497"/>
+                                       </object>
+                                       <int key="connectionID">37</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">arrangeInFront:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="625202149"/>
+                                       </object>
+                                       <int key="connectionID">39</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">print:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="49223823"/>
+                                       </object>
+                                       <int key="connectionID">86</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">runPageLayout:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="294629803"/>
+                                       </object>
+                                       <int key="connectionID">87</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">clearRecentDocuments:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="759406840"/>
+                                       </object>
+                                       <int key="connectionID">127</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">orderFrontStandardAboutPanel:</string>
+                                               <reference key="source" ref="1021"/>
+                                               <reference key="destination" ref="238522557"/>
+                                       </object>
+                                       <int key="connectionID">142</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performClose:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="776162233"/>
+                                       </object>
+                                       <int key="connectionID">193</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleContinuousSpellChecking:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="948374510"/>
+                                       </object>
+                                       <int key="connectionID">222</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">undo:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1058277027"/>
+                                       </object>
+                                       <int key="connectionID">223</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">copy:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="860595796"/>
+                                       </object>
+                                       <int key="connectionID">224</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">checkSpelling:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="96193923"/>
+                                       </object>
+                                       <int key="connectionID">225</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">paste:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="29853731"/>
+                                       </object>
+                                       <int key="connectionID">226</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">stopSpeaking:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="680220178"/>
+                                       </object>
+                                       <int key="connectionID">227</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">cut:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="296257095"/>
+                                       </object>
+                                       <int key="connectionID">228</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">showGuessPanel:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="679648819"/>
+                                       </object>
+                                       <int key="connectionID">230</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">redo:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="790794224"/>
+                                       </object>
+                                       <int key="connectionID">231</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">selectAll:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="583158037"/>
+                                       </object>
+                                       <int key="connectionID">232</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">startSpeaking:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="731782645"/>
+                                       </object>
+                                       <int key="connectionID">233</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">delete:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="437104165"/>
+                                       </object>
+                                       <int key="connectionID">235</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performZoom:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="575023229"/>
+                                       </object>
+                                       <int key="connectionID">240</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performFindPanelAction:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="447796847"/>
+                                       </object>
+                                       <int key="connectionID">241</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">centerSelectionInVisibleArea:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="88285865"/>
+                                       </object>
+                                       <int key="connectionID">245</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleGrammarChecking:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="967646866"/>
+                                       </object>
+                                       <int key="connectionID">347</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleSmartInsertDelete:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="605118523"/>
+                                       </object>
+                                       <int key="connectionID">355</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleAutomaticQuoteSubstitution:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="197661976"/>
+                                       </object>
+                                       <int key="connectionID">356</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleAutomaticLinkDetection:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="708854459"/>
+                                       </object>
+                                       <int key="connectionID">357</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">saveDocument:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1023925487"/>
+                                       </object>
+                                       <int key="connectionID">362</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">saveDocumentAs:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="117038363"/>
+                                       </object>
+                                       <int key="connectionID">363</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">revertDocumentToSaved:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="579971712"/>
+                                       </object>
+                                       <int key="connectionID">364</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">runToolbarCustomizationPalette:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="237841660"/>
+                                       </object>
+                                       <int key="connectionID">365</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleToolbarShown:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="102151532"/>
+                                       </object>
+                                       <int key="connectionID">366</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">hide:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="755159360"/>
+                                       </object>
+                                       <int key="connectionID">367</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">hideOtherApplications:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="342932134"/>
+                                       </object>
+                                       <int key="connectionID">368</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">unhideAllApplications:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="908899353"/>
+                                       </object>
+                                       <int key="connectionID">370</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">newDocument:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="705341025"/>
+                                       </object>
+                                       <int key="connectionID">373</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">openDocument:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="722745758"/>
+                                       </object>
+                                       <int key="connectionID">374</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">addFontTrait:</string>
+                                               <reference key="source" ref="755631768"/>
+                                               <reference key="destination" ref="305399458"/>
+                                       </object>
+                                       <int key="connectionID">421</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">addFontTrait:</string>
+                                               <reference key="source" ref="755631768"/>
+                                               <reference key="destination" ref="814362025"/>
+                                       </object>
+                                       <int key="connectionID">422</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">modifyFont:</string>
+                                               <reference key="source" ref="755631768"/>
+                                               <reference key="destination" ref="885547335"/>
+                                       </object>
+                                       <int key="connectionID">423</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">orderFrontFontPanel:</string>
+                                               <reference key="source" ref="755631768"/>
+                                               <reference key="destination" ref="159677712"/>
+                                       </object>
+                                       <int key="connectionID">424</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">modifyFont:</string>
+                                               <reference key="source" ref="755631768"/>
+                                               <reference key="destination" ref="158063935"/>
+                                       </object>
+                                       <int key="connectionID">425</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">raiseBaseline:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="941806246"/>
+                                       </object>
+                                       <int key="connectionID">426</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">lowerBaseline:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1045724900"/>
+                                       </object>
+                                       <int key="connectionID">427</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">copyFont:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="596732606"/>
+                                       </object>
+                                       <int key="connectionID">428</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">subscript:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1037576581"/>
+                                       </object>
+                                       <int key="connectionID">429</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">superscript:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="644725453"/>
+                                       </object>
+                                       <int key="connectionID">430</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">tightenKerning:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="677519740"/>
+                                       </object>
+                                       <int key="connectionID">431</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">underline:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="330926929"/>
+                                       </object>
+                                       <int key="connectionID">432</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">orderFrontColorPanel:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1012600125"/>
+                                       </object>
+                                       <int key="connectionID">433</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">useAllLigatures:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="663508465"/>
+                                       </object>
+                                       <int key="connectionID">434</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">loosenKerning:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="238351151"/>
+                                       </object>
+                                       <int key="connectionID">435</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">pasteFont:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="393423671"/>
+                                       </object>
+                                       <int key="connectionID">436</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">unscript:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="257962622"/>
+                                       </object>
+                                       <int key="connectionID">437</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">useStandardKerning:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="252969304"/>
+                                       </object>
+                                       <int key="connectionID">438</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">useStandardLigatures:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="706297211"/>
+                                       </object>
+                                       <int key="connectionID">439</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">turnOffLigatures:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="568384683"/>
+                                       </object>
+                                       <int key="connectionID">440</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">turnOffKerning:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="766922938"/>
+                                       </object>
+                                       <int key="connectionID">441</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">terminate:</string>
+                                               <reference key="source" ref="1050"/>
+                                               <reference key="destination" ref="632727374"/>
+                                       </object>
+                                       <int key="connectionID">449</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleAutomaticSpellingCorrection:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="795346622"/>
+                                       </object>
+                                       <int key="connectionID">456</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">orderFrontSubstitutionsPanel:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="65139061"/>
+                                       </object>
+                                       <int key="connectionID">458</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleAutomaticDashSubstitution:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="672708820"/>
+                                       </object>
+                                       <int key="connectionID">461</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleAutomaticTextReplacement:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="537092702"/>
+                                       </object>
+                                       <int key="connectionID">463</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">uppercaseWord:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1060694897"/>
+                                       </object>
+                                       <int key="connectionID">464</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">capitalizeWord:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="56570060"/>
+                                       </object>
+                                       <int key="connectionID">467</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">lowercaseWord:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="879586729"/>
+                                       </object>
+                                       <int key="connectionID">468</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">pasteAsPlainText:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="82994268"/>
+                                       </object>
+                                       <int key="connectionID">486</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performFindPanelAction:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="326711663"/>
+                                       </object>
+                                       <int key="connectionID">487</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performFindPanelAction:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="270902937"/>
+                                       </object>
+                                       <int key="connectionID">488</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performFindPanelAction:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="159080638"/>
+                                       </object>
+                                       <int key="connectionID">489</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">showHelp:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="105068016"/>
+                                       </object>
+                                       <int key="connectionID">493</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">delegate</string>
+                                               <reference key="source" ref="1021"/>
+                                               <reference key="destination" ref="976324537"/>
+                                       </object>
+                                       <int key="connectionID">495</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">alignCenter:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="630155264"/>
+                                       </object>
+                                       <int key="connectionID">518</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">pasteRuler:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="883618387"/>
+                                       </object>
+                                       <int key="connectionID">519</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleRuler:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="644046920"/>
+                                       </object>
+                                       <int key="connectionID">520</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">alignRight:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="512868991"/>
+                                       </object>
+                                       <int key="connectionID">521</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">copyRuler:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="231811626"/>
+                                       </object>
+                                       <int key="connectionID">522</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">alignJustified:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="945678886"/>
+                                       </object>
+                                       <int key="connectionID">523</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">alignLeft:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="875092757"/>
+                                       </object>
+                                       <int key="connectionID">524</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeBaseWritingDirectionNatural:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="551969625"/>
+                                       </object>
+                                       <int key="connectionID">525</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeBaseWritingDirectionLeftToRight:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="249532473"/>
+                                       </object>
+                                       <int key="connectionID">526</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeBaseWritingDirectionRightToLeft:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="607364498"/>
+                                       </object>
+                                       <int key="connectionID">527</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeTextWritingDirectionNatural:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="380031999"/>
+                                       </object>
+                                       <int key="connectionID">528</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeTextWritingDirectionLeftToRight:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="825984362"/>
+                                       </object>
+                                       <int key="connectionID">529</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeTextWritingDirectionRightToLeft:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="560145579"/>
+                                       </object>
+                                       <int key="connectionID">530</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">window</string>
+                                               <reference key="source" ref="976324537"/>
+                                               <reference key="destination" ref="972006081"/>
+                                       </object>
+                                       <int key="connectionID">532</int>
+                               </object>
+                       </object>
+                       <object class="IBMutableOrderedSet" key="objectRecords">
+                               <object class="NSArray" key="orderedObjects">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">0</int>
+                                               <reference key="object" ref="0"/>
+                                               <reference key="children" ref="1048"/>
+                                               <nil key="parent"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">-2</int>
+                                               <reference key="object" ref="1021"/>
+                                               <reference key="parent" ref="0"/>
+                                               <string key="objectName">File's Owner</string>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">-1</int>
+                                               <reference key="object" ref="1014"/>
+                                               <reference key="parent" ref="0"/>
+                                               <string key="objectName">First Responder</string>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">-3</int>
+                                               <reference key="object" ref="1050"/>
+                                               <reference key="parent" ref="0"/>
+                                               <string key="objectName">Application</string>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">29</int>
+                                               <reference key="object" ref="649796088"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="713487014"/>
+                                                       <reference ref="694149608"/>
+                                                       <reference ref="952259628"/>
+                                                       <reference ref="379814623"/>
+                                                       <reference ref="586577488"/>
+                                                       <reference ref="302598603"/>
+                                                       <reference ref="448692316"/>
+                                               </object>
+                                               <reference key="parent" ref="0"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">19</int>
+                                               <reference key="object" ref="713487014"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="835318025"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">56</int>
+                                               <reference key="object" ref="694149608"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="110575045"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">217</int>
+                                               <reference key="object" ref="952259628"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="789758025"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">83</int>
+                                               <reference key="object" ref="379814623"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="720053764"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">81</int>
+                                               <reference key="object" ref="720053764"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="1023925487"/>
+                                                       <reference ref="117038363"/>
+                                                       <reference ref="49223823"/>
+                                                       <reference ref="722745758"/>
+                                                       <reference ref="705341025"/>
+                                                       <reference ref="1025936716"/>
+                                                       <reference ref="294629803"/>
+                                                       <reference ref="776162233"/>
+                                                       <reference ref="425164168"/>
+                                                       <reference ref="579971712"/>
+                                                       <reference ref="1010469920"/>
+                                               </object>
+                                               <reference key="parent" ref="379814623"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">75</int>
+                                               <reference key="object" ref="1023925487"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">80</int>
+                                               <reference key="object" ref="117038363"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">78</int>
+                                               <reference key="object" ref="49223823"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">72</int>
+                                               <reference key="object" ref="722745758"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">82</int>
+                                               <reference key="object" ref="705341025"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">124</int>
+                                               <reference key="object" ref="1025936716"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="1065607017"/>
+                                               </object>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">77</int>
+                                               <reference key="object" ref="294629803"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">73</int>
+                                               <reference key="object" ref="776162233"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">79</int>
+                                               <reference key="object" ref="425164168"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">112</int>
+                                               <reference key="object" ref="579971712"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">74</int>
+                                               <reference key="object" ref="1010469920"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">125</int>
+                                               <reference key="object" ref="1065607017"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="759406840"/>
+                                               </object>
+                                               <reference key="parent" ref="1025936716"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">126</int>
+                                               <reference key="object" ref="759406840"/>
+                                               <reference key="parent" ref="1065607017"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">205</int>
+                                               <reference key="object" ref="789758025"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="437104165"/>
+                                                       <reference ref="583158037"/>
+                                                       <reference ref="1058277027"/>
+                                                       <reference ref="212016141"/>
+                                                       <reference ref="296257095"/>
+                                                       <reference ref="29853731"/>
+                                                       <reference ref="860595796"/>
+                                                       <reference ref="1040322652"/>
+                                                       <reference ref="790794224"/>
+                                                       <reference ref="892235320"/>
+                                                       <reference ref="972420730"/>
+                                                       <reference ref="676164635"/>
+                                                       <reference ref="507821607"/>
+                                                       <reference ref="288088188"/>
+                                                       <reference ref="82994268"/>
+                                               </object>
+                                               <reference key="parent" ref="952259628"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">202</int>
+                                               <reference key="object" ref="437104165"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">198</int>
+                                               <reference key="object" ref="583158037"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">207</int>
+                                               <reference key="object" ref="1058277027"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">214</int>
+                                               <reference key="object" ref="212016141"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">199</int>
+                                               <reference key="object" ref="296257095"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">203</int>
+                                               <reference key="object" ref="29853731"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">197</int>
+                                               <reference key="object" ref="860595796"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">206</int>
+                                               <reference key="object" ref="1040322652"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">215</int>
+                                               <reference key="object" ref="790794224"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">218</int>
+                                               <reference key="object" ref="892235320"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="963351320"/>
+                                               </object>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">216</int>
+                                               <reference key="object" ref="972420730"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="769623530"/>
+                                               </object>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">200</int>
+                                               <reference key="object" ref="769623530"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="948374510"/>
+                                                       <reference ref="96193923"/>
+                                                       <reference ref="679648819"/>
+                                                       <reference ref="967646866"/>
+                                                       <reference ref="859480356"/>
+                                                       <reference ref="795346622"/>
+                                               </object>
+                                               <reference key="parent" ref="972420730"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">219</int>
+                                               <reference key="object" ref="948374510"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">201</int>
+                                               <reference key="object" ref="96193923"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">204</int>
+                                               <reference key="object" ref="679648819"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">220</int>
+                                               <reference key="object" ref="963351320"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="270902937"/>
+                                                       <reference ref="88285865"/>
+                                                       <reference ref="159080638"/>
+                                                       <reference ref="326711663"/>
+                                                       <reference ref="447796847"/>
+                                               </object>
+                                               <reference key="parent" ref="892235320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">213</int>
+                                               <reference key="object" ref="270902937"/>
+                                               <reference key="parent" ref="963351320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">210</int>
+                                               <reference key="object" ref="88285865"/>
+                                               <reference key="parent" ref="963351320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">221</int>
+                                               <reference key="object" ref="159080638"/>
+                                               <reference key="parent" ref="963351320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">208</int>
+                                               <reference key="object" ref="326711663"/>
+                                               <reference key="parent" ref="963351320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">209</int>
+                                               <reference key="object" ref="447796847"/>
+                                               <reference key="parent" ref="963351320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">57</int>
+                                               <reference key="object" ref="110575045"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="238522557"/>
+                                                       <reference ref="755159360"/>
+                                                       <reference ref="908899353"/>
+                                                       <reference ref="632727374"/>
+                                                       <reference ref="646227648"/>
+                                                       <reference ref="609285721"/>
+                                                       <reference ref="481834944"/>
+                                                       <reference ref="304266470"/>
+                                                       <reference ref="1046388886"/>
+                                                       <reference ref="1056857174"/>
+                                                       <reference ref="342932134"/>
+                                               </object>
+                                               <reference key="parent" ref="694149608"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">58</int>
+                                               <reference key="object" ref="238522557"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">134</int>
+                                               <reference key="object" ref="755159360"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">150</int>
+                                               <reference key="object" ref="908899353"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">136</int>
+                                               <reference key="object" ref="632727374"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">144</int>
+                                               <reference key="object" ref="646227648"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">129</int>
+                                               <reference key="object" ref="609285721"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">143</int>
+                                               <reference key="object" ref="481834944"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">236</int>
+                                               <reference key="object" ref="304266470"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">131</int>
+                                               <reference key="object" ref="1046388886"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="752062318"/>
+                                               </object>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">149</int>
+                                               <reference key="object" ref="1056857174"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">145</int>
+                                               <reference key="object" ref="342932134"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">130</int>
+                                               <reference key="object" ref="752062318"/>
+                                               <reference key="parent" ref="1046388886"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">24</int>
+                                               <reference key="object" ref="835318025"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="299356726"/>
+                                                       <reference ref="625202149"/>
+                                                       <reference ref="575023229"/>
+                                                       <reference ref="1011231497"/>
+                                               </object>
+                                               <reference key="parent" ref="713487014"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">92</int>
+                                               <reference key="object" ref="299356726"/>
+                                               <reference key="parent" ref="835318025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">5</int>
+                                               <reference key="object" ref="625202149"/>
+                                               <reference key="parent" ref="835318025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">239</int>
+                                               <reference key="object" ref="575023229"/>
+                                               <reference key="parent" ref="835318025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">23</int>
+                                               <reference key="object" ref="1011231497"/>
+                                               <reference key="parent" ref="835318025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">295</int>
+                                               <reference key="object" ref="586577488"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="466310130"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">296</int>
+                                               <reference key="object" ref="466310130"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="102151532"/>
+                                                       <reference ref="237841660"/>
+                                               </object>
+                                               <reference key="parent" ref="586577488"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">297</int>
+                                               <reference key="object" ref="102151532"/>
+                                               <reference key="parent" ref="466310130"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">298</int>
+                                               <reference key="object" ref="237841660"/>
+                                               <reference key="parent" ref="466310130"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">211</int>
+                                               <reference key="object" ref="676164635"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="785027613"/>
+                                               </object>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">212</int>
+                                               <reference key="object" ref="785027613"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="680220178"/>
+                                                       <reference ref="731782645"/>
+                                               </object>
+                                               <reference key="parent" ref="676164635"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">195</int>
+                                               <reference key="object" ref="680220178"/>
+                                               <reference key="parent" ref="785027613"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">196</int>
+                                               <reference key="object" ref="731782645"/>
+                                               <reference key="parent" ref="785027613"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">346</int>
+                                               <reference key="object" ref="967646866"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">348</int>
+                                               <reference key="object" ref="507821607"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="698887838"/>
+                                               </object>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">349</int>
+                                               <reference key="object" ref="698887838"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="605118523"/>
+                                                       <reference ref="197661976"/>
+                                                       <reference ref="708854459"/>
+                                                       <reference ref="65139061"/>
+                                                       <reference ref="19036812"/>
+                                                       <reference ref="672708820"/>
+                                                       <reference ref="537092702"/>
+                                               </object>
+                                               <reference key="parent" ref="507821607"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">350</int>
+                                               <reference key="object" ref="605118523"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">351</int>
+                                               <reference key="object" ref="197661976"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">354</int>
+                                               <reference key="object" ref="708854459"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">371</int>
+                                               <reference key="object" ref="972006081"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="439893737"/>
+                                               </object>
+                                               <reference key="parent" ref="0"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">372</int>
+                                               <reference key="object" ref="439893737"/>
+                                               <reference key="parent" ref="972006081"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">375</int>
+                                               <reference key="object" ref="302598603"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="941447902"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">376</int>
+                                               <reference key="object" ref="941447902"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="792887677"/>
+                                                       <reference ref="215659978"/>
+                                               </object>
+                                               <reference key="parent" ref="302598603"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">377</int>
+                                               <reference key="object" ref="792887677"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="786677654"/>
+                                               </object>
+                                               <reference key="parent" ref="941447902"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">388</int>
+                                               <reference key="object" ref="786677654"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="159677712"/>
+                                                       <reference ref="305399458"/>
+                                                       <reference ref="814362025"/>
+                                                       <reference ref="330926929"/>
+                                                       <reference ref="533507878"/>
+                                                       <reference ref="158063935"/>
+                                                       <reference ref="885547335"/>
+                                                       <reference ref="901062459"/>
+                                                       <reference ref="767671776"/>
+                                                       <reference ref="691570813"/>
+                                                       <reference ref="769124883"/>
+                                                       <reference ref="739652853"/>
+                                                       <reference ref="1012600125"/>
+                                                       <reference ref="214559597"/>
+                                                       <reference ref="596732606"/>
+                                                       <reference ref="393423671"/>
+                                               </object>
+                                               <reference key="parent" ref="792887677"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">389</int>
+                                               <reference key="object" ref="159677712"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">390</int>
+                                               <reference key="object" ref="305399458"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">391</int>
+                                               <reference key="object" ref="814362025"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">392</int>
+                                               <reference key="object" ref="330926929"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">393</int>
+                                               <reference key="object" ref="533507878"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">394</int>
+                                               <reference key="object" ref="158063935"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">395</int>
+                                               <reference key="object" ref="885547335"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">396</int>
+                                               <reference key="object" ref="901062459"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">397</int>
+                                               <reference key="object" ref="767671776"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="175441468"/>
+                                               </object>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">398</int>
+                                               <reference key="object" ref="691570813"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="1058217995"/>
+                                               </object>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">399</int>
+                                               <reference key="object" ref="769124883"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="18263474"/>
+                                               </object>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">400</int>
+                                               <reference key="object" ref="739652853"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">401</int>
+                                               <reference key="object" ref="1012600125"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">402</int>
+                                               <reference key="object" ref="214559597"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">403</int>
+                                               <reference key="object" ref="596732606"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">404</int>
+                                               <reference key="object" ref="393423671"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">405</int>
+                                               <reference key="object" ref="18263474"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="257962622"/>
+                                                       <reference ref="644725453"/>
+                                                       <reference ref="1037576581"/>
+                                                       <reference ref="941806246"/>
+                                                       <reference ref="1045724900"/>
+                                               </object>
+                                               <reference key="parent" ref="769124883"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">406</int>
+                                               <reference key="object" ref="257962622"/>
+                                               <reference key="parent" ref="18263474"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">407</int>
+                                               <reference key="object" ref="644725453"/>
+                                               <reference key="parent" ref="18263474"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">408</int>
+                                               <reference key="object" ref="1037576581"/>
+                                               <reference key="parent" ref="18263474"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">409</int>
+                                               <reference key="object" ref="941806246"/>
+                                               <reference key="parent" ref="18263474"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">410</int>
+                                               <reference key="object" ref="1045724900"/>
+                                               <reference key="parent" ref="18263474"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">411</int>
+                                               <reference key="object" ref="1058217995"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="706297211"/>
+                                                       <reference ref="568384683"/>
+                                                       <reference ref="663508465"/>
+                                               </object>
+                                               <reference key="parent" ref="691570813"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">412</int>
+                                               <reference key="object" ref="706297211"/>
+                                               <reference key="parent" ref="1058217995"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">413</int>
+                                               <reference key="object" ref="568384683"/>
+                                               <reference key="parent" ref="1058217995"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">414</int>
+                                               <reference key="object" ref="663508465"/>
+                                               <reference key="parent" ref="1058217995"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">415</int>
+                                               <reference key="object" ref="175441468"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="252969304"/>
+                                                       <reference ref="766922938"/>
+                                                       <reference ref="677519740"/>
+                                                       <reference ref="238351151"/>
+                                               </object>
+                                               <reference key="parent" ref="767671776"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">416</int>
+                                               <reference key="object" ref="252969304"/>
+                                               <reference key="parent" ref="175441468"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">417</int>
+                                               <reference key="object" ref="766922938"/>
+                                               <reference key="parent" ref="175441468"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">418</int>
+                                               <reference key="object" ref="677519740"/>
+                                               <reference key="parent" ref="175441468"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">419</int>
+                                               <reference key="object" ref="238351151"/>
+                                               <reference key="parent" ref="175441468"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">420</int>
+                                               <reference key="object" ref="755631768"/>
+                                               <reference key="parent" ref="0"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">450</int>
+                                               <reference key="object" ref="288088188"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="579392910"/>
+                                               </object>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">451</int>
+                                               <reference key="object" ref="579392910"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="1060694897"/>
+                                                       <reference ref="879586729"/>
+                                                       <reference ref="56570060"/>
+                                               </object>
+                                               <reference key="parent" ref="288088188"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">452</int>
+                                               <reference key="object" ref="1060694897"/>
+                                               <reference key="parent" ref="579392910"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">453</int>
+                                               <reference key="object" ref="859480356"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">454</int>
+                                               <reference key="object" ref="795346622"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">457</int>
+                                               <reference key="object" ref="65139061"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">459</int>
+                                               <reference key="object" ref="19036812"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">460</int>
+                                               <reference key="object" ref="672708820"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">462</int>
+                                               <reference key="object" ref="537092702"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">465</int>
+                                               <reference key="object" ref="879586729"/>
+                                               <reference key="parent" ref="579392910"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">466</int>
+                                               <reference key="object" ref="56570060"/>
+                                               <reference key="parent" ref="579392910"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">485</int>
+                                               <reference key="object" ref="82994268"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">490</int>
+                                               <reference key="object" ref="448692316"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="992780483"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">491</int>
+                                               <reference key="object" ref="992780483"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="105068016"/>
+                                               </object>
+                                               <reference key="parent" ref="448692316"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">492</int>
+                                               <reference key="object" ref="105068016"/>
+                                               <reference key="parent" ref="992780483"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">494</int>
+                                               <reference key="object" ref="976324537"/>
+                                               <reference key="parent" ref="0"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">496</int>
+                                               <reference key="object" ref="215659978"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="446991534"/>
+                                               </object>
+                                               <reference key="parent" ref="941447902"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">497</int>
+                                               <reference key="object" ref="446991534"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="875092757"/>
+                                                       <reference ref="630155264"/>
+                                                       <reference ref="945678886"/>
+                                                       <reference ref="512868991"/>
+                                                       <reference ref="163117631"/>
+                                                       <reference ref="31516759"/>
+                                                       <reference ref="908105787"/>
+                                                       <reference ref="644046920"/>
+                                                       <reference ref="231811626"/>
+                                                       <reference ref="883618387"/>
+                                               </object>
+                                               <reference key="parent" ref="215659978"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">498</int>
+                                               <reference key="object" ref="875092757"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">499</int>
+                                               <reference key="object" ref="630155264"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">500</int>
+                                               <reference key="object" ref="945678886"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">501</int>
+                                               <reference key="object" ref="512868991"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">502</int>
+                                               <reference key="object" ref="163117631"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">503</int>
+                                               <reference key="object" ref="31516759"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="956096989"/>
+                                               </object>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">504</int>
+                                               <reference key="object" ref="908105787"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">505</int>
+                                               <reference key="object" ref="644046920"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">506</int>
+                                               <reference key="object" ref="231811626"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">507</int>
+                                               <reference key="object" ref="883618387"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">508</int>
+                                               <reference key="object" ref="956096989"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="257099033"/>
+                                                       <reference ref="551969625"/>
+                                                       <reference ref="249532473"/>
+                                                       <reference ref="607364498"/>
+                                                       <reference ref="508151438"/>
+                                                       <reference ref="981751889"/>
+                                                       <reference ref="380031999"/>
+                                                       <reference ref="825984362"/>
+                                                       <reference ref="560145579"/>
+                                               </object>
+                                               <reference key="parent" ref="31516759"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">509</int>
+                                               <reference key="object" ref="257099033"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">510</int>
+                                               <reference key="object" ref="551969625"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">511</int>
+                                               <reference key="object" ref="249532473"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">512</int>
+                                               <reference key="object" ref="607364498"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">513</int>
+                                               <reference key="object" ref="508151438"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">514</int>
+                                               <reference key="object" ref="981751889"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">515</int>
+                                               <reference key="object" ref="380031999"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">516</int>
+                                               <reference key="object" ref="825984362"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">517</int>
+                                               <reference key="object" ref="560145579"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                               </object>
+                       </object>
+                       <object class="NSMutableDictionary" key="flattenedProperties">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <object class="NSArray" key="dict.sortedKeys">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                       <string>-3.IBPluginDependency</string>
+                                       <string>112.IBPluginDependency</string>
+                                       <string>112.ImportedFromIB2</string>
+                                       <string>124.IBPluginDependency</string>
+                                       <string>124.ImportedFromIB2</string>
+                                       <string>125.IBPluginDependency</string>
+                                       <string>125.ImportedFromIB2</string>
+                                       <string>125.editorWindowContentRectSynchronizationRect</string>
+                                       <string>126.IBPluginDependency</string>
+                                       <string>126.ImportedFromIB2</string>
+                                       <string>129.IBPluginDependency</string>
+                                       <string>129.ImportedFromIB2</string>
+                                       <string>130.IBPluginDependency</string>
+                                       <string>130.ImportedFromIB2</string>
+                                       <string>130.editorWindowContentRectSynchronizationRect</string>
+                                       <string>131.IBPluginDependency</string>
+                                       <string>131.ImportedFromIB2</string>
+                                       <string>134.IBPluginDependency</string>
+                                       <string>134.ImportedFromIB2</string>
+                                       <string>136.IBPluginDependency</string>
+                                       <string>136.ImportedFromIB2</string>
+                                       <string>143.IBPluginDependency</string>
+                                       <string>143.ImportedFromIB2</string>
+                                       <string>144.IBPluginDependency</string>
+                                       <string>144.ImportedFromIB2</string>
+                                       <string>145.IBPluginDependency</string>
+                                       <string>145.ImportedFromIB2</string>
+                                       <string>149.IBPluginDependency</string>
+                                       <string>149.ImportedFromIB2</string>
+                                       <string>150.IBPluginDependency</string>
+                                       <string>150.ImportedFromIB2</string>
+                                       <string>19.IBPluginDependency</string>
+                                       <string>19.ImportedFromIB2</string>
+                                       <string>195.IBPluginDependency</string>
+                                       <string>195.ImportedFromIB2</string>
+                                       <string>196.IBPluginDependency</string>
+                                       <string>196.ImportedFromIB2</string>
+                                       <string>197.IBPluginDependency</string>
+                                       <string>197.ImportedFromIB2</string>
+                                       <string>198.IBPluginDependency</string>
+                                       <string>198.ImportedFromIB2</string>
+                                       <string>199.IBPluginDependency</string>
+                                       <string>199.ImportedFromIB2</string>
+                                       <string>200.IBEditorWindowLastContentRect</string>
+                                       <string>200.IBPluginDependency</string>
+                                       <string>200.ImportedFromIB2</string>
+                                       <string>200.editorWindowContentRectSynchronizationRect</string>
+                                       <string>201.IBPluginDependency</string>
+                                       <string>201.ImportedFromIB2</string>
+                                       <string>202.IBPluginDependency</string>
+                                       <string>202.ImportedFromIB2</string>
+                                       <string>203.IBPluginDependency</string>
+                                       <string>203.ImportedFromIB2</string>
+                                       <string>204.IBPluginDependency</string>
+                                       <string>204.ImportedFromIB2</string>
+                                       <string>205.IBEditorWindowLastContentRect</string>
+                                       <string>205.IBPluginDependency</string>
+                                       <string>205.ImportedFromIB2</string>
+                                       <string>205.editorWindowContentRectSynchronizationRect</string>
+                                       <string>206.IBPluginDependency</string>
+                                       <string>206.ImportedFromIB2</string>
+                                       <string>207.IBPluginDependency</string>
+                                       <string>207.ImportedFromIB2</string>
+                                       <string>208.IBPluginDependency</string>
+                                       <string>208.ImportedFromIB2</string>
+                                       <string>209.IBPluginDependency</string>
+                                       <string>209.ImportedFromIB2</string>
+                                       <string>210.IBPluginDependency</string>
+                                       <string>210.ImportedFromIB2</string>
+                                       <string>211.IBPluginDependency</string>
+                                       <string>211.ImportedFromIB2</string>
+                                       <string>212.IBPluginDependency</string>
+                                       <string>212.ImportedFromIB2</string>
+                                       <string>212.editorWindowContentRectSynchronizationRect</string>
+                                       <string>213.IBPluginDependency</string>
+                                       <string>213.ImportedFromIB2</string>
+                                       <string>214.IBPluginDependency</string>
+                                       <string>214.ImportedFromIB2</string>
+                                       <string>215.IBPluginDependency</string>
+                                       <string>215.ImportedFromIB2</string>
+                                       <string>216.IBPluginDependency</string>
+                                       <string>216.ImportedFromIB2</string>
+                                       <string>217.IBPluginDependency</string>
+                                       <string>217.ImportedFromIB2</string>
+                                       <string>218.IBPluginDependency</string>
+                                       <string>218.ImportedFromIB2</string>
+                                       <string>219.IBPluginDependency</string>
+                                       <string>219.ImportedFromIB2</string>
+                                       <string>220.IBEditorWindowLastContentRect</string>
+                                       <string>220.IBPluginDependency</string>
+                                       <string>220.ImportedFromIB2</string>
+                                       <string>220.editorWindowContentRectSynchronizationRect</string>
+                                       <string>221.IBPluginDependency</string>
+                                       <string>221.ImportedFromIB2</string>
+                                       <string>23.IBPluginDependency</string>
+                                       <string>23.ImportedFromIB2</string>
+                                       <string>236.IBPluginDependency</string>
+                                       <string>236.ImportedFromIB2</string>
+                                       <string>239.IBPluginDependency</string>
+                                       <string>239.ImportedFromIB2</string>
+                                       <string>24.IBEditorWindowLastContentRect</string>
+                                       <string>24.IBPluginDependency</string>
+                                       <string>24.ImportedFromIB2</string>
+                                       <string>24.editorWindowContentRectSynchronizationRect</string>
+                                       <string>29.IBEditorWindowLastContentRect</string>
+                                       <string>29.IBPluginDependency</string>
+                                       <string>29.ImportedFromIB2</string>
+                                       <string>29.WindowOrigin</string>
+                                       <string>29.editorWindowContentRectSynchronizationRect</string>
+                                       <string>295.IBPluginDependency</string>
+                                       <string>296.IBEditorWindowLastContentRect</string>
+                                       <string>296.IBPluginDependency</string>
+                                       <string>296.editorWindowContentRectSynchronizationRect</string>
+                                       <string>297.IBPluginDependency</string>
+                                       <string>298.IBPluginDependency</string>
+                                       <string>346.IBPluginDependency</string>
+                                       <string>346.ImportedFromIB2</string>
+                                       <string>348.IBPluginDependency</string>
+                                       <string>348.ImportedFromIB2</string>
+                                       <string>349.IBEditorWindowLastContentRect</string>
+                                       <string>349.IBPluginDependency</string>
+                                       <string>349.ImportedFromIB2</string>
+                                       <string>349.editorWindowContentRectSynchronizationRect</string>
+                                       <string>350.IBPluginDependency</string>
+                                       <string>350.ImportedFromIB2</string>
+                                       <string>351.IBPluginDependency</string>
+                                       <string>351.ImportedFromIB2</string>
+                                       <string>354.IBPluginDependency</string>
+                                       <string>354.ImportedFromIB2</string>
+                                       <string>371.IBEditorWindowLastContentRect</string>
+                                       <string>371.IBPluginDependency</string>
+                                       <string>371.IBWindowTemplateEditedContentRect</string>
+                                       <string>371.NSWindowTemplate.visibleAtLaunch</string>
+                                       <string>371.editorWindowContentRectSynchronizationRect</string>
+                                       <string>371.windowTemplate.maxSize</string>
+                                       <string>372.IBPluginDependency</string>
+                                       <string>375.IBPluginDependency</string>
+                                       <string>376.IBEditorWindowLastContentRect</string>
+                                       <string>376.IBPluginDependency</string>
+                                       <string>377.IBPluginDependency</string>
+                                       <string>388.IBEditorWindowLastContentRect</string>
+                                       <string>388.IBPluginDependency</string>
+                                       <string>389.IBPluginDependency</string>
+                                       <string>390.IBPluginDependency</string>
+                                       <string>391.IBPluginDependency</string>
+                                       <string>392.IBPluginDependency</string>
+                                       <string>393.IBPluginDependency</string>
+                                       <string>394.IBPluginDependency</string>
+                                       <string>395.IBPluginDependency</string>
+                                       <string>396.IBPluginDependency</string>
+                                       <string>397.IBPluginDependency</string>
+                                       <string>398.IBPluginDependency</string>
+                                       <string>399.IBPluginDependency</string>
+                                       <string>400.IBPluginDependency</string>
+                                       <string>401.IBPluginDependency</string>
+                                       <string>402.IBPluginDependency</string>
+                                       <string>403.IBPluginDependency</string>
+                                       <string>404.IBPluginDependency</string>
+                                       <string>405.IBPluginDependency</string>
+                                       <string>406.IBPluginDependency</string>
+                                       <string>407.IBPluginDependency</string>
+                                       <string>408.IBPluginDependency</string>
+                                       <string>409.IBPluginDependency</string>
+                                       <string>410.IBPluginDependency</string>
+                                       <string>411.IBPluginDependency</string>
+                                       <string>412.IBPluginDependency</string>
+                                       <string>413.IBPluginDependency</string>
+                                       <string>414.IBPluginDependency</string>
+                                       <string>415.IBPluginDependency</string>
+                                       <string>416.IBPluginDependency</string>
+                                       <string>417.IBPluginDependency</string>
+                                       <string>418.IBPluginDependency</string>
+                                       <string>419.IBPluginDependency</string>
+                                       <string>450.IBPluginDependency</string>
+                                       <string>451.IBEditorWindowLastContentRect</string>
+                                       <string>451.IBPluginDependency</string>
+                                       <string>452.IBPluginDependency</string>
+                                       <string>453.IBPluginDependency</string>
+                                       <string>454.IBPluginDependency</string>
+                                       <string>457.IBPluginDependency</string>
+                                       <string>459.IBPluginDependency</string>
+                                       <string>460.IBPluginDependency</string>
+                                       <string>462.IBPluginDependency</string>
+                                       <string>465.IBPluginDependency</string>
+                                       <string>466.IBPluginDependency</string>
+                                       <string>485.IBPluginDependency</string>
+                                       <string>490.IBPluginDependency</string>
+                                       <string>491.IBEditorWindowLastContentRect</string>
+                                       <string>491.IBPluginDependency</string>
+                                       <string>492.IBPluginDependency</string>
+                                       <string>496.IBPluginDependency</string>
+                                       <string>497.IBEditorWindowLastContentRect</string>
+                                       <string>497.IBPluginDependency</string>
+                                       <string>498.IBPluginDependency</string>
+                                       <string>499.IBPluginDependency</string>
+                                       <string>5.IBPluginDependency</string>
+                                       <string>5.ImportedFromIB2</string>
+                                       <string>500.IBPluginDependency</string>
+                                       <string>501.IBPluginDependency</string>
+                                       <string>502.IBPluginDependency</string>
+                                       <string>503.IBPluginDependency</string>
+                                       <string>504.IBPluginDependency</string>
+                                       <string>505.IBPluginDependency</string>
+                                       <string>506.IBPluginDependency</string>
+                                       <string>507.IBPluginDependency</string>
+                                       <string>508.IBEditorWindowLastContentRect</string>
+                                       <string>508.IBPluginDependency</string>
+                                       <string>509.IBPluginDependency</string>
+                                       <string>510.IBPluginDependency</string>
+                                       <string>511.IBPluginDependency</string>
+                                       <string>512.IBPluginDependency</string>
+                                       <string>513.IBPluginDependency</string>
+                                       <string>514.IBPluginDependency</string>
+                                       <string>515.IBPluginDependency</string>
+                                       <string>516.IBPluginDependency</string>
+                                       <string>517.IBPluginDependency</string>
+                                       <string>56.IBPluginDependency</string>
+                                       <string>56.ImportedFromIB2</string>
+                                       <string>57.IBEditorWindowLastContentRect</string>
+                                       <string>57.IBPluginDependency</string>
+                                       <string>57.ImportedFromIB2</string>
+                                       <string>57.editorWindowContentRectSynchronizationRect</string>
+                                       <string>58.IBPluginDependency</string>
+                                       <string>58.ImportedFromIB2</string>
+                                       <string>72.IBPluginDependency</string>
+                                       <string>72.ImportedFromIB2</string>
+                                       <string>73.IBPluginDependency</string>
+                                       <string>73.ImportedFromIB2</string>
+                                       <string>74.IBPluginDependency</string>
+                                       <string>74.ImportedFromIB2</string>
+                                       <string>75.IBPluginDependency</string>
+                                       <string>75.ImportedFromIB2</string>
+                                       <string>77.IBPluginDependency</string>
+                                       <string>77.ImportedFromIB2</string>
+                                       <string>78.IBPluginDependency</string>
+                                       <string>78.ImportedFromIB2</string>
+                                       <string>79.IBPluginDependency</string>
+                                       <string>79.ImportedFromIB2</string>
+                                       <string>80.IBPluginDependency</string>
+                                       <string>80.ImportedFromIB2</string>
+                                       <string>81.IBEditorWindowLastContentRect</string>
+                                       <string>81.IBPluginDependency</string>
+                                       <string>81.ImportedFromIB2</string>
+                                       <string>81.editorWindowContentRectSynchronizationRect</string>
+                                       <string>82.IBPluginDependency</string>
+                                       <string>82.ImportedFromIB2</string>
+                                       <string>83.IBPluginDependency</string>
+                                       <string>83.ImportedFromIB2</string>
+                                       <string>92.IBPluginDependency</string>
+                                       <string>92.ImportedFromIB2</string>
+                               </object>
+                               <object class="NSMutableArray" key="dict.values">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{522, 812}, {146, 23}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{436, 809}, {64, 6}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{753, 187}, {275, 113}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{608, 612}, {275, 83}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{547, 180}, {254, 283}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{187, 434}, {243, 243}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{608, 612}, {167, 43}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{753, 217}, {238, 103}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{608, 612}, {241, 103}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{654, 239}, {194, 73}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{525, 802}, {197, 73}}</string>
+                                       <string>{{380, 836}, {512, 20}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{74, 862}</string>
+                                       <string>{{6, 978}, {478, 20}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{604, 269}, {231, 43}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{475, 832}, {234, 43}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{746, 287}, {220, 133}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{608, 612}, {215, 63}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{380, 496}, {480, 360}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{380, 496}, {480, 360}}</string>
+                                       <integer value="1"/>
+                                       <string>{{33, 99}, {480, 360}}</string>
+                                       <string>{3.40282e+38, 3.40282e+38}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{591, 420}, {83, 43}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{523, 2}, {178, 283}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{753, 197}, {170, 63}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{725, 289}, {246, 23}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{674, 260}, {204, 183}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{878, 180}, {164, 173}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{286, 129}, {275, 183}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{23, 794}, {245, 183}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{452, 109}, {196, 203}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{145, 474}, {199, 203}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                               </object>
+                       </object>
+                       <object class="NSMutableDictionary" key="unlocalizedProperties">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <reference key="dict.sortedKeys" ref="0"/>
+                               <object class="NSMutableArray" key="dict.values">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                               </object>
+                       </object>
+                       <nil key="activeLocalization"/>
+                       <object class="NSMutableDictionary" key="localizations">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <reference key="dict.sortedKeys" ref="0"/>
+                               <object class="NSMutableArray" key="dict.values">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                               </object>
+                       </object>
+                       <nil key="sourceID"/>
+                       <int key="maxID">532</int>
+               </object>
+               <object class="IBClassDescriber" key="IBDocument.Classes">
+                       <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">TestAppAppDelegate</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="NSMutableDictionary" key="outlets">
+                                               <string key="NS.key.0">window</string>
+                                               <string key="NS.object.0">NSWindow</string>
+                                       </object>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBProjectSource</string>
+                                               <string key="minorKey">TestAppAppDelegate.h</string>
+                                       </object>
+                               </object>
+                       </object>
+                       <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <string key="superclassName">NSResponder</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="822405504">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSApplication.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="850738725">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSApplicationScripting.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="624831158">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSColorPanel.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSHelpManager.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSPageLayout.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSUserInterfaceItemSearching.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSBrowser</string>
+                                       <string key="superclassName">NSControl</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSBrowser.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSControl</string>
+                                       <string key="superclassName">NSView</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="310914472">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSControl.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSDocument</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="NSMutableDictionary" key="actions">
+                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                               <object class="NSArray" key="dict.sortedKeys">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <string>printDocument:</string>
+                                                       <string>revertDocumentToSaved:</string>
+                                                       <string>runPageLayout:</string>
+                                                       <string>saveDocument:</string>
+                                                       <string>saveDocumentAs:</string>
+                                                       <string>saveDocumentTo:</string>
+                                               </object>
+                                               <object class="NSMutableArray" key="dict.values">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                               </object>
+                                       </object>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDocument.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSDocument</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDocumentScripting.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSDocumentController</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="NSMutableDictionary" key="actions">
+                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                               <object class="NSArray" key="dict.sortedKeys">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <string>clearRecentDocuments:</string>
+                                                       <string>newDocument:</string>
+                                                       <string>openDocument:</string>
+                                                       <string>saveAllDocuments:</string>
+                                               </object>
+                                               <object class="NSMutableArray" key="dict.values">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                               </object>
+                                       </object>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDocumentController.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSFontManager</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="946436764">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSFormatter</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSMatrix</string>
+                                       <string key="superclassName">NSControl</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSMatrix.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSMenu</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="1056362899">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSMenu.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSMenuItem</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="472958451">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSMovieView</string>
+                                       <string key="superclassName">NSView</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSMovieView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSAccessibility.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="822405504"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="850738725"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="624831158"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="310914472"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDictionaryController.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDragging.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="946436764"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSFontPanel.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSKeyValueBinding.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="1056362899"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSNibLoading.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSPasteboard.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSSavePanel.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="809545482">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSTableView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSToolbarItem.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="260078765">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSArchiver.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSClassDescription.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSError.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSObjectScripting.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSPortCoder.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSScriptClassDescription.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSScriptKeyValueCoding.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSScriptObjectSpecifiers.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSScriptWhoseTests.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSURLDownload.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSResponder</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSInterfaceStyle.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSResponder</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSResponder.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSTableView</string>
+                                       <string key="superclassName">NSControl</string>
+                                       <reference key="sourceIdentifier" ref="809545482"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSText</string>
+                                       <string key="superclassName">NSView</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSText.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSTextView</string>
+                                       <string key="superclassName">NSText</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSTextView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSView</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSClipView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSView</string>
+                                       <reference key="sourceIdentifier" ref="472958451"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSView</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSRulerView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSView</string>
+                                       <string key="superclassName">NSResponder</string>
+                                       <reference key="sourceIdentifier" ref="260078765"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSWindow</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDrawer.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSWindow</string>
+                                       <string key="superclassName">NSResponder</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSWindow.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSWindow</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string>
+                                       </object>
+                               </object>
+                       </object>
+               </object>
+               <int key="IBDocument.localizationMode">0</int>
+               <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
+                       <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
+                       <integer value="1060" key="NS.object.0"/>
+               </object>
+               <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+                       <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
+                       <integer value="3000" key="NS.object.0"/>
+               </object>
+               <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+               <string key="IBDocument.LastKnownRelativeProjectPath">../TestApp.xcodeproj</string>
+               <int key="IBDocument.defaultPropertyAccessControl">3</int>
+       </data>
+</archive>
diff --git a/gyp/test/ios/app-bundle/TestApp/English.lproj/Main_iPhone.storyboard b/gyp/test/ios/app-bundle/TestApp/English.lproj/Main_iPhone.storyboard
new file mode 100644 (file)
index 0000000..723bc85
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.0" toolsVersion="1906" systemVersion="11A511" targetRuntime="iOS.CocoaTouch" nextObjectID="6" propertyAccessControl="none" initialViewController="2">
+    <dependencies>
+        <development defaultVersion="4200" identifier="xcode"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="902"/>
+    </dependencies>
+    <scenes>
+        <scene sceneID="5">
+            <objects>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="4" sceneMemberID="firstResponder"/>
+                <viewController id="2" customClass="ViewController" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="3">
+                        <rect key="frame" x="0.0" y="20" width="320" height="460"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        <subviews/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+            </objects>
+        </scene>
+    </scenes>
+    <simulatedMetricsContainer key="defaultSimulatedMetrics">
+        <simulatedStatusBarMetrics key="statusBar"/>
+        <simulatedOrientationMetrics key="orientation"/>
+        <simulatedScreenMetrics key="destination"/>
+    </simulatedMetricsContainer>
+</document>
diff --git a/gyp/test/ios/app-bundle/TestApp/TestApp-Info.plist b/gyp/test/ios/app-bundle/TestApp/TestApp-Info.plist
new file mode 100644 (file)
index 0000000..8cb142e
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.google.${PRODUCT_NAME}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>ause</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+       <key>NSMainNibFile</key>
+       <string>MainMenu</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/gyp/test/ios/app-bundle/TestApp/check_no_signature.py b/gyp/test/ios/app-bundle/TestApp/check_no_signature.py
new file mode 100644 (file)
index 0000000..4f6e340
--- /dev/null
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+
+import os
+import subprocess
+import sys
+
+p = os.path.join(os.environ['BUILT_PRODUCTS_DIR'],os.environ['EXECUTABLE_PATH'])
+proc = subprocess.Popen(['codesign', '-v', p],
+                        stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+o = proc.communicate()[0].strip()
+if "code object is not signed at all" not in o:
+  sys.stderr.write('File should not already be signed.')
+  sys.exit(1)
diff --git a/gyp/test/ios/app-bundle/TestApp/main.m b/gyp/test/ios/app-bundle/TestApp/main.m
new file mode 100644 (file)
index 0000000..ec93e0e
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+int main(int argc, char *argv[])
+{
+  NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+  int retVal  = UIApplicationMain(argc, argv, nil, nil);
+  [pool release];
+  return retVal;
+}
diff --git a/gyp/test/ios/app-bundle/TestApp/only-compile-in-32-bits.m b/gyp/test/ios/app-bundle/TestApp/only-compile-in-32-bits.m
new file mode 100644 (file)
index 0000000..28bb117
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(__LP64__)
+# error 64-bit build
+#endif
diff --git a/gyp/test/ios/app-bundle/TestApp/only-compile-in-64-bits.m b/gyp/test/ios/app-bundle/TestApp/only-compile-in-64-bits.m
new file mode 100644 (file)
index 0000000..e6d2558
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if !defined(__LP64__)
+# error 32-bit build
+#endif
diff --git a/gyp/test/ios/app-bundle/test-archs.gyp b/gyp/test/ios/app-bundle/test-archs.gyp
new file mode 100644 (file)
index 0000000..b1558c9
--- /dev/null
@@ -0,0 +1,110 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+  ],
+  'target_defaults': {
+    'product_extension': 'bundle',
+    'mac_bundle_resources': [
+      'TestApp/English.lproj/InfoPlist.strings',
+      'TestApp/English.lproj/MainMenu.xib',
+    ],
+    'link_settings': {
+      'libraries': [
+        '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+        '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+      ],
+    },
+    'xcode_settings': {
+      'OTHER_CFLAGS': [
+        '-fobjc-abi-version=2',
+      ],
+      'CODE_SIGNING_REQUIRED': 'NO',
+      'SDKROOT': 'iphonesimulator',  # -isysroot
+      'TARGETED_DEVICE_FAMILY': '1,2',
+      'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+      'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+      'CONFIGURATION_BUILD_DIR':'build/Default',
+    },
+  },
+  'targets': [
+    {
+      'target_name': 'TestNoArchs',
+      'product_name': 'TestNoArchs',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'TestApp/main.m',
+        'TestApp/only-compile-in-32-bits.m',
+      ],
+      'xcode_settings': {
+        'VALID_ARCHS': [
+          'i386',
+          'x86_64',
+          'arm64',
+          'armv7',
+        ],
+      }
+    },
+    {
+      'target_name': 'TestArch32Bits',
+      'product_name': 'TestArch32Bits',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'TestApp/main.m',
+        'TestApp/only-compile-in-32-bits.m',
+      ],
+      'xcode_settings': {
+        'ARCHS': [
+          '$(ARCHS_STANDARD)',
+        ],
+        'VALID_ARCHS': [
+          'i386',
+          'armv7',
+        ],
+      },
+    },
+    {
+      'target_name': 'TestArch64Bits',
+      'product_name': 'TestArch64Bits',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'TestApp/main.m',
+        'TestApp/only-compile-in-64-bits.m',
+      ],
+      'xcode_settings': {
+        'ARCHS': [
+          '$(ARCHS_STANDARD_INCLUDING_64_BIT)',
+        ],
+        'VALID_ARCHS': [
+          'x86_64',
+          'arm64',
+        ],
+      },
+    },
+    {
+      'target_name': 'TestMultiArchs',
+      'product_name': 'TestMultiArchs',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'TestApp/main.m',
+      ],
+      'xcode_settings': {
+        'ARCHS': [
+          '$(ARCHS_STANDARD_INCLUDING_64_BIT)',
+        ],
+        'VALID_ARCHS': [
+          'x86_64',
+          'i386',
+          'arm64',
+          'armv7',
+        ],
+      }
+    },
+  ],
+}
diff --git a/gyp/test/ios/app-bundle/test-crosscompile.gyp b/gyp/test/ios/app-bundle/test-crosscompile.gyp
new file mode 100644 (file)
index 0000000..d904958
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+  ],
+  'targets': [
+    # This target will not be built, but is here so that ninja Xcode emulation
+    # understand this is a multi-platform (ios + mac) build.
+    {
+      'target_name': 'TestDummy',
+      'product_name': 'TestDummy',
+      'toolsets': ['target'],
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'tool_main.cc',
+      ],
+      'xcode_settings': {
+        'SDKROOT': 'iphonesimulator',  # -isysroot
+        'TARGETED_DEVICE_FAMILY': '1,2',
+        'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+      },
+    },
+    {
+      'target_name': 'TestHost',
+      'product_name': 'TestHost',
+      'toolsets': ['host'],
+      'type': 'executable',
+      'mac_bundle': 0,
+      'sources': [
+        'tool_main.cc',
+      ],
+      'xcode_settings': {
+        'SDKROOT': 'macosx',
+        'ARCHS': [
+          '$(ARCHS_STANDARD)',
+          'x86_64',
+        ],
+        'VALID_ARCHS': [
+          'x86_64',
+        ],
+      }
+    }
+  ],
+}
diff --git a/gyp/test/ios/app-bundle/test-device.gyp b/gyp/test/ios/app-bundle/test-device.gyp
new file mode 100644 (file)
index 0000000..28cdbb3
--- /dev/null
@@ -0,0 +1,79 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+  ],
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test App Gyp',
+      'type': 'executable',
+      'product_extension': 'bundle',
+      'mac_bundle': 1,
+      'sources': [
+        'TestApp/main.m',
+      ],
+      'mac_bundle_resources': [
+        'TestApp/English.lproj/InfoPlist.strings',
+        'TestApp/English.lproj/MainMenu.xib',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+          '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+        ],
+      },
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-fobjc-abi-version=2',
+        ],
+        'SDKROOT': 'iphonesimulator',  # -isysroot
+        'TARGETED_DEVICE_FAMILY': '1,2',
+        'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+        'IPHONEOS_DEPLOYMENT_TARGET': '4.2',
+        'CONFIGURATION_BUILD_DIR':'build/Default',
+      },
+    },
+    {
+      'target_name': 'sig_test',
+      'product_name': 'sig_test',
+      'type': 'executable',
+      'product_extension': 'bundle',
+      'mac_bundle': 1,
+      'sources': [
+        'TestApp/main.m',
+      ],
+      'mac_bundle_resources': [
+        'TestApp/English.lproj/InfoPlist.strings',
+        'TestApp/English.lproj/MainMenu.xib',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+          '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+        ],
+      },
+      'postbuilds': [
+        {
+          'postbuild_name': 'Verify no signature',
+          'action': [
+            'python',
+            'TestApp/check_no_signature.py'
+          ],
+        },
+      ],
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-fobjc-abi-version=2',
+        ],
+        'SDKROOT': 'iphonesimulator',  # -isysroot
+        'CODE_SIGN_IDENTITY[sdk=iphoneos*]': 'iPhone Developer',
+        'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+        'IPHONEOS_DEPLOYMENT_TARGET': '4.2',
+        'CONFIGURATION_BUILD_DIR':'buildsig/Default',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/ios/app-bundle/test.gyp b/gyp/test/ios/app-bundle/test.gyp
new file mode 100644 (file)
index 0000000..a8601e8
--- /dev/null
@@ -0,0 +1,44 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'conditions': [
+    ['"<(GENERATOR)"=="ninja"', {
+      'make_global_settings': [
+        ['CC', '/usr/bin/clang'],
+        ['CXX', '/usr/bin/clang++'],
+      ],
+    }],
+  ],
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test App Gyp',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'TestApp/main.m',
+      ],
+      'mac_bundle_resources': [
+        'TestApp/English.lproj/InfoPlist.strings',
+        'TestApp/English.lproj/MainMenu.xib',
+        'TestApp/English.lproj/Main_iPhone.storyboard',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+          '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+        ],
+      },
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-fobjc-abi-version=2',
+        ],
+        'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+        'SDKROOT': 'iphonesimulator',  # -isysroot
+        'IPHONEOS_DEPLOYMENT_TARGET': '5.0',
+        'CONFIGURATION_BUILD_DIR':'build/Default',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/ios/app-bundle/tool_main.cc b/gyp/test/ios/app-bundle/tool_main.cc
new file mode 100644 (file)
index 0000000..9dc3c94
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/ios/deployment-target/check-version-min.c b/gyp/test/ios/deployment-target/check-version-min.c
new file mode 100644 (file)
index 0000000..761c529
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (c) 2013 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <Availability.h>
+
+/* GYPTEST_MAC_VERSION_MIN: should be set to the corresponding value of
+ * xcode setting 'MACOSX_DEPLOYMENT_TARGET', otherwise both should be
+ * left undefined.
+ *
+ * GYPTEST_IOS_VERSION_MIN: should be set to the corresponding value of
+ * xcode setting 'IPHONEOS_DEPLOYMENT_TARGET', otherwise both should be
+ * left undefined.
+ */
+
+#if defined(GYPTEST_MAC_VERSION_MIN)
+# if GYPTEST_MAC_VERSION_MIN != __MAC_OS_X_VERSION_MIN_REQUIRED
+#  error __MAC_OS_X_VERSION_MIN_REQUIRED has wrong value
+# endif
+#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+# error __MAC_OS_X_VERSION_MIN_REQUIRED should be undefined
+#endif
+
+#if defined(GYPTEST_IOS_VERSION_MIN)
+# if GYPTEST_IOS_VERSION_MIN != __IPHONE_OS_VERSION_MIN_REQUIRED
+#  error __IPHONE_OS_VERSION_MIN_REQUIRED has wrong value
+# endif
+#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+# error __IPHONE_OS_VERSION_MIN_REQUIRED should be undefined
+#endif
+
+int main() { return 0; }
+
diff --git a/gyp/test/ios/deployment-target/deployment-target.gyp b/gyp/test/ios/deployment-target/deployment-target.gyp
new file mode 100644 (file)
index 0000000..e272276
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+    ['CXX', '/usr/bin/clang++'],
+  ],
+  'targets': [
+    {
+      'target_name': 'iphoneos-version-min-4.3',
+      'type': 'static_library',
+      'sources': [ 'check-version-min.c', ],
+      'defines': [ 'GYPTEST_IOS_VERSION_MIN=40300', ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'ARCHS': [ 'armv7' ],
+        'SDKROOT': 'iphoneos',
+        'IPHONEOS_DEPLOYMENT_TARGET': '4.3',
+      },
+    },
+    {
+      'target_name': 'iphoneos-version-min-5.0',
+      'type': 'static_library',
+      'sources': [ 'check-version-min.c', ],
+      'defines': [ 'GYPTEST_IOS_VERSION_MIN=50000', ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'ARCHS': [ 'armv7' ],
+        'SDKROOT': 'iphoneos',
+        'IPHONEOS_DEPLOYMENT_TARGET': '5.0',
+      },
+    },
+    {
+      'target_name': 'iphonesimulator-version-min-4.3',
+      'type': 'static_library',
+      'sources': [ 'check-version-min.c', ],
+      'defines': [ 'GYPTEST_IOS_VERSION_MIN=40300', ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'SDKROOT': 'iphonesimulator',
+        'IPHONEOS_DEPLOYMENT_TARGET': '4.3',
+      },
+    },
+    {
+      'target_name': 'iphonesimulator-version-min-5.0',
+      'type': 'static_library',
+      'sources': [ 'check-version-min.c', ],
+      'defines': [ 'GYPTEST_IOS_VERSION_MIN=50000', ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'SDKROOT': 'iphonesimulator',
+        'IPHONEOS_DEPLOYMENT_TARGET': '5.0',
+      },
+    },
+  ],
+}
+
diff --git a/gyp/test/ios/extension/ActionExtension/ActionViewController.h b/gyp/test/ios/extension/ActionExtension/ActionViewController.h
new file mode 100644 (file)
index 0000000..1c92509
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface ActionViewController : UIViewController
+
+@end
diff --git a/gyp/test/ios/extension/ActionExtension/ActionViewController.m b/gyp/test/ios/extension/ActionExtension/ActionViewController.m
new file mode 100644 (file)
index 0000000..d37bacd
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ActionViewController.h"
+#import <MobileCoreServices/MobileCoreServices.h>
+
+@interface ActionViewController ()
+
+@end
+
+@implementation ActionViewController
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+}
+
+- (void)didReceiveMemoryWarning {
+  [super didReceiveMemoryWarning];
+  // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)done {
+  // Return any edited content to the host app.
+  // This template doesn't do anything, so we just echo the passed in items.
+  [self.extensionContext
+      completeRequestReturningItems:self.extensionContext.inputItems
+      completionHandler:nil];
+}
+
+@end
diff --git a/gyp/test/ios/extension/ActionExtension/Info.plist b/gyp/test/ios/extension/ActionExtension/Info.plist
new file mode 100644 (file)
index 0000000..f89cd79
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleDisplayName</key>
+       <string>ActionExtension</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.google.gyptest.extension.ActionExtension</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>XPC!</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>NSExtension</key>
+       <dict>
+               <key>NSExtensionAttributes</key>
+               <dict>
+                       <key>NSExtensionActivationRule</key>
+                       <string>TRUEPREDICATE</string>
+                       <key>NSExtensionPointName</key>
+                       <string>com.apple.ui-services</string>
+                       <key>NSExtensionPointVersion</key>
+                       <string>1.0</string>
+               </dict>
+               <key>NSExtensionMainStoryboard</key>
+               <string>MainInterface</string>
+               <key>NSExtensionPointIdentifier</key>
+               <string>com.apple.ui-services</string>
+       </dict>
+</dict>
+</plist>
diff --git a/gyp/test/ios/extension/ActionExtension/MainInterface.storyboard b/gyp/test/ios/extension/ActionExtension/MainInterface.storyboard
new file mode 100644 (file)
index 0000000..5aa5818
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6148" systemVersion="14A229a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="ObA-dk-sSI">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6147"/>
+    </dependencies>
+    <scenes>
+        <!--Action View Controller - Image-->
+        <scene sceneID="7MM-of-jgj">
+            <objects>
+                <viewController title="Image" id="ObA-dk-sSI" customClass="ActionViewController" customModuleProvider="" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="qkL-Od-lgU"/>
+                        <viewControllerLayoutGuide type="bottom" id="n38-gi-rB5"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="zMn-AG-sqS">
+                        <rect key="frame" x="0.0" y="0.0" width="320" height="528"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="9ga-4F-77Z">
+                                <rect key="frame" x="0.0" y="64" width="320" height="464"/>
+                            </imageView>
+                            <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NOA-Dm-cuz">
+                                <rect key="frame" x="0.0" y="20" width="320" height="44"/>
+                                <items>
+                                    <navigationItem id="3HJ-uW-3hn">
+                                        <barButtonItem key="leftBarButtonItem" title="Done" style="done" id="WYi-yp-eM6">
+                                            <connections>
+                                                <action selector="done" destination="ObA-dk-sSI" id="Qdu-qn-U6V"/>
+                                            </connections>
+                                        </barButtonItem>
+                                    </navigationItem>
+                                </items>
+                            </navigationBar>
+                        </subviews>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="NOA-Dm-cuz" secondAttribute="trailing" id="A05-Pj-hrr"/>
+                            <constraint firstItem="9ga-4F-77Z" firstAttribute="top" secondItem="NOA-Dm-cuz" secondAttribute="bottom" id="Fps-3D-QQW"/>
+                            <constraint firstItem="NOA-Dm-cuz" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="HxO-8t-aoh"/>
+                            <constraint firstAttribute="trailing" secondItem="9ga-4F-77Z" secondAttribute="trailing" id="Ozw-Hg-0yh"/>
+                            <constraint firstItem="9ga-4F-77Z" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="XH5-ld-ONA"/>
+                            <constraint firstItem="n38-gi-rB5" firstAttribute="top" secondItem="9ga-4F-77Z" secondAttribute="bottom" id="eQg-nn-Zy4"/>
+                            <constraint firstItem="NOA-Dm-cuz" firstAttribute="top" secondItem="qkL-Od-lgU" secondAttribute="bottom" id="we0-1t-bgp"/>
+                        </constraints>
+                    </view>
+                    <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+                    <size key="freeformSize" width="320" height="528"/>
+                    <connections>
+                        <outlet property="imageView" destination="9ga-4F-77Z" id="5y6-5w-9QO"/>
+                        <outlet property="view" destination="zMn-AG-sqS" id="Qma-de-2ek"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="X47-rx-isc" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="252" y="-124"/>
+        </scene>
+    </scenes>
+    <simulatedMetricsContainer key="defaultSimulatedMetrics">
+        <simulatedStatusBarMetrics key="statusBar"/>
+        <simulatedOrientationMetrics key="orientation"/>
+        <simulatedScreenMetrics key="destination" type="retina4"/>
+    </simulatedMetricsContainer>
+</document>
diff --git a/gyp/test/ios/extension/ExtensionContainer/AppDelegate.h b/gyp/test/ios/extension/ExtensionContainer/AppDelegate.h
new file mode 100644 (file)
index 0000000..510e230
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
+
diff --git a/gyp/test/ios/extension/ExtensionContainer/AppDelegate.m b/gyp/test/ios/extension/ExtensionContainer/AppDelegate.m
new file mode 100644 (file)
index 0000000..1197bc1
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication*)application
+    didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
+  // Override point for customization after application launch.
+  return YES;
+}
+
+@end
diff --git a/gyp/test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard b/gyp/test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard
new file mode 100644 (file)
index 0000000..e8f3cfb
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6162" systemVersion="14A238h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6160"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+</document>
diff --git a/gyp/test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json b/gyp/test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644 (file)
index 0000000..f697f61
--- /dev/null
@@ -0,0 +1,53 @@
+{
+  "images" : [
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "60x60",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/gyp/test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json b/gyp/test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644 (file)
index 0000000..4458b40
--- /dev/null
@@ -0,0 +1,51 @@
+{
+  "images" : [
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "subtype" : "retina4",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/gyp/test/ios/extension/ExtensionContainer/Info.plist b/gyp/test/ios/extension/ExtensionContainer/Info.plist
new file mode 100644 (file)
index 0000000..31ccf4c
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>CFBundleDevelopmentRegion</key>
+    <string>en</string>
+    <key>CFBundleExecutable</key>
+    <string>ExtensionContainer</string>
+    <key>CFBundleIdentifier</key>
+    <string>com.google.gyptest.extension</string>
+    <key>CFBundleInfoDictionaryVersion</key>
+    <string>6.0</string>
+    <key>CFBundleName</key>
+    <string>${PRODUCT_NAME}</string>
+    <key>CFBundlePackageType</key>
+    <string>APPL</string>
+    <key>CFBundleShortVersionString</key>
+    <string>1.0</string>
+    <key>CFBundleSignature</key>
+    <string>????</string>
+    <key>CFBundleVersion</key>
+    <string>1</string>
+    <key>LSRequiresIPhoneOS</key>
+    <true/>
+    <key>UIMainStoryboardFile</key>
+    <string>Main</string>
+    <key>UIRequiredDeviceCapabilities</key>
+    <array>
+        <string>armv7</string>
+    </array>
+</dict>
+</plist>
diff --git a/gyp/test/ios/extension/ExtensionContainer/ViewController.h b/gyp/test/ios/extension/ExtensionContainer/ViewController.h
new file mode 100644 (file)
index 0000000..fad7754
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+
+@end
+
diff --git a/gyp/test/ios/extension/ExtensionContainer/ViewController.m b/gyp/test/ios/extension/ExtensionContainer/ViewController.m
new file mode 100644 (file)
index 0000000..3810fa9
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ViewController.h"
+
+@interface ViewController ()
+
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+  // Do any additional setup after loading the view, typically from a nib.
+}
+
+- (void)didReceiveMemoryWarning {
+  [super didReceiveMemoryWarning];
+  // Dispose of any resources that can be recreated.
+}
+
+@end
diff --git a/gyp/test/ios/extension/ExtensionContainer/main.m b/gyp/test/ios/extension/ExtensionContainer/main.m
new file mode 100644 (file)
index 0000000..47aecb5
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+  @autoreleasepool {
+    return UIApplicationMain(argc, argv, nil,
+        NSStringFromClass([AppDelegate class]));
+  }
+}
diff --git a/gyp/test/ios/extension/extension.gyp b/gyp/test/ios/extension/extension.gyp
new file mode 100644 (file)
index 0000000..6fa468c
--- /dev/null
@@ -0,0 +1,83 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+    ['CXX', '/usr/bin/clang++'],
+  ],
+  'targets': [
+    {
+      'target_name': 'ExtensionContainer',
+      'product_name': 'ExtensionContainer',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'mac_bundle_resources': [
+        'ExtensionContainer/Base.lproj/Main.storyboard',
+      ],
+      'sources': [
+        'ExtensionContainer/AppDelegate.h',
+        'ExtensionContainer/AppDelegate.m',
+        'ExtensionContainer/ViewController.h',
+        'ExtensionContainer/ViewController.m',
+        'ExtensionContainer/main.m',
+      ],
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/ExtensionContainer.app/PlugIns',
+          'files': [
+            '<(PRODUCT_DIR)/ActionExtension.appex',
+      ]}],
+      'dependencies': [
+        'ActionExtension'
+      ],
+
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+          '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+        ],
+      },
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-fobjc-abi-version=2',
+        ],
+        'INFOPLIST_FILE': 'ExtensionContainer/Info.plist',
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'ARCHS': [ 'armv7' ],
+        'SDKROOT': 'iphoneos',
+        'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+      },
+    },
+    {
+      'target_name': 'ActionExtension',
+      'product_name': 'ActionExtension',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'ios_app_extension': 1,
+      'sources': [
+        'ActionExtension/ActionViewController.h',
+        'ActionExtension/ActionViewController.m',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+          '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+          '$(SDKROOT)/System/Library/Frameworks/MobileCoreServices.framework',
+        ],
+      },
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-fobjc-abi-version=2',
+        ],
+        'INFOPLIST_FILE': 'ActionExtension/Info.plist',
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'ARCHS': [ 'armv7' ],
+        'SDKROOT': 'iphoneos',
+        'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+      },
+    },
+  ],
+}
+
diff --git a/gyp/test/ios/gyptest-app-ios.py b/gyp/test/ios/gyptest-app-ios.py
new file mode 100755 (executable)
index 0000000..37afbfe
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that ios app bundles are built correctly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['xcode', 'ninja'])
+
+  test.run_gyp('test.gyp', chdir='app-bundle')
+
+  test.build('test.gyp', test.ALL, chdir='app-bundle')
+
+  # Test that the extension is .bundle
+  test.built_file_must_exist('Test App Gyp.app/Test App Gyp',
+                             chdir='app-bundle')
+
+  # Info.plist
+  info_plist = test.built_file_path('Test App Gyp.app/Info.plist',
+                                    chdir='app-bundle')
+  # Resources
+  test.built_file_must_exist(
+      'Test App Gyp.app/English.lproj/InfoPlist.strings',
+      chdir='app-bundle')
+  test.built_file_must_exist(
+      'Test App Gyp.app/English.lproj/MainMenu.nib',
+      chdir='app-bundle')
+  test.built_file_must_exist(
+      'Test App Gyp.app/English.lproj/Main_iPhone.storyboardc',
+      chdir='app-bundle')
+
+  # Packaging
+  test.built_file_must_exist('Test App Gyp.app/PkgInfo',
+                             chdir='app-bundle')
+  test.built_file_must_match('Test App Gyp.app/PkgInfo', 'APPLause',
+                             chdir='app-bundle')
+
+  test.pass_test()
diff --git a/gyp/test/ios/gyptest-archs.py b/gyp/test/ios/gyptest-archs.py
new file mode 100644 (file)
index 0000000..38c5c61
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that device and simulator bundles are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import collections
+import sys
+
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+  test_cases = [
+    ('Default', 'TestArch32Bits', ['i386']),
+    ('Default-iphoneos', 'TestArch32Bits', ['armv7']),
+  ]
+
+  if TestMac.Xcode.Version() < '0510':
+    test_cases.extend([
+        ('Default', 'TestNoArchs', ['i386']),
+        ('Default-iphoneos', 'TestNoArchs', ['armv7'])])
+
+  if TestMac.Xcode.Version() >= '0500':
+    test_cases.extend([
+        ('Default', 'TestArch64Bits', ['x86_64']),
+        ('Default', 'TestMultiArchs', ['i386', 'x86_64']),
+        ('Default-iphoneos', 'TestArch64Bits', ['arm64']),
+        ('Default-iphoneos', 'TestMultiArchs', ['armv7', 'arm64'])])
+
+  test.run_gyp('test-archs.gyp', chdir='app-bundle')
+  for configuration, target, archs in test_cases:
+    is_device_build = configuration.endswith('-iphoneos')
+
+    kwds = collections.defaultdict(list)
+    if test.format == 'xcode':
+      if is_device_build:
+        configuration, sdk = configuration.split('-')
+        kwds['arguments'].extend(['-sdk', sdk])
+      if TestMac.Xcode.Version() < '0500':
+        kwds['arguments'].extend(['-arch', archs[0]])
+
+    test.set_configuration(configuration)
+    filename = '%s.bundle/%s' % (target, target)
+    test.build('test-archs.gyp', target, chdir='app-bundle', **kwds)
+    result_file = test.built_file_path(filename, chdir='app-bundle')
+
+    test.must_exist(result_file)
+    TestMac.CheckFileType(test, result_file, archs)
+
+  test.pass_test()
diff --git a/gyp/test/ios/gyptest-crosscompile.py b/gyp/test/ios/gyptest-crosscompile.py
new file mode 100644 (file)
index 0000000..a081683
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that tools are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import sys
+import os
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+  oldenv = os.environ.copy()
+  try:
+    os.environ['GYP_CROSSCOMPILE'] = '1'
+    test.run_gyp('test-crosscompile.gyp', chdir='app-bundle')
+  finally:
+    os.environ.clear()
+    os.environ.update(oldenv)
+
+  test.set_configuration('Default')
+  test.build('test-crosscompile.gyp', 'TestHost', chdir='app-bundle')
+  result_file = test.built_file_path('TestHost', chdir='app-bundle')
+  test.must_exist(result_file)
+  TestMac.CheckFileType(test, result_file, ['x86_64'])
+
+  test.pass_test()
diff --git a/gyp/test/ios/gyptest-deployment-target.py b/gyp/test/ios/gyptest-deployment-target.py
new file mode 100644 (file)
index 0000000..6c09d9d
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that IPHONEOS_DEPLOYMENT_TARGET works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode'])
+
+  test.run_gyp('deployment-target.gyp', chdir='deployment-target')
+
+  test.build('deployment-target.gyp', test.ALL, chdir='deployment-target')
+
+  test.pass_test()
+
diff --git a/gyp/test/ios/gyptest-extension.py b/gyp/test/ios/gyptest-extension.py
new file mode 100755 (executable)
index 0000000..103eb3f
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that ios app extensions are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import sys
+if sys.platform == 'darwin' and TestMac.Xcode.Version()>="0600":
+  test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+  test.run_gyp('extension.gyp', chdir='extension')
+
+  test.build('extension.gyp', 'ExtensionContainer', chdir='extension')
+
+  # Test that the extension is .appex
+  test.built_file_must_exist(
+      'ExtensionContainer.app/PlugIns/ActionExtension.appex',
+      chdir='extension')
+
+  test.pass_test()
+
diff --git a/gyp/test/ios/gyptest-per-config-settings.py b/gyp/test/ios/gyptest-per-config-settings.py
new file mode 100644 (file)
index 0000000..d15907e
--- /dev/null
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that device and simulator bundles are built correctly.
+"""
+
+import plistlib
+import TestGyp
+import os
+import struct
+import subprocess
+import sys
+import tempfile
+
+
+def CheckFileType(file, expected):
+  proc = subprocess.Popen(['lipo', '-info', file], stdout=subprocess.PIPE)
+  o = proc.communicate()[0].strip()
+  assert not proc.returncode
+  if not expected in o:
+    print 'File: Expected %s, got %s' % (expected, o)
+    test.fail_test()
+
+def HasCerts():
+  # Because the bots do not have certs, don't check them if there are no
+  # certs available.
+  proc = subprocess.Popen(['security','find-identity','-p', 'codesigning',
+                           '-v'], stdout=subprocess.PIPE)
+  return "0 valid identities found" not in proc.communicate()[0].strip()
+
+def CheckSignature(file):
+  proc = subprocess.Popen(['codesign', '-v', file], stdout=subprocess.PIPE)
+  o = proc.communicate()[0].strip()
+  assert not proc.returncode
+  if "code object is not signed at all" in o:
+    print 'File %s not properly signed.' % (file)
+    test.fail_test()
+
+def CheckEntitlements(file, expected_entitlements):
+  with tempfile.NamedTemporaryFile() as temp:
+    proc = subprocess.Popen(['codesign', '--display', '--entitlements',
+                             temp.name, file], stdout=subprocess.PIPE)
+    o = proc.communicate()[0].strip()
+    assert not proc.returncode
+    data = temp.read()
+  entitlements = ParseEntitlements(data)
+  if not entitlements:
+    print 'No valid entitlements found in %s.' % (file)
+    test.fail_test()
+  if entitlements != expected_entitlements:
+    print 'Unexpected entitlements found in %s.' % (file)
+    test.fail_test()
+
+def ParseEntitlements(data):
+  if len(data) < 8:
+    return None
+  magic, length = struct.unpack('>II', data[:8])
+  if magic != 0xfade7171 or length != len(data):
+    return None
+  return data[8:]
+
+def GetProductVersion():
+  args = ['xcodebuild','-version','-sdk','iphoneos','ProductVersion']
+  job = subprocess.Popen(args, stdout=subprocess.PIPE)
+  return job.communicate()[0].strip()
+
+def CheckPlistvalue(plist, key, expected):
+  if key not in plist:
+    print '%s not set in plist' % key
+    test.fail_test()
+    return
+  actual = plist[key]
+  if actual != expected:
+    print 'File: Expected %s, got %s for %s' % (expected, actual, key)
+    test.fail_test()
+
+def CheckPlistNotSet(plist, key):
+  if key in plist:
+    print '%s should not be set in plist' % key
+    test.fail_test()
+    return
+
+def ConvertBinaryPlistToXML(path):
+  proc = subprocess.call(['plutil', '-convert', 'xml1', path],
+                         stdout=subprocess.PIPE)
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+  test.run_gyp('test-device.gyp', chdir='app-bundle')
+
+  test_configs = ['Default-iphoneos', 'Default']
+  # TODO(justincohen): Disabling 'Default-iphoneos' for xcode until bots are
+  # configured with signing certs.
+  if test.format == 'xcode':
+    test_configs.remove('Default-iphoneos')
+
+  for configuration in test_configs:
+    test.set_configuration(configuration)
+    test.build('test-device.gyp', 'test_app', chdir='app-bundle')
+    result_file = test.built_file_path('Test App Gyp.bundle/Test App Gyp',
+                                       chdir='app-bundle')
+    test.must_exist(result_file)
+
+    info_plist = test.built_file_path('Test App Gyp.bundle/Info.plist',
+                                      chdir='app-bundle')
+
+    # plistlib doesn't support binary plists, but that's what Xcode creates.
+    if test.format == 'xcode':
+      ConvertBinaryPlistToXML(info_plist)
+    plist = plistlib.readPlist(info_plist)
+
+    CheckPlistvalue(plist, 'UIDeviceFamily', [1, 2])
+
+    if configuration == 'Default-iphoneos':
+      CheckFileType(result_file, 'armv7')
+      CheckPlistvalue(plist, 'DTPlatformVersion', GetProductVersion())
+      CheckPlistvalue(plist, 'CFBundleSupportedPlatforms', ['iPhoneOS'])
+      CheckPlistvalue(plist, 'DTPlatformName', 'iphoneos')
+    else:
+      CheckFileType(result_file, 'i386')
+      CheckPlistNotSet(plist, 'DTPlatformVersion')
+      CheckPlistvalue(plist, 'CFBundleSupportedPlatforms', ['iPhoneSimulator'])
+      CheckPlistvalue(plist, 'DTPlatformName', 'iphonesimulator')
+
+    if HasCerts() and configuration == 'Default-iphoneos':
+      test.build('test-device.gyp', 'sig_test', chdir='app-bundle')
+      result_file = test.built_file_path('sig_test.bundle/sig_test',
+                                         chdir='app-bundle')
+      CheckSignature(result_file)
+      info_plist = test.built_file_path('sig_test.bundle/Info.plist',
+                                        chdir='app-bundle')
+
+      plist = plistlib.readPlist(info_plist)
+      CheckPlistvalue(plist, 'UIDeviceFamily', [1])
+
+      entitlements_file = test.built_file_path('sig_test.xcent',
+                                               chdir='app-bundle')
+      if os.path.isfile(entitlements_file):
+        expected_entitlements = open(entitlements_file).read()
+        CheckEntitlements(result_file, expected_entitlements)
+
+  test.pass_test()
diff --git a/gyp/test/ios/gyptest-xcode-ninja.py b/gyp/test/ios/gyptest-xcode-ninja.py
new file mode 100644 (file)
index 0000000..609db8c
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that the xcode-ninja GYP_GENERATOR runs and builds correctly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['xcode'])
+
+  # Run ninja and xcode-ninja
+  test.formats = ['ninja', 'xcode-ninja']
+  test.run_gyp('test.gyp', chdir='app-bundle')
+
+  # If it builds the target, it works.
+  test.build('test.ninja.gyp', chdir='app-bundle')
+  test.pass_test()
diff --git a/gyp/test/lib/README.txt b/gyp/test/lib/README.txt
new file mode 100644 (file)
index 0000000..b3d7245
--- /dev/null
@@ -0,0 +1,17 @@
+Supporting modules for GYP testing.
+
+    TestCmd.py
+    TestCommon.py
+
+        Modules for generic testing of command-line utilities,
+        specifically including the ability to copy a test configuration
+        to temporary directories (with default cleanup on exit) as part
+        of running test scripts that invoke commands, compare actual
+        against expected output, etc.
+
+        Our copies of these come from the SCons project,
+        http://www.scons.org/.
+
+    TestGyp.py
+
+        Modules for GYP-specific tests, of course.
diff --git a/gyp/test/lib/TestCmd.py b/gyp/test/lib/TestCmd.py
new file mode 100644 (file)
index 0000000..7140361
--- /dev/null
@@ -0,0 +1,1597 @@
+"""
+TestCmd.py:  a testing framework for commands and scripts.
+
+The TestCmd module provides a framework for portable automated testing
+of executable commands and scripts (in any language, not just Python),
+especially commands and scripts that require file system interaction.
+
+In addition to running tests and evaluating conditions, the TestCmd
+module manages and cleans up one or more temporary workspace
+directories, and provides methods for creating files and directories in
+those workspace directories from in-line data, here-documents), allowing
+tests to be completely self-contained.
+
+A TestCmd environment object is created via the usual invocation:
+
+    import TestCmd
+    test = TestCmd.TestCmd()
+
+There are a bunch of keyword arguments available at instantiation:
+
+    test = TestCmd.TestCmd(description = 'string',
+                           program = 'program_or_script_to_test',
+                           interpreter = 'script_interpreter',
+                           workdir = 'prefix',
+                           subdir = 'subdir',
+                           verbose = Boolean,
+                           match = default_match_function,
+                           diff = default_diff_function,
+                           combine = Boolean)
+
+There are a bunch of methods that let you do different things:
+
+    test.verbose_set(1)
+
+    test.description_set('string')
+
+    test.program_set('program_or_script_to_test')
+
+    test.interpreter_set('script_interpreter')
+    test.interpreter_set(['script_interpreter', 'arg'])
+
+    test.workdir_set('prefix')
+    test.workdir_set('')
+
+    test.workpath('file')
+    test.workpath('subdir', 'file')
+
+    test.subdir('subdir', ...)
+
+    test.rmdir('subdir', ...)
+
+    test.write('file', "contents\n")
+    test.write(['subdir', 'file'], "contents\n")
+
+    test.read('file')
+    test.read(['subdir', 'file'])
+    test.read('file', mode)
+    test.read(['subdir', 'file'], mode)
+
+    test.writable('dir', 1)
+    test.writable('dir', None)
+
+    test.preserve(condition, ...)
+
+    test.cleanup(condition)
+
+    test.command_args(program = 'program_or_script_to_run',
+                      interpreter = 'script_interpreter',
+                      arguments = 'arguments to pass to program')
+
+    test.run(program = 'program_or_script_to_run',
+             interpreter = 'script_interpreter',
+             arguments = 'arguments to pass to program',
+             chdir = 'directory_to_chdir_to',
+             stdin = 'input to feed to the program\n')
+             universal_newlines = True)
+
+    p = test.start(program = 'program_or_script_to_run',
+                   interpreter = 'script_interpreter',
+                   arguments = 'arguments to pass to program',
+                   universal_newlines = None)
+
+    test.finish(self, p)
+
+    test.pass_test()
+    test.pass_test(condition)
+    test.pass_test(condition, function)
+
+    test.fail_test()
+    test.fail_test(condition)
+    test.fail_test(condition, function)
+    test.fail_test(condition, function, skip)
+
+    test.no_result()
+    test.no_result(condition)
+    test.no_result(condition, function)
+    test.no_result(condition, function, skip)
+
+    test.stdout()
+    test.stdout(run)
+
+    test.stderr()
+    test.stderr(run)
+
+    test.symlink(target, link)
+
+    test.banner(string)
+    test.banner(string, width)
+
+    test.diff(actual, expected)
+
+    test.match(actual, expected)
+
+    test.match_exact("actual 1\nactual 2\n", "expected 1\nexpected 2\n")
+    test.match_exact(["actual 1\n", "actual 2\n"],
+                     ["expected 1\n", "expected 2\n"])
+
+    test.match_re("actual 1\nactual 2\n", regex_string)
+    test.match_re(["actual 1\n", "actual 2\n"], list_of_regexes)
+
+    test.match_re_dotall("actual 1\nactual 2\n", regex_string)
+    test.match_re_dotall(["actual 1\n", "actual 2\n"], list_of_regexes)
+
+    test.tempdir()
+    test.tempdir('temporary-directory')
+
+    test.sleep()
+    test.sleep(seconds)
+
+    test.where_is('foo')
+    test.where_is('foo', 'PATH1:PATH2')
+    test.where_is('foo', 'PATH1;PATH2', '.suffix3;.suffix4')
+
+    test.unlink('file')
+    test.unlink('subdir', 'file')
+
+The TestCmd module provides pass_test(), fail_test(), and no_result()
+unbound functions that report test results for use with the Aegis change
+management system.  These methods terminate the test immediately,
+reporting PASSED, FAILED, or NO RESULT respectively, and exiting with
+status 0 (success), 1 or 2 respectively.  This allows for a distinction
+between an actual failed test and a test that could not be properly
+evaluated because of an external condition (such as a full file system
+or incorrect permissions).
+
+    import TestCmd
+
+    TestCmd.pass_test()
+    TestCmd.pass_test(condition)
+    TestCmd.pass_test(condition, function)
+
+    TestCmd.fail_test()
+    TestCmd.fail_test(condition)
+    TestCmd.fail_test(condition, function)
+    TestCmd.fail_test(condition, function, skip)
+
+    TestCmd.no_result()
+    TestCmd.no_result(condition)
+    TestCmd.no_result(condition, function)
+    TestCmd.no_result(condition, function, skip)
+
+The TestCmd module also provides unbound functions that handle matching
+in the same way as the match_*() methods described above.
+
+    import TestCmd
+
+    test = TestCmd.TestCmd(match = TestCmd.match_exact)
+
+    test = TestCmd.TestCmd(match = TestCmd.match_re)
+
+    test = TestCmd.TestCmd(match = TestCmd.match_re_dotall)
+
+The TestCmd module provides unbound functions that can be used for the
+"diff" argument to TestCmd.TestCmd instantiation:
+
+    import TestCmd
+
+    test = TestCmd.TestCmd(match = TestCmd.match_re,
+                           diff = TestCmd.diff_re)
+
+    test = TestCmd.TestCmd(diff = TestCmd.simple_diff)
+
+The "diff" argument can also be used with standard difflib functions:
+
+    import difflib
+
+    test = TestCmd.TestCmd(diff = difflib.context_diff)
+
+    test = TestCmd.TestCmd(diff = difflib.unified_diff)
+
+Lastly, the where_is() method also exists in an unbound function
+version.
+
+    import TestCmd
+
+    TestCmd.where_is('foo')
+    TestCmd.where_is('foo', 'PATH1:PATH2')
+    TestCmd.where_is('foo', 'PATH1;PATH2', '.suffix3;.suffix4')
+"""
+
+# Copyright 2000-2010 Steven Knight
+# This module is free software, and you may redistribute it and/or modify
+# it under the same terms as Python itself, so long as this copyright message
+# and disclaimer are retained in their original form.
+#
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
+# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+__author__ = "Steven Knight <knight at baldmt dot com>"
+__revision__ = "TestCmd.py 0.37.D001 2010/01/11 16:55:50 knight"
+__version__ = "0.37"
+
+import errno
+import os
+import os.path
+import re
+import shutil
+import stat
+import string
+import sys
+import tempfile
+import time
+import traceback
+import types
+import UserList
+
+__all__ = [
+    'diff_re',
+    'fail_test',
+    'no_result',
+    'pass_test',
+    'match_exact',
+    'match_re',
+    'match_re_dotall',
+    'python_executable',
+    'TestCmd'
+]
+
+try:
+    import difflib
+except ImportError:
+    __all__.append('simple_diff')
+
+def is_List(e):
+    return type(e) is types.ListType \
+        or isinstance(e, UserList.UserList)
+
+try:
+    from UserString import UserString
+except ImportError:
+    class UserString:
+        pass
+
+if hasattr(types, 'UnicodeType'):
+    def is_String(e):
+        return type(e) is types.StringType \
+            or type(e) is types.UnicodeType \
+            or isinstance(e, UserString)
+else:
+    def is_String(e):
+        return type(e) is types.StringType or isinstance(e, UserString)
+
+tempfile.template = 'testcmd.'
+if os.name in ('posix', 'nt'):
+    tempfile.template = 'testcmd.' + str(os.getpid()) + '.'
+else:
+    tempfile.template = 'testcmd.'
+
+re_space = re.compile('\s')
+
+_Cleanup = []
+
+_chain_to_exitfunc = None
+
+def _clean():
+    global _Cleanup
+    cleanlist = filter(None, _Cleanup)
+    del _Cleanup[:]
+    cleanlist.reverse()
+    for test in cleanlist:
+        test.cleanup()
+    if _chain_to_exitfunc:
+        _chain_to_exitfunc()
+
+try:
+    import atexit
+except ImportError:
+    # TODO(1.5): atexit requires python 2.0, so chain sys.exitfunc
+    try:
+        _chain_to_exitfunc = sys.exitfunc
+    except AttributeError:
+        pass
+    sys.exitfunc = _clean
+else:
+    atexit.register(_clean)
+
+try:
+    zip
+except NameError:
+    def zip(*lists):
+        result = []
+        for i in xrange(min(map(len, lists))):
+            result.append(tuple(map(lambda l, i=i: l[i], lists)))
+        return result
+
+class Collector:
+    def __init__(self, top):
+        self.entries = [top]
+    def __call__(self, arg, dirname, names):
+        pathjoin = lambda n, d=dirname: os.path.join(d, n)
+        self.entries.extend(map(pathjoin, names))
+
+def _caller(tblist, skip):
+    string = ""
+    arr = []
+    for file, line, name, text in tblist:
+        if file[-10:] == "TestCmd.py":
+                break
+        arr = [(file, line, name, text)] + arr
+    atfrom = "at"
+    for file, line, name, text in arr[skip:]:
+        if name in ("?", "<module>"):
+            name = ""
+        else:
+            name = " (" + name + ")"
+        string = string + ("%s line %d of %s%s\n" % (atfrom, line, file, name))
+        atfrom = "\tfrom"
+    return string
+
+def fail_test(self = None, condition = 1, function = None, skip = 0):
+    """Cause the test to fail.
+
+    By default, the fail_test() method reports that the test FAILED
+    and exits with a status of 1.  If a condition argument is supplied,
+    the test fails only if the condition is true.
+    """
+    if not condition:
+        return
+    if not function is None:
+        function()
+    of = ""
+    desc = ""
+    sep = " "
+    if not self is None:
+        if self.program:
+            of = " of " + self.program
+            sep = "\n\t"
+        if self.description:
+            desc = " [" + self.description + "]"
+            sep = "\n\t"
+
+    at = _caller(traceback.extract_stack(), skip)
+    sys.stderr.write("FAILED test" + of + desc + sep + at)
+
+    sys.exit(1)
+
+def no_result(self = None, condition = 1, function = None, skip = 0):
+    """Causes a test to exit with no valid result.
+
+    By default, the no_result() method reports NO RESULT for the test
+    and exits with a status of 2.  If a condition argument is supplied,
+    the test fails only if the condition is true.
+    """
+    if not condition:
+        return
+    if not function is None:
+        function()
+    of = ""
+    desc = ""
+    sep = " "
+    if not self is None:
+        if self.program:
+            of = " of " + self.program
+            sep = "\n\t"
+        if self.description:
+            desc = " [" + self.description + "]"
+            sep = "\n\t"
+
+    if os.environ.get('TESTCMD_DEBUG_SKIPS'):
+        at = _caller(traceback.extract_stack(), skip)
+        sys.stderr.write("NO RESULT for test" + of + desc + sep + at)
+    else:
+        sys.stderr.write("NO RESULT\n")
+
+    sys.exit(2)
+
+def pass_test(self = None, condition = 1, function = None):
+    """Causes a test to pass.
+
+    By default, the pass_test() method reports PASSED for the test
+    and exits with a status of 0.  If a condition argument is supplied,
+    the test passes only if the condition is true.
+    """
+    if not condition:
+        return
+    if not function is None:
+        function()
+    sys.stderr.write("PASSED\n")
+    sys.exit(0)
+
+def match_exact(lines = None, matches = None):
+    """
+    """
+    if not is_List(lines):
+        lines = string.split(lines, "\n")
+    if not is_List(matches):
+        matches = string.split(matches, "\n")
+    if len(lines) != len(matches):
+        return
+    for i in range(len(lines)):
+        if lines[i] != matches[i]:
+            return
+    return 1
+
+def match_re(lines = None, res = None):
+    """
+    """
+    if not is_List(lines):
+        lines = string.split(lines, "\n")
+    if not is_List(res):
+        res = string.split(res, "\n")
+    if len(lines) != len(res):
+        return
+    for i in range(len(lines)):
+        s = "^" + res[i] + "$"
+        try:
+            expr = re.compile(s)
+        except re.error, e:
+            msg = "Regular expression error in %s: %s"
+            raise re.error, msg % (repr(s), e[0])
+        if not expr.search(lines[i]):
+            return
+    return 1
+
+def match_re_dotall(lines = None, res = None):
+    """
+    """
+    if not type(lines) is type(""):
+        lines = string.join(lines, "\n")
+    if not type(res) is type(""):
+        res = string.join(res, "\n")
+    s = "^" + res + "$"
+    try:
+        expr = re.compile(s, re.DOTALL)
+    except re.error, e:
+        msg = "Regular expression error in %s: %s"
+        raise re.error, msg % (repr(s), e[0])
+    if expr.match(lines):
+        return 1
+
+try:
+    import difflib
+except ImportError:
+    pass
+else:
+    def simple_diff(a, b, fromfile='', tofile='',
+                    fromfiledate='', tofiledate='', n=3, lineterm='\n'):
+        """
+        A function with the same calling signature as difflib.context_diff
+        (diff -c) and difflib.unified_diff (diff -u) but which prints
+        output like the simple, unadorned 'diff" command.
+        """
+        sm = difflib.SequenceMatcher(None, a, b)
+        def comma(x1, x2):
+            return x1+1 == x2 and str(x2) or '%s,%s' % (x1+1, x2)
+        result = []
+        for op, a1, a2, b1, b2 in sm.get_opcodes():
+            if op == 'delete':
+                result.append("%sd%d" % (comma(a1, a2), b1))
+                result.extend(map(lambda l: '< ' + l, a[a1:a2]))
+            elif op == 'insert':
+                result.append("%da%s" % (a1, comma(b1, b2)))
+                result.extend(map(lambda l: '> ' + l, b[b1:b2]))
+            elif op == 'replace':
+                result.append("%sc%s" % (comma(a1, a2), comma(b1, b2)))
+                result.extend(map(lambda l: '< ' + l, a[a1:a2]))
+                result.append('---')
+                result.extend(map(lambda l: '> ' + l, b[b1:b2]))
+        return result
+
+def diff_re(a, b, fromfile='', tofile='',
+                fromfiledate='', tofiledate='', n=3, lineterm='\n'):
+    """
+    A simple "diff" of two sets of lines when the expected lines
+    are regular expressions.  This is a really dumb thing that
+    just compares each line in turn, so it doesn't look for
+    chunks of matching lines and the like--but at least it lets
+    you know exactly which line first didn't compare correctl...
+    """
+    result = []
+    diff = len(a) - len(b)
+    if diff < 0:
+        a = a + ['']*(-diff)
+    elif diff > 0:
+        b = b + ['']*diff
+    i = 0
+    for aline, bline in zip(a, b):
+        s = "^" + aline + "$"
+        try:
+            expr = re.compile(s)
+        except re.error, e:
+            msg = "Regular expression error in %s: %s"
+            raise re.error, msg % (repr(s), e[0])
+        if not expr.search(bline):
+            result.append("%sc%s" % (i+1, i+1))
+            result.append('< ' + repr(a[i]))
+            result.append('---')
+            result.append('> ' + repr(b[i]))
+        i = i+1
+    return result
+
+if os.name == 'java':
+
+    python_executable = os.path.join(sys.prefix, 'jython')
+
+else:
+
+    python_executable = sys.executable
+
+if sys.platform == 'win32':
+
+    default_sleep_seconds = 2
+
+    def where_is(file, path=None, pathext=None):
+        if path is None:
+            path = os.environ['PATH']
+        if is_String(path):
+            path = string.split(path, os.pathsep)
+        if pathext is None:
+            pathext = os.environ['PATHEXT']
+        if is_String(pathext):
+            pathext = string.split(pathext, os.pathsep)
+        for ext in pathext:
+            if string.lower(ext) == string.lower(file[-len(ext):]):
+                pathext = ['']
+                break
+        for dir in path:
+            f = os.path.join(dir, file)
+            for ext in pathext:
+                fext = f + ext
+                if os.path.isfile(fext):
+                    return fext
+        return None
+
+else:
+
+    def where_is(file, path=None, pathext=None):
+        if path is None:
+            path = os.environ['PATH']
+        if is_String(path):
+            path = string.split(path, os.pathsep)
+        for dir in path:
+            f = os.path.join(dir, file)
+            if os.path.isfile(f):
+                try:
+                    st = os.stat(f)
+                except OSError:
+                    continue
+                if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
+                    return f
+        return None
+
+    default_sleep_seconds = 1
+
+
+
+try:
+    import subprocess
+except ImportError:
+    # The subprocess module doesn't exist in this version of Python,
+    # so we're going to cobble up something that looks just enough
+    # like its API for our purposes below.
+    import new
+
+    subprocess = new.module('subprocess')
+
+    subprocess.PIPE = 'PIPE'
+    subprocess.STDOUT = 'STDOUT'
+    subprocess.mswindows = (sys.platform == 'win32')
+
+    try:
+        import popen2
+        popen2.Popen3
+    except AttributeError:
+        class Popen3:
+            universal_newlines = 1
+            def __init__(self, command, **kw):
+                if sys.platform == 'win32' and command[0] == '"':
+                    command = '"' + command + '"'
+                (stdin, stdout, stderr) = os.popen3(' ' + command)
+                self.stdin = stdin
+                self.stdout = stdout
+                self.stderr = stderr
+            def close_output(self):
+                self.stdout.close()
+                self.resultcode = self.stderr.close()
+            def wait(self):
+                resultcode = self.resultcode
+                if os.WIFEXITED(resultcode):
+                    return os.WEXITSTATUS(resultcode)
+                elif os.WIFSIGNALED(resultcode):
+                    return os.WTERMSIG(resultcode)
+                else:
+                    return None
+
+    else:
+        try:
+            popen2.Popen4
+        except AttributeError:
+            # A cribbed Popen4 class, with some retrofitted code from
+            # the Python 1.5 Popen3 class methods to do certain things
+            # by hand.
+            class Popen4(popen2.Popen3):
+                childerr = None
+
+                def __init__(self, cmd, bufsize=-1):
+                    p2cread, p2cwrite = os.pipe()
+                    c2pread, c2pwrite = os.pipe()
+                    self.pid = os.fork()
+                    if self.pid == 0:
+                        # Child
+                        os.dup2(p2cread, 0)
+                        os.dup2(c2pwrite, 1)
+                        os.dup2(c2pwrite, 2)
+                        for i in range(3, popen2.MAXFD):
+                            try:
+                                os.close(i)
+                            except: pass
+                        try:
+                            os.execvp(cmd[0], cmd)
+                        finally:
+                            os._exit(1)
+                        # Shouldn't come here, I guess
+                        os._exit(1)
+                    os.close(p2cread)
+                    self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
+                    os.close(c2pwrite)
+                    self.fromchild = os.fdopen(c2pread, 'r', bufsize)
+                    popen2._active.append(self)
+
+            popen2.Popen4 = Popen4
+
+        class Popen3(popen2.Popen3, popen2.Popen4):
+            universal_newlines = 1
+            def __init__(self, command, **kw):
+                if kw.get('stderr') == 'STDOUT':
+                    apply(popen2.Popen4.__init__, (self, command, 1))
+                else:
+                    apply(popen2.Popen3.__init__, (self, command, 1))
+                self.stdin = self.tochild
+                self.stdout = self.fromchild
+                self.stderr = self.childerr
+            def wait(self, *args, **kw):
+                resultcode = apply(popen2.Popen3.wait, (self,)+args, kw)
+                if os.WIFEXITED(resultcode):
+                    return os.WEXITSTATUS(resultcode)
+                elif os.WIFSIGNALED(resultcode):
+                    return os.WTERMSIG(resultcode)
+                else:
+                    return None
+
+    subprocess.Popen = Popen3
+
+
+
+# From Josiah Carlson,
+# ASPN : Python Cookbook : Module to allow Asynchronous subprocess use on Windows and Posix platforms
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554
+
+PIPE = subprocess.PIPE
+
+if subprocess.mswindows:
+    from win32file import ReadFile, WriteFile
+    from win32pipe import PeekNamedPipe
+    import msvcrt
+else:
+    import select
+    import fcntl
+
+    try:                    fcntl.F_GETFL
+    except AttributeError:  fcntl.F_GETFL = 3
+
+    try:                    fcntl.F_SETFL
+    except AttributeError:  fcntl.F_SETFL = 4
+
+class Popen(subprocess.Popen):
+    def recv(self, maxsize=None):
+        return self._recv('stdout', maxsize)
+
+    def recv_err(self, maxsize=None):
+        return self._recv('stderr', maxsize)
+
+    def send_recv(self, input='', maxsize=None):
+        return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
+
+    def get_conn_maxsize(self, which, maxsize):
+        if maxsize is None:
+            maxsize = 1024
+        elif maxsize < 1:
+            maxsize = 1
+        return getattr(self, which), maxsize
+
+    def _close(self, which):
+        getattr(self, which).close()
+        setattr(self, which, None)
+
+    if subprocess.mswindows:
+        def send(self, input):
+            if not self.stdin:
+                return None
+
+            try:
+                x = msvcrt.get_osfhandle(self.stdin.fileno())
+                (errCode, written) = WriteFile(x, input)
+            except ValueError:
+                return self._close('stdin')
+            except (subprocess.pywintypes.error, Exception), why:
+                if why[0] in (109, errno.ESHUTDOWN):
+                    return self._close('stdin')
+                raise
+
+            return written
+
+        def _recv(self, which, maxsize):
+            conn, maxsize = self.get_conn_maxsize(which, maxsize)
+            if conn is None:
+                return None
+
+            try:
+                x = msvcrt.get_osfhandle(conn.fileno())
+                (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
+                if maxsize < nAvail:
+                    nAvail = maxsize
+                if nAvail > 0:
+                    (errCode, read) = ReadFile(x, nAvail, None)
+            except ValueError:
+                return self._close(which)
+            except (subprocess.pywintypes.error, Exception), why:
+                if why[0] in (109, errno.ESHUTDOWN):
+                    return self._close(which)
+                raise
+
+            #if self.universal_newlines:
+            #    read = self._translate_newlines(read)
+            return read
+
+    else:
+        def send(self, input):
+            if not self.stdin:
+                return None
+
+            if not select.select([], [self.stdin], [], 0)[1]:
+                return 0
+
+            try:
+                written = os.write(self.stdin.fileno(), input)
+            except OSError, why:
+                if why[0] == errno.EPIPE: #broken pipe
+                    return self._close('stdin')
+                raise
+
+            return written
+
+        def _recv(self, which, maxsize):
+            conn, maxsize = self.get_conn_maxsize(which, maxsize)
+            if conn is None:
+                return None
+
+            try:
+                flags = fcntl.fcntl(conn, fcntl.F_GETFL)
+            except TypeError:
+                flags = None
+            else:
+                if not conn.closed:
+                    fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
+
+            try:
+                if not select.select([conn], [], [], 0)[0]:
+                    return ''
+
+                r = conn.read(maxsize)
+                if not r:
+                    return self._close(which)
+
+                #if self.universal_newlines:
+                #    r = self._translate_newlines(r)
+                return r
+            finally:
+                if not conn.closed and not flags is None:
+                    fcntl.fcntl(conn, fcntl.F_SETFL, flags)
+
+disconnect_message = "Other end disconnected!"
+
+def recv_some(p, t=.1, e=1, tr=5, stderr=0):
+    if tr < 1:
+        tr = 1
+    x = time.time()+t
+    y = []
+    r = ''
+    pr = p.recv
+    if stderr:
+        pr = p.recv_err
+    while time.time() < x or r:
+        r = pr()
+        if r is None:
+            if e:
+                raise Exception(disconnect_message)
+            else:
+                break
+        elif r:
+            y.append(r)
+        else:
+            time.sleep(max((x-time.time())/tr, 0))
+    return ''.join(y)
+
+# TODO(3.0:  rewrite to use memoryview()
+def send_all(p, data):
+    while len(data):
+        sent = p.send(data)
+        if sent is None:
+            raise Exception(disconnect_message)
+        data = buffer(data, sent)
+
+
+
+try:
+    object
+except NameError:
+    class object:
+        pass
+
+
+
+class TestCmd(object):
+    """Class TestCmd
+    """
+
+    def __init__(self, description = None,
+                       program = None,
+                       interpreter = None,
+                       workdir = None,
+                       subdir = None,
+                       verbose = None,
+                       match = None,
+                       diff = None,
+                       combine = 0,
+                       universal_newlines = 1):
+        self._cwd = os.getcwd()
+        self.description_set(description)
+        self.program_set(program)
+        self.interpreter_set(interpreter)
+        if verbose is None:
+            try:
+                verbose = max( 0, int(os.environ.get('TESTCMD_VERBOSE', 0)) )
+            except ValueError:
+                verbose = 0
+        self.verbose_set(verbose)
+        self.combine = combine
+        self.universal_newlines = universal_newlines
+        if match is not None:
+            self.match_function = match
+        else:
+            self.match_function = match_re
+        if diff is not None:
+            self.diff_function = diff
+        else:
+            try:
+                difflib
+            except NameError:
+                pass
+            else:
+                self.diff_function = simple_diff
+                #self.diff_function = difflib.context_diff
+                #self.diff_function = difflib.unified_diff
+        self._dirlist = []
+        self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0}
+        if os.environ.has_key('PRESERVE') and not os.environ['PRESERVE'] is '':
+            self._preserve['pass_test'] = os.environ['PRESERVE']
+            self._preserve['fail_test'] = os.environ['PRESERVE']
+            self._preserve['no_result'] = os.environ['PRESERVE']
+        else:
+            try:
+                self._preserve['pass_test'] = os.environ['PRESERVE_PASS']
+            except KeyError:
+                pass
+            try:
+                self._preserve['fail_test'] = os.environ['PRESERVE_FAIL']
+            except KeyError:
+                pass
+            try:
+                self._preserve['no_result'] = os.environ['PRESERVE_NO_RESULT']
+            except KeyError:
+                pass
+        self._stdout = []
+        self._stderr = []
+        self.status = None
+        self.condition = 'no_result'
+        self.workdir_set(workdir)
+        self.subdir(subdir)
+
+    def __del__(self):
+        self.cleanup()
+
+    def __repr__(self):
+        return "%x" % id(self)
+
+    banner_char = '='
+    banner_width = 80
+
+    def banner(self, s, width=None):
+        if width is None:
+            width = self.banner_width
+        return s + self.banner_char * (width - len(s))
+
+    if os.name == 'posix':
+
+        def escape(self, arg):
+            "escape shell special characters"
+            slash = '\\'
+            special = '"$'
+
+            arg = string.replace(arg, slash, slash+slash)
+            for c in special:
+                arg = string.replace(arg, c, slash+c)
+
+            if re_space.search(arg):
+                arg = '"' + arg + '"'
+            return arg
+
+    else:
+
+        # Windows does not allow special characters in file names
+        # anyway, so no need for an escape function, we will just quote
+        # the arg.
+        def escape(self, arg):
+            if re_space.search(arg):
+                arg = '"' + arg + '"'
+            return arg
+
+    def canonicalize(self, path):
+        if is_List(path):
+            path = apply(os.path.join, tuple(path))
+        if not os.path.isabs(path):
+            path = os.path.join(self.workdir, path)
+        return path
+
+    def chmod(self, path, mode):
+        """Changes permissions on the specified file or directory
+        path name."""
+        path = self.canonicalize(path)
+        os.chmod(path, mode)
+
+    def cleanup(self, condition = None):
+        """Removes any temporary working directories for the specified
+        TestCmd environment.  If the environment variable PRESERVE was
+        set when the TestCmd environment was created, temporary working
+        directories are not removed.  If any of the environment variables
+        PRESERVE_PASS, PRESERVE_FAIL, or PRESERVE_NO_RESULT were set
+        when the TestCmd environment was created, then temporary working
+        directories are not removed if the test passed, failed, or had
+        no result, respectively.  Temporary working directories are also
+        preserved for conditions specified via the preserve method.
+
+        Typically, this method is not called directly, but is used when
+        the script exits to clean up temporary working directories as
+        appropriate for the exit status.
+        """
+        if not self._dirlist:
+            return
+        os.chdir(self._cwd)
+        self.workdir = None
+        if condition is None:
+            condition = self.condition
+        if self._preserve[condition]:
+            for dir in self._dirlist:
+                print "Preserved directory", dir
+        else:
+            list = self._dirlist[:]
+            list.reverse()
+            for dir in list:
+                self.writable(dir, 1)
+                shutil.rmtree(dir, ignore_errors = 1)
+            self._dirlist = []
+
+        try:
+            global _Cleanup
+            _Cleanup.remove(self)
+        except (AttributeError, ValueError):
+            pass
+
+    def command_args(self, program = None,
+                           interpreter = None,
+                           arguments = None):
+        if program:
+            if type(program) == type('') and not os.path.isabs(program):
+                program = os.path.join(self._cwd, program)
+        else:
+            program = self.program
+            if not interpreter:
+                interpreter = self.interpreter
+        if not type(program) in [type([]), type(())]:
+            program = [program]
+        cmd = list(program)
+        if interpreter:
+            if not type(interpreter) in [type([]), type(())]:
+                interpreter = [interpreter]
+            cmd = list(interpreter) + cmd
+        if arguments:
+            if type(arguments) == type(''):
+                arguments = string.split(arguments)
+            cmd.extend(arguments)
+        return cmd
+
+    def description_set(self, description):
+        """Set the description of the functionality being tested.
+        """
+        self.description = description
+
+    try:
+        difflib
+    except NameError:
+        def diff(self, a, b, name, *args, **kw):
+            print self.banner('Expected %s' % name)
+            print a
+            print self.banner('Actual %s' % name)
+            print b
+    else:
+        def diff(self, a, b, name, *args, **kw):
+            print self.banner(name)
+            args = (a.splitlines(), b.splitlines()) + args
+            lines = apply(self.diff_function, args, kw)
+            for l in lines:
+                print l
+
+    def fail_test(self, condition = 1, function = None, skip = 0):
+        """Cause the test to fail.
+        """
+        if not condition:
+            return
+        self.condition = 'fail_test'
+        fail_test(self = self,
+                  condition = condition,
+                  function = function,
+                  skip = skip)
+
+    def interpreter_set(self, interpreter):
+        """Set the program to be used to interpret the program
+        under test as a script.
+        """
+        self.interpreter = interpreter
+
+    def match(self, lines, matches):
+        """Compare actual and expected file contents.
+        """
+        return self.match_function(lines, matches)
+
+    def match_exact(self, lines, matches):
+        """Compare actual and expected file contents.
+        """
+        return match_exact(lines, matches)
+
+    def match_re(self, lines, res):
+        """Compare actual and expected file contents.
+        """
+        return match_re(lines, res)
+
+    def match_re_dotall(self, lines, res):
+        """Compare actual and expected file contents.
+        """
+        return match_re_dotall(lines, res)
+
+    def no_result(self, condition = 1, function = None, skip = 0):
+        """Report that the test could not be run.
+        """
+        if not condition:
+            return
+        self.condition = 'no_result'
+        no_result(self = self,
+                  condition = condition,
+                  function = function,
+                  skip = skip)
+
+    def pass_test(self, condition = 1, function = None):
+        """Cause the test to pass.
+        """
+        if not condition:
+            return
+        self.condition = 'pass_test'
+        pass_test(self = self, condition = condition, function = function)
+
+    def preserve(self, *conditions):
+        """Arrange for the temporary working directories for the
+        specified TestCmd environment to be preserved for one or more
+        conditions.  If no conditions are specified, arranges for
+        the temporary working directories to be preserved for all
+        conditions.
+        """
+        if conditions is ():
+            conditions = ('pass_test', 'fail_test', 'no_result')
+        for cond in conditions:
+            self._preserve[cond] = 1
+
+    def program_set(self, program):
+        """Set the executable program or script to be tested.
+        """
+        if program and not os.path.isabs(program):
+            program = os.path.join(self._cwd, program)
+        self.program = program
+
+    def read(self, file, mode = 'rb'):
+        """Reads and returns the contents of the specified file name.
+        The file name may be a list, in which case the elements are
+        concatenated with the os.path.join() method.  The file is
+        assumed to be under the temporary working directory unless it
+        is an absolute path name.  The I/O mode for the file may
+        be specified; it must begin with an 'r'.  The default is
+        'rb' (binary read).
+        """
+        file = self.canonicalize(file)
+        if mode[0] != 'r':
+            raise ValueError, "mode must begin with 'r'"
+        with open(file, mode) as f:
+            result = f.read()
+        return result
+
+    def rmdir(self, dir):
+        """Removes the specified dir name.
+        The dir name may be a list, in which case the elements are
+        concatenated with the os.path.join() method.  The dir is
+        assumed to be under the temporary working directory unless it
+        is an absolute path name.
+        The dir must be empty.
+        """
+        dir = self.canonicalize(dir)
+        os.rmdir(dir)
+
+    def start(self, program = None,
+                    interpreter = None,
+                    arguments = None,
+                    universal_newlines = None,
+                    **kw):
+        """
+        Starts a program or script for the test environment.
+
+        The specified program will have the original directory
+        prepended unless it is enclosed in a [list].
+        """
+        cmd = self.command_args(program, interpreter, arguments)
+        cmd_string = string.join(map(self.escape, cmd), ' ')
+        if self.verbose:
+            sys.stderr.write(cmd_string + "\n")
+        if universal_newlines is None:
+            universal_newlines = self.universal_newlines
+
+        # On Windows, if we make stdin a pipe when we plan to send 
+        # no input, and the test program exits before
+        # Popen calls msvcrt.open_osfhandle, that call will fail.
+        # So don't use a pipe for stdin if we don't need one.
+        stdin = kw.get('stdin', None)
+        if stdin is not None:
+            stdin = subprocess.PIPE
+
+        combine = kw.get('combine', self.combine)
+        if combine:
+            stderr_value = subprocess.STDOUT
+        else:
+            stderr_value = subprocess.PIPE
+
+        return Popen(cmd,
+                     stdin=stdin,
+                     stdout=subprocess.PIPE,
+                     stderr=stderr_value,
+                     universal_newlines=universal_newlines)
+
+    def finish(self, popen, **kw):
+        """
+        Finishes and waits for the process being run under control of
+        the specified popen argument, recording the exit status,
+        standard output and error output.
+        """
+        popen.stdin.close()
+        self.status = popen.wait()
+        if not self.status:
+            self.status = 0
+        self._stdout.append(popen.stdout.read())
+        if popen.stderr:
+            stderr = popen.stderr.read()
+        else:
+            stderr = ''
+        self._stderr.append(stderr)
+
+    def run(self, program = None,
+                  interpreter = None,
+                  arguments = None,
+                  chdir = None,
+                  stdin = None,
+                  universal_newlines = None):
+        """Runs a test of the program or script for the test
+        environment.  Standard output and error output are saved for
+        future retrieval via the stdout() and stderr() methods.
+
+        The specified program will have the original directory
+        prepended unless it is enclosed in a [list].
+        """
+        if chdir:
+            oldcwd = os.getcwd()
+            if not os.path.isabs(chdir):
+                chdir = os.path.join(self.workpath(chdir))
+            if self.verbose:
+                sys.stderr.write("chdir(" + chdir + ")\n")
+            os.chdir(chdir)
+        p = self.start(program,
+                       interpreter,
+                       arguments,
+                       universal_newlines,
+                       stdin=stdin)
+        if stdin:
+            if is_List(stdin):
+                for line in stdin:
+                    p.stdin.write(line)
+            else:
+                p.stdin.write(stdin)
+            p.stdin.close()
+
+        out = p.stdout.read()
+        if p.stderr is None:
+            err = ''
+        else:
+            err = p.stderr.read()
+        try:
+            close_output = p.close_output
+        except AttributeError:
+            p.stdout.close()
+            if not p.stderr is None:
+                p.stderr.close()
+        else:
+            close_output()
+
+        self._stdout.append(out)
+        self._stderr.append(err)
+
+        self.status = p.wait()
+        if not self.status:
+            self.status = 0
+
+        if chdir:
+            os.chdir(oldcwd)
+        if self.verbose >= 2:
+            write = sys.stdout.write
+            write('============ STATUS: %d\n' % self.status)
+            out = self.stdout()
+            if out or self.verbose >= 3:
+                write('============ BEGIN STDOUT (len=%d):\n' % len(out))
+                write(out)
+                write('============ END STDOUT\n')
+            err = self.stderr()
+            if err or self.verbose >= 3:
+                write('============ BEGIN STDERR (len=%d)\n' % len(err))
+                write(err)
+                write('============ END STDERR\n')
+
+    def sleep(self, seconds = default_sleep_seconds):
+        """Sleeps at least the specified number of seconds.  If no
+        number is specified, sleeps at least the minimum number of
+        seconds necessary to advance file time stamps on the current
+        system.  Sleeping more seconds is all right.
+        """
+        time.sleep(seconds)
+
+    def stderr(self, run = None):
+        """Returns the error output from the specified run number.
+        If there is no specified run number, then returns the error
+        output of the last run.  If the run number is less than zero,
+        then returns the error output from that many runs back from the
+        current run.
+        """
+        if not run:
+            run = len(self._stderr)
+        elif run < 0:
+            run = len(self._stderr) + run
+        run = run - 1
+        return self._stderr[run]
+
+    def stdout(self, run = None):
+        """Returns the standard output from the specified run number.
+        If there is no specified run number, then returns the standard
+        output of the last run.  If the run number is less than zero,
+        then returns the standard output from that many runs back from
+        the current run.
+        """
+        if not run:
+            run = len(self._stdout)
+        elif run < 0:
+            run = len(self._stdout) + run
+        run = run - 1
+        return self._stdout[run]
+
+    def subdir(self, *subdirs):
+        """Create new subdirectories under the temporary working
+        directory, one for each argument.  An argument may be a list,
+        in which case the list elements are concatenated using the
+        os.path.join() method.  Subdirectories multiple levels deep
+        must be created using a separate argument for each level:
+
+                test.subdir('sub', ['sub', 'dir'], ['sub', 'dir', 'ectory'])
+
+        Returns the number of subdirectories actually created.
+        """
+        count = 0
+        for sub in subdirs:
+            if sub is None:
+                continue
+            if is_List(sub):
+                sub = apply(os.path.join, tuple(sub))
+            new = os.path.join(self.workdir, sub)
+            try:
+                os.mkdir(new)
+            except OSError:
+                pass
+            else:
+                count = count + 1
+        return count
+
+    def symlink(self, target, link):
+        """Creates a symlink to the specified target.
+        The link name may be a list, in which case the elements are
+        concatenated with the os.path.join() method.  The link is
+        assumed to be under the temporary working directory unless it
+        is an absolute path name. The target is *not* assumed to be
+        under the temporary working directory.
+        """
+        link = self.canonicalize(link)
+        os.symlink(target, link)
+
+    def tempdir(self, path=None):
+        """Creates a temporary directory.
+        A unique directory name is generated if no path name is specified.
+        The directory is created, and will be removed when the TestCmd
+        object is destroyed.
+        """
+        if path is None:
+            try:
+                path = tempfile.mktemp(prefix=tempfile.template)
+            except TypeError:
+                path = tempfile.mktemp()
+        os.mkdir(path)
+
+        # Symlinks in the path will report things
+        # differently from os.getcwd(), so chdir there
+        # and back to fetch the canonical path.
+        cwd = os.getcwd()
+        try:
+            os.chdir(path)
+            path = os.getcwd()
+        finally:
+            os.chdir(cwd)
+
+        # Uppercase the drive letter since the case of drive
+        # letters is pretty much random on win32:
+        drive,rest = os.path.splitdrive(path)
+        if drive:
+            path = string.upper(drive) + rest
+
+        #
+        self._dirlist.append(path)
+        global _Cleanup
+        try:
+            _Cleanup.index(self)
+        except ValueError:
+            _Cleanup.append(self)
+
+        return path
+
+    def touch(self, path, mtime=None):
+        """Updates the modification time on the specified file or
+        directory path name.  The default is to update to the
+        current time if no explicit modification time is specified.
+        """
+        path = self.canonicalize(path)
+        atime = os.path.getatime(path)
+        if mtime is None:
+            mtime = time.time()
+        os.utime(path, (atime, mtime))
+
+    def unlink(self, file):
+        """Unlinks the specified file name.
+        The file name may be a list, in which case the elements are
+        concatenated with the os.path.join() method.  The file is
+        assumed to be under the temporary working directory unless it
+        is an absolute path name.
+        """
+        file = self.canonicalize(file)
+        os.unlink(file)
+
+    def verbose_set(self, verbose):
+        """Set the verbose level.
+        """
+        self.verbose = verbose
+
+    def where_is(self, file, path=None, pathext=None):
+        """Find an executable file.
+        """
+        if is_List(file):
+            file = apply(os.path.join, tuple(file))
+        if not os.path.isabs(file):
+            file = where_is(file, path, pathext)
+        return file
+
+    def workdir_set(self, path):
+        """Creates a temporary working directory with the specified
+        path name.  If the path is a null string (''), a unique
+        directory name is created.
+        """
+        if (path != None):
+            if path == '':
+                path = None
+            path = self.tempdir(path)
+        self.workdir = path
+
+    def workpath(self, *args):
+        """Returns the absolute path name to a subdirectory or file
+        within the current temporary working directory.  Concatenates
+        the temporary working directory name with the specified
+        arguments using the os.path.join() method.
+        """
+        return apply(os.path.join, (self.workdir,) + tuple(args))
+
+    def readable(self, top, read=1):
+        """Make the specified directory tree readable (read == 1)
+        or not (read == None).
+
+        This method has no effect on Windows systems, which use a
+        completely different mechanism to control file readability.
+        """
+
+        if sys.platform == 'win32':
+            return
+
+        if read:
+            def do_chmod(fname):
+                try: st = os.stat(fname)
+                except OSError: pass
+                else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|stat.S_IREAD))
+        else:
+            def do_chmod(fname):
+                try: st = os.stat(fname)
+                except OSError: pass
+                else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IREAD))
+
+        if os.path.isfile(top):
+            # If it's a file, that's easy, just chmod it.
+            do_chmod(top)
+        elif read:
+            # It's a directory and we're trying to turn on read
+            # permission, so it's also pretty easy, just chmod the
+            # directory and then chmod every entry on our walk down the
+            # tree.  Because os.path.walk() is top-down, we'll enable
+            # read permission on any directories that have it disabled
+            # before os.path.walk() tries to list their contents.
+            do_chmod(top)
+
+            def chmod_entries(arg, dirname, names, do_chmod=do_chmod):
+                for n in names:
+                    do_chmod(os.path.join(dirname, n))
+
+            os.path.walk(top, chmod_entries, None)
+        else:
+            # It's a directory and we're trying to turn off read
+            # permission, which means we have to chmod the directoreis
+            # in the tree bottom-up, lest disabling read permission from
+            # the top down get in the way of being able to get at lower
+            # parts of the tree.  But os.path.walk() visits things top
+            # down, so we just use an object to collect a list of all
+            # of the entries in the tree, reverse the list, and then
+            # chmod the reversed (bottom-up) list.
+            col = Collector(top)
+            os.path.walk(top, col, None)
+            col.entries.reverse()
+            for d in col.entries: do_chmod(d)
+
+    def writable(self, top, write=1):
+        """Make the specified directory tree writable (write == 1)
+        or not (write == None).
+        """
+
+        if sys.platform == 'win32':
+
+            if write:
+                def do_chmod(fname):
+                    try: os.chmod(fname, stat.S_IWRITE)
+                    except OSError: pass
+            else:
+                def do_chmod(fname):
+                    try: os.chmod(fname, stat.S_IREAD)
+                    except OSError: pass
+
+        else:
+
+            if write:
+                def do_chmod(fname):
+                    try: st = os.stat(fname)
+                    except OSError: pass
+                    else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0200))
+            else:
+                def do_chmod(fname):
+                    try: st = os.stat(fname)
+                    except OSError: pass
+                    else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0200))
+
+        if os.path.isfile(top):
+            do_chmod(top)
+        else:
+            col = Collector(top)
+            os.path.walk(top, col, None)
+            for d in col.entries: do_chmod(d)
+
+    def executable(self, top, execute=1):
+        """Make the specified directory tree executable (execute == 1)
+        or not (execute == None).
+
+        This method has no effect on Windows systems, which use a
+        completely different mechanism to control file executability.
+        """
+
+        if sys.platform == 'win32':
+            return
+
+        if execute:
+            def do_chmod(fname):
+                try: st = os.stat(fname)
+                except OSError: pass
+                else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|stat.S_IEXEC))
+        else:
+            def do_chmod(fname):
+                try: st = os.stat(fname)
+                except OSError: pass
+                else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IEXEC))
+
+        if os.path.isfile(top):
+            # If it's a file, that's easy, just chmod it.
+            do_chmod(top)
+        elif execute:
+            # It's a directory and we're trying to turn on execute
+            # permission, so it's also pretty easy, just chmod the
+            # directory and then chmod every entry on our walk down the
+            # tree.  Because os.path.walk() is top-down, we'll enable
+            # execute permission on any directories that have it disabled
+            # before os.path.walk() tries to list their contents.
+            do_chmod(top)
+
+            def chmod_entries(arg, dirname, names, do_chmod=do_chmod):
+                for n in names:
+                    do_chmod(os.path.join(dirname, n))
+
+            os.path.walk(top, chmod_entries, None)
+        else:
+            # It's a directory and we're trying to turn off execute
+            # permission, which means we have to chmod the directories
+            # in the tree bottom-up, lest disabling execute permission from
+            # the top down get in the way of being able to get at lower
+            # parts of the tree.  But os.path.walk() visits things top
+            # down, so we just use an object to collect a list of all
+            # of the entries in the tree, reverse the list, and then
+            # chmod the reversed (bottom-up) list.
+            col = Collector(top)
+            os.path.walk(top, col, None)
+            col.entries.reverse()
+            for d in col.entries: do_chmod(d)
+
+    def write(self, file, content, mode = 'wb'):
+        """Writes the specified content text (second argument) to the
+        specified file name (first argument).  The file name may be
+        a list, in which case the elements are concatenated with the
+        os.path.join() method.  The file is created under the temporary
+        working directory.  Any subdirectories in the path must already
+        exist.  The I/O mode for the file may be specified; it must
+        begin with a 'w'.  The default is 'wb' (binary write).
+        """
+        file = self.canonicalize(file)
+        if mode[0] != 'w':
+            raise ValueError, "mode must begin with 'w'"
+        with open(file, mode) as f:
+            f.write(content)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/gyp/test/lib/TestCommon.py b/gyp/test/lib/TestCommon.py
new file mode 100644 (file)
index 0000000..c54530c
--- /dev/null
@@ -0,0 +1,570 @@
+"""
+TestCommon.py:  a testing framework for commands and scripts
+                with commonly useful error handling
+
+The TestCommon module provides a simple, high-level interface for writing
+tests of executable commands and scripts, especially commands and scripts
+that interact with the file system.  All methods throw exceptions and
+exit on failure, with useful error messages.  This makes a number of
+explicit checks unnecessary, making the test scripts themselves simpler
+to write and easier to read.
+
+The TestCommon class is a subclass of the TestCmd class.  In essence,
+TestCommon is a wrapper that handles common TestCmd error conditions in
+useful ways.  You can use TestCommon directly, or subclass it for your
+program and add additional (or override) methods to tailor it to your
+program's specific needs.  Alternatively, the TestCommon class serves
+as a useful example of how to define your own TestCmd subclass.
+
+As a subclass of TestCmd, TestCommon provides access to all of the
+variables and methods from the TestCmd module.  Consequently, you can
+use any variable or method documented in the TestCmd module without
+having to explicitly import TestCmd.
+
+A TestCommon environment object is created via the usual invocation:
+
+    import TestCommon
+    test = TestCommon.TestCommon()
+
+You can use all of the TestCmd keyword arguments when instantiating a
+TestCommon object; see the TestCmd documentation for details.
+
+Here is an overview of the methods and keyword arguments that are
+provided by the TestCommon class:
+
+    test.must_be_writable('file1', ['file2', ...])
+
+    test.must_contain('file', 'required text\n')
+
+    test.must_contain_all_lines(output, lines, ['title', find])
+
+    test.must_contain_any_line(output, lines, ['title', find])
+
+    test.must_exist('file1', ['file2', ...])
+
+    test.must_match('file', "expected contents\n")
+
+    test.must_not_be_writable('file1', ['file2', ...])
+
+    test.must_not_contain('file', 'banned text\n')
+
+    test.must_not_contain_any_line(output, lines, ['title', find])
+
+    test.must_not_exist('file1', ['file2', ...])
+
+    test.run(options = "options to be prepended to arguments",
+             stdout = "expected standard output from the program",
+             stderr = "expected error output from the program",
+             status = expected_status,
+             match = match_function)
+
+The TestCommon module also provides the following variables
+
+    TestCommon.python_executable
+    TestCommon.exe_suffix
+    TestCommon.obj_suffix
+    TestCommon.shobj_prefix
+    TestCommon.shobj_suffix
+    TestCommon.lib_prefix
+    TestCommon.lib_suffix
+    TestCommon.dll_prefix
+    TestCommon.dll_suffix
+
+"""
+
+# Copyright 2000-2010 Steven Knight
+# This module is free software, and you may redistribute it and/or modify
+# it under the same terms as Python itself, so long as this copyright message
+# and disclaimer are retained in their original form.
+#
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
+# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+__author__ = "Steven Knight <knight at baldmt dot com>"
+__revision__ = "TestCommon.py 0.37.D001 2010/01/11 16:55:50 knight"
+__version__ = "0.37"
+
+import copy
+import os
+import os.path
+import stat
+import string
+import sys
+import types
+import UserList
+
+from TestCmd import *
+from TestCmd import __all__
+
+__all__.extend([ 'TestCommon',
+                 'exe_suffix',
+                 'obj_suffix',
+                 'shobj_prefix',
+                 'shobj_suffix',
+                 'lib_prefix',
+                 'lib_suffix',
+                 'dll_prefix',
+                 'dll_suffix',
+               ])
+
+# Variables that describe the prefixes and suffixes on this system.
+if sys.platform == 'win32':
+    exe_suffix   = '.exe'
+    obj_suffix   = '.obj'
+    shobj_suffix = '.obj'
+    shobj_prefix = ''
+    lib_prefix   = ''
+    lib_suffix   = '.lib'
+    dll_prefix   = ''
+    dll_suffix   = '.dll'
+elif sys.platform == 'cygwin':
+    exe_suffix   = '.exe'
+    obj_suffix   = '.o'
+    shobj_suffix = '.os'
+    shobj_prefix = ''
+    lib_prefix   = 'lib'
+    lib_suffix   = '.a'
+    dll_prefix   = ''
+    dll_suffix   = '.dll'
+elif string.find(sys.platform, 'irix') != -1:
+    exe_suffix   = ''
+    obj_suffix   = '.o'
+    shobj_suffix = '.o'
+    shobj_prefix = ''
+    lib_prefix   = 'lib'
+    lib_suffix   = '.a'
+    dll_prefix   = 'lib'
+    dll_suffix   = '.so'
+elif string.find(sys.platform, 'darwin') != -1:
+    exe_suffix   = ''
+    obj_suffix   = '.o'
+    shobj_suffix = '.os'
+    shobj_prefix = ''
+    lib_prefix   = 'lib'
+    lib_suffix   = '.a'
+    dll_prefix   = 'lib'
+    dll_suffix   = '.dylib'
+elif string.find(sys.platform, 'sunos') != -1:
+    exe_suffix   = ''
+    obj_suffix   = '.o'
+    shobj_suffix = '.os'
+    shobj_prefix = 'so_'
+    lib_prefix   = 'lib'
+    lib_suffix   = '.a'
+    dll_prefix   = 'lib'
+    dll_suffix   = '.dylib'
+else:
+    exe_suffix   = ''
+    obj_suffix   = '.o'
+    shobj_suffix = '.os'
+    shobj_prefix = ''
+    lib_prefix   = 'lib'
+    lib_suffix   = '.a'
+    dll_prefix   = 'lib'
+    dll_suffix   = '.so'
+
+def is_List(e):
+    return type(e) is types.ListType \
+        or isinstance(e, UserList.UserList)
+
+def is_writable(f):
+    mode = os.stat(f)[stat.ST_MODE]
+    return mode & stat.S_IWUSR
+
+def separate_files(flist):
+    existing = []
+    missing = []
+    for f in flist:
+        if os.path.exists(f):
+            existing.append(f)
+        else:
+            missing.append(f)
+    return existing, missing
+
+def _failed(self, status = 0):
+    if self.status is None or status is None:
+        return None
+    try:
+        return _status(self) not in status
+    except TypeError:
+        # status wasn't an iterable
+        return _status(self) != status
+
+def _status(self):
+    return self.status
+
+class TestCommon(TestCmd):
+
+    # Additional methods from the Perl Test::Cmd::Common module
+    # that we may wish to add in the future:
+    #
+    #  $test->subdir('subdir', ...);
+    #
+    #  $test->copy('src_file', 'dst_file');
+
+    def __init__(self, **kw):
+        """Initialize a new TestCommon instance.  This involves just
+        calling the base class initialization, and then changing directory
+        to the workdir.
+        """
+        apply(TestCmd.__init__, [self], kw)
+        os.chdir(self.workdir)
+
+    def must_be_writable(self, *files):
+        """Ensures that the specified file(s) exist and are writable.
+        An individual file can be specified as a list of directory names,
+        in which case the pathname will be constructed by concatenating
+        them.  Exits FAILED if any of the files does not exist or is
+        not writable.
+        """
+        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
+        existing, missing = separate_files(files)
+        unwritable = filter(lambda x, iw=is_writable: not iw(x), existing)
+        if missing:
+            print "Missing files: `%s'" % string.join(missing, "', `")
+        if unwritable:
+            print "Unwritable files: `%s'" % string.join(unwritable, "', `")
+        self.fail_test(missing + unwritable)
+
+    def must_contain(self, file, required, mode = 'rb'):
+        """Ensures that the specified file contains the required text.
+        """
+        file_contents = self.read(file, mode)
+        contains = (string.find(file_contents, required) != -1)
+        if not contains:
+            print "File `%s' does not contain required string." % file
+            print self.banner('Required string ')
+            print required
+            print self.banner('%s contents ' % file)
+            print file_contents
+            self.fail_test(not contains)
+
+    def must_contain_all_lines(self, output, lines, title=None, find=None):
+        """Ensures that the specified output string (first argument)
+        contains all of the specified lines (second argument).
+
+        An optional third argument can be used to describe the type
+        of output being searched, and only shows up in failure output.
+
+        An optional fourth argument can be used to supply a different
+        function, of the form "find(line, output), to use when searching
+        for lines in the output.
+        """
+        if find is None:
+            find = lambda o, l: string.find(o, l) != -1
+        missing = []
+        for line in lines:
+            if not find(output, line):
+                missing.append(line)
+
+        if missing:
+            if title is None:
+                title = 'output'
+            sys.stdout.write("Missing expected lines from %s:\n" % title)
+            for line in missing:
+                sys.stdout.write('    ' + repr(line) + '\n')
+            sys.stdout.write(self.banner(title + ' '))
+            sys.stdout.write(output)
+            self.fail_test()
+
+    def must_contain_any_line(self, output, lines, title=None, find=None):
+        """Ensures that the specified output string (first argument)
+        contains at least one of the specified lines (second argument).
+
+        An optional third argument can be used to describe the type
+        of output being searched, and only shows up in failure output.
+
+        An optional fourth argument can be used to supply a different
+        function, of the form "find(line, output), to use when searching
+        for lines in the output.
+        """
+        if find is None:
+            find = lambda o, l: string.find(o, l) != -1
+        for line in lines:
+            if find(output, line):
+                return
+
+        if title is None:
+            title = 'output'
+        sys.stdout.write("Missing any expected line from %s:\n" % title)
+        for line in lines:
+            sys.stdout.write('    ' + repr(line) + '\n')
+        sys.stdout.write(self.banner(title + ' '))
+        sys.stdout.write(output)
+        self.fail_test()
+
+    def must_contain_lines(self, lines, output, title=None):
+        # Deprecated; retain for backwards compatibility.
+        return self.must_contain_all_lines(output, lines, title)
+
+    def must_exist(self, *files):
+        """Ensures that the specified file(s) must exist.  An individual
+        file be specified as a list of directory names, in which case the
+        pathname will be constructed by concatenating them.  Exits FAILED
+        if any of the files does not exist.
+        """
+        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
+        missing = filter(lambda x: not os.path.exists(x), files)
+        if missing:
+            print "Missing files: `%s'" % string.join(missing, "', `")
+            self.fail_test(missing)
+
+    def must_match(self, file, expect, mode = 'rb'):
+        """Matches the contents of the specified file (first argument)
+        against the expected contents (second argument).  The expected
+        contents are a list of lines or a string which will be split
+        on newlines.
+        """
+        file_contents = self.read(file, mode)
+        try:
+            self.fail_test(not self.match(file_contents, expect))
+        except KeyboardInterrupt:
+            raise
+        except:
+            print "Unexpected contents of `%s'" % file
+            self.diff(expect, file_contents, 'contents ')
+            raise
+
+    def must_not_contain(self, file, banned, mode = 'rb'):
+        """Ensures that the specified file doesn't contain the banned text.
+        """
+        file_contents = self.read(file, mode)
+        contains = (string.find(file_contents, banned) != -1)
+        if contains:
+            print "File `%s' contains banned string." % file
+            print self.banner('Banned string ')
+            print banned
+            print self.banner('%s contents ' % file)
+            print file_contents
+            self.fail_test(contains)
+
+    def must_not_contain_any_line(self, output, lines, title=None, find=None):
+        """Ensures that the specified output string (first argument)
+        does not contain any of the specified lines (second argument).
+
+        An optional third argument can be used to describe the type
+        of output being searched, and only shows up in failure output.
+
+        An optional fourth argument can be used to supply a different
+        function, of the form "find(line, output), to use when searching
+        for lines in the output.
+        """
+        if find is None:
+            find = lambda o, l: string.find(o, l) != -1
+        unexpected = []
+        for line in lines:
+            if find(output, line):
+                unexpected.append(line)
+
+        if unexpected:
+            if title is None:
+                title = 'output'
+            sys.stdout.write("Unexpected lines in %s:\n" % title)
+            for line in unexpected:
+                sys.stdout.write('    ' + repr(line) + '\n')
+            sys.stdout.write(self.banner(title + ' '))
+            sys.stdout.write(output)
+            self.fail_test()
+
+    def must_not_contain_lines(self, lines, output, title=None):
+        return self.must_not_contain_any_line(output, lines, title)
+
+    def must_not_exist(self, *files):
+        """Ensures that the specified file(s) must not exist.
+        An individual file be specified as a list of directory names, in
+        which case the pathname will be constructed by concatenating them.
+        Exits FAILED if any of the files exists.
+        """
+        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
+        existing = filter(os.path.exists, files)
+        if existing:
+            print "Unexpected files exist: `%s'" % string.join(existing, "', `")
+            self.fail_test(existing)
+
+    def must_not_be_writable(self, *files):
+        """Ensures that the specified file(s) exist and are not writable.
+        An individual file can be specified as a list of directory names,
+        in which case the pathname will be constructed by concatenating
+        them.  Exits FAILED if any of the files does not exist or is
+        writable.
+        """
+        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
+        existing, missing = separate_files(files)
+        writable = filter(is_writable, existing)
+        if missing:
+            print "Missing files: `%s'" % string.join(missing, "', `")
+        if writable:
+            print "Writable files: `%s'" % string.join(writable, "', `")
+        self.fail_test(missing + writable)
+
+    def _complete(self, actual_stdout, expected_stdout,
+                        actual_stderr, expected_stderr, status, match):
+        """
+        Post-processes running a subcommand, checking for failure
+        status and displaying output appropriately.
+        """
+        if _failed(self, status):
+            expect = ''
+            if status != 0:
+                expect = " (expected %s)" % str(status)
+            print "%s returned %s%s" % (self.program, str(_status(self)), expect)
+            print self.banner('STDOUT ')
+            print actual_stdout
+            print self.banner('STDERR ')
+            print actual_stderr
+            self.fail_test()
+        if not expected_stdout is None and not match(actual_stdout, expected_stdout):
+            self.diff(expected_stdout, actual_stdout, 'STDOUT ')
+            if actual_stderr:
+                print self.banner('STDERR ')
+                print actual_stderr
+            self.fail_test()
+        if not expected_stderr is None and not match(actual_stderr, expected_stderr):
+            print self.banner('STDOUT ')
+            print actual_stdout
+            self.diff(expected_stderr, actual_stderr, 'STDERR ')
+            self.fail_test()
+
+    def start(self, program = None,
+                    interpreter = None,
+                    arguments = None,
+                    universal_newlines = None,
+                    **kw):
+        """
+        Starts a program or script for the test environment.
+
+        This handles the "options" keyword argument and exceptions.
+        """
+        options = kw.pop('options', None)
+        if options:
+            if arguments is None:
+                arguments = options
+            else:
+                arguments = options + " " + arguments
+
+        try:
+            return apply(TestCmd.start,
+                         (self, program, interpreter, arguments, universal_newlines),
+                         kw)
+        except KeyboardInterrupt:
+            raise
+        except Exception, e:
+            print self.banner('STDOUT ')
+            try:
+                print self.stdout()
+            except IndexError:
+                pass
+            print self.banner('STDERR ')
+            try:
+                print self.stderr()
+            except IndexError:
+                pass
+            cmd_args = self.command_args(program, interpreter, arguments)
+            sys.stderr.write('Exception trying to execute: %s\n' % cmd_args)
+            raise e
+
+    def finish(self, popen, stdout = None, stderr = '', status = 0, **kw):
+        """
+        Finishes and waits for the process being run under control of
+        the specified popen argument.  Additional arguments are similar
+        to those of the run() method:
+
+                stdout  The expected standard output from
+                        the command.  A value of None means
+                        don't test standard output.
+
+                stderr  The expected error output from
+                        the command.  A value of None means
+                        don't test error output.
+
+                status  The expected exit status from the
+                        command.  A value of None means don't
+                        test exit status.
+        """
+        apply(TestCmd.finish, (self, popen,), kw)
+        match = kw.get('match', self.match)
+        self._complete(self.stdout(), stdout,
+                       self.stderr(), stderr, status, match)
+
+    def run(self, options = None, arguments = None,
+                  stdout = None, stderr = '', status = 0, **kw):
+        """Runs the program under test, checking that the test succeeded.
+
+        The arguments are the same as the base TestCmd.run() method,
+        with the addition of:
+
+                options Extra options that get appended to the beginning
+                        of the arguments.
+
+                stdout  The expected standard output from
+                        the command.  A value of None means
+                        don't test standard output.
+
+                stderr  The expected error output from
+                        the command.  A value of None means
+                        don't test error output.
+
+                status  The expected exit status from the
+                        command.  A value of None means don't
+                        test exit status.
+
+        By default, this expects a successful exit (status = 0), does
+        not test standard output (stdout = None), and expects that error
+        output is empty (stderr = "").
+        """
+        if options:
+            if arguments is None:
+                arguments = options
+            else:
+                arguments = options + " " + arguments
+        kw['arguments'] = arguments
+        match = kw.pop('match', self.match)
+        apply(TestCmd.run, [self], kw)
+        self._complete(self.stdout(), stdout,
+                       self.stderr(), stderr, status, match)
+
+    def skip_test(self, message="Skipping test.\n"):
+        """Skips a test.
+
+        Proper test-skipping behavior is dependent on the external
+        TESTCOMMON_PASS_SKIPS environment variable.  If set, we treat
+        the skip as a PASS (exit 0), and otherwise treat it as NO RESULT.
+        In either case, we print the specified message as an indication
+        that the substance of the test was skipped.
+
+        (This was originally added to support development under Aegis.
+        Technically, skipping a test is a NO RESULT, but Aegis would
+        treat that as a test failure and prevent the change from going to
+        the next step.  Since we ddn't want to force anyone using Aegis
+        to have to install absolutely every tool used by the tests, we
+        would actually report to Aegis that a skipped test has PASSED
+        so that the workflow isn't held up.)
+        """
+        if message:
+            sys.stdout.write(message)
+            sys.stdout.flush()
+        pass_skips = os.environ.get('TESTCOMMON_PASS_SKIPS')
+        if pass_skips in [None, 0, '0']:
+            # skip=1 means skip this function when showing where this
+            # result came from.  They only care about the line where the
+            # script called test.skip_test(), not the line number where
+            # we call test.no_result().
+            self.no_result(skip=1)
+        else:
+            # We're under the development directory for this change,
+            # so this is an Aegis invocation; pass the test (exit 0).
+            self.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/gyp/test/lib/TestGyp.py b/gyp/test/lib/TestGyp.py
new file mode 100644 (file)
index 0000000..3cea15e
--- /dev/null
@@ -0,0 +1,1319 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+TestGyp.py:  a testing framework for GYP integration tests.
+"""
+
+import collections
+from contextlib import contextmanager
+import itertools
+import os
+import re
+import shutil
+import stat
+import subprocess
+import sys
+import tempfile
+
+import TestCmd
+import TestCommon
+from TestCommon import __all__
+
+__all__.extend([
+  'TestGyp',
+])
+
+
+def remove_debug_line_numbers(contents):
+  """Function to remove the line numbers from the debug output
+  of gyp and thus reduce the extreme fragility of the stdout
+  comparison tests.
+  """
+  lines = contents.splitlines()
+  # split each line on ":"
+  lines = [l.split(":", 3) for l in lines]
+  # join each line back together while ignoring the
+  # 3rd column which is the line number
+  lines = [len(l) > 3 and ":".join(l[3:]) or l for l in lines]
+  return "\n".join(lines)
+
+
+def match_modulo_line_numbers(contents_a, contents_b):
+  """File contents matcher that ignores line numbers."""
+  contents_a = remove_debug_line_numbers(contents_a)
+  contents_b = remove_debug_line_numbers(contents_b)
+  return TestCommon.match_exact(contents_a, contents_b)
+
+
+@contextmanager
+def LocalEnv(local_env):
+  """Context manager to provide a local OS environment."""
+  old_env = os.environ.copy()
+  os.environ.update(local_env)
+  try:
+    yield
+  finally:
+    os.environ.clear()
+    os.environ.update(old_env)
+
+
+class TestGypBase(TestCommon.TestCommon):
+  """
+  Class for controlling end-to-end tests of gyp generators.
+
+  Instantiating this class will create a temporary directory and
+  arrange for its destruction (via the TestCmd superclass) and
+  copy all of the non-gyptest files in the directory hierarchy of the
+  executing script.
+
+  The default behavior is to test the 'gyp' or 'gyp.bat' file in the
+  current directory.  An alternative may be specified explicitly on
+  instantiation, or by setting the TESTGYP_GYP environment variable.
+
+  This class should be subclassed for each supported gyp generator
+  (format).  Various abstract methods below define calling signatures
+  used by the test scripts to invoke builds on the generated build
+  configuration and to run executables generated by those builds.
+  """
+
+  formats = []
+  build_tool = None
+  build_tool_list = []
+
+  _exe = TestCommon.exe_suffix
+  _obj = TestCommon.obj_suffix
+  shobj_ = TestCommon.shobj_prefix
+  _shobj = TestCommon.shobj_suffix
+  lib_ = TestCommon.lib_prefix
+  _lib = TestCommon.lib_suffix
+  dll_ = TestCommon.dll_prefix
+  _dll = TestCommon.dll_suffix
+
+  # Constants to represent different targets.
+  ALL = '__all__'
+  DEFAULT = '__default__'
+
+  # Constants for different target types.
+  EXECUTABLE = '__executable__'
+  STATIC_LIB = '__static_lib__'
+  SHARED_LIB = '__shared_lib__'
+
+  def __init__(self, gyp=None, *args, **kw):
+    self.origin_cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
+    self.extra_args = sys.argv[1:]
+
+    if not gyp:
+      gyp = os.environ.get('TESTGYP_GYP')
+      if not gyp:
+        if sys.platform == 'win32':
+          gyp = 'gyp.bat'
+        else:
+          gyp = 'gyp'
+    self.gyp = os.path.abspath(gyp)
+    self.no_parallel = False
+
+    self.formats = [self.format]
+
+    self.initialize_build_tool()
+
+    kw.setdefault('match', TestCommon.match_exact)
+
+    # Put test output in out/testworkarea by default.
+    # Use temporary names so there are no collisions.
+    workdir = os.path.join('out', kw.get('workdir', 'testworkarea'))
+    # Create work area if it doesn't already exist.
+    if not os.path.isdir(workdir):
+      os.makedirs(workdir)
+
+    kw['workdir'] = tempfile.mktemp(prefix='testgyp.', dir=workdir)
+
+    formats = kw.pop('formats', [])
+
+    super(TestGypBase, self).__init__(*args, **kw)
+
+    real_format = self.format.split('-')[-1]
+    excluded_formats = set([f for f in formats if f[0] == '!'])
+    included_formats = set(formats) - excluded_formats
+    if ('!'+real_format in excluded_formats or
+        included_formats and real_format not in included_formats):
+      msg = 'Invalid test for %r format; skipping test.\n'
+      self.skip_test(msg % self.format)
+
+    self.copy_test_configuration(self.origin_cwd, self.workdir)
+    self.set_configuration(None)
+
+    # Set $HOME so that gyp doesn't read the user's actual
+    # ~/.gyp/include.gypi file, which may contain variables
+    # and other settings that would change the output.
+    os.environ['HOME'] = self.workpath()
+    # Clear $GYP_DEFINES for the same reason.
+    if 'GYP_DEFINES' in os.environ:
+      del os.environ['GYP_DEFINES']
+    # Override the user's language settings, which could
+    # otherwise make the output vary from what is expected.
+    os.environ['LC_ALL'] = 'C'
+
+  def built_file_must_exist(self, name, type=None, **kw):
+    """
+    Fails the test if the specified built file name does not exist.
+    """
+    return self.must_exist(self.built_file_path(name, type, **kw))
+
+  def built_file_must_not_exist(self, name, type=None, **kw):
+    """
+    Fails the test if the specified built file name exists.
+    """
+    return self.must_not_exist(self.built_file_path(name, type, **kw))
+
+  def built_file_must_match(self, name, contents, **kw):
+    """
+    Fails the test if the contents of the specified built file name
+    do not match the specified contents.
+    """
+    return self.must_match(self.built_file_path(name, **kw), contents)
+
+  def built_file_must_not_match(self, name, contents, **kw):
+    """
+    Fails the test if the contents of the specified built file name
+    match the specified contents.
+    """
+    return self.must_not_match(self.built_file_path(name, **kw), contents)
+
+  def built_file_must_not_contain(self, name, contents, **kw):
+    """
+    Fails the test if the specified built file name contains the specified
+    contents.
+    """
+    return self.must_not_contain(self.built_file_path(name, **kw), contents)
+
+  def copy_test_configuration(self, source_dir, dest_dir):
+    """
+    Copies the test configuration from the specified source_dir
+    (the directory in which the test script lives) to the
+    specified dest_dir (a temporary working directory).
+
+    This ignores all files and directories that begin with
+    the string 'gyptest', and all '.svn' subdirectories.
+    """
+    for root, dirs, files in os.walk(source_dir):
+      if '.svn' in dirs:
+        dirs.remove('.svn')
+      dirs = [ d for d in dirs if not d.startswith('gyptest') ]
+      files = [ f for f in files if not f.startswith('gyptest') ]
+      for dirname in dirs:
+        source = os.path.join(root, dirname)
+        destination = source.replace(source_dir, dest_dir)
+        os.mkdir(destination)
+        if sys.platform != 'win32':
+          shutil.copystat(source, destination)
+      for filename in files:
+        source = os.path.join(root, filename)
+        destination = source.replace(source_dir, dest_dir)
+        shutil.copy2(source, destination)
+
+  def initialize_build_tool(self):
+    """
+    Initializes the .build_tool attribute.
+
+    Searches the .build_tool_list for an executable name on the user's
+    $PATH.  The first tool on the list is used as-is if nothing is found
+    on the current $PATH.
+    """
+    for build_tool in self.build_tool_list:
+      if not build_tool:
+        continue
+      if os.path.isabs(build_tool):
+        self.build_tool = build_tool
+        return
+      build_tool = self.where_is(build_tool)
+      if build_tool:
+        self.build_tool = build_tool
+        return
+
+    if self.build_tool_list:
+      self.build_tool = self.build_tool_list[0]
+
+  def relocate(self, source, destination):
+    """
+    Renames (relocates) the specified source (usually a directory)
+    to the specified destination, creating the destination directory
+    first if necessary.
+
+    Note:  Don't use this as a generic "rename" operation.  In the
+    future, "relocating" parts of a GYP tree may affect the state of
+    the test to modify the behavior of later method calls.
+    """
+    destination_dir = os.path.dirname(destination)
+    if not os.path.exists(destination_dir):
+      self.subdir(destination_dir)
+    os.rename(source, destination)
+
+  def report_not_up_to_date(self):
+    """
+    Reports that a build is not up-to-date.
+
+    This provides common reporting for formats that have complicated
+    conditions for checking whether a build is up-to-date.  Formats
+    that expect exact output from the command (make) can
+    just set stdout= when they call the run_build() method.
+    """
+    print "Build is not up-to-date:"
+    print self.banner('STDOUT ')
+    print self.stdout()
+    stderr = self.stderr()
+    if stderr:
+      print self.banner('STDERR ')
+      print stderr
+
+  def run_gyp(self, gyp_file, *args, **kw):
+    """
+    Runs gyp against the specified gyp_file with the specified args.
+    """
+
+    # When running gyp, and comparing its output we use a comparitor
+    # that ignores the line numbers that gyp logs in its debug output.
+    if kw.pop('ignore_line_numbers', False):
+      kw.setdefault('match', match_modulo_line_numbers)
+
+    # TODO:  --depth=. works around Chromium-specific tree climbing.
+    depth = kw.pop('depth', '.')
+    run_args = ['--depth='+depth]
+    run_args.extend(['--format='+f for f in self.formats]);
+    run_args.append(gyp_file)
+    if self.no_parallel:
+      run_args += ['--no-parallel']
+    # TODO: if extra_args contains a '--build' flag
+    # we really want that to only apply to the last format (self.format).
+    run_args.extend(self.extra_args)
+    run_args.extend(args)
+    return self.run(program=self.gyp, arguments=run_args, **kw)
+
+  def run(self, *args, **kw):
+    """
+    Executes a program by calling the superclass .run() method.
+
+    This exists to provide a common place to filter out keyword
+    arguments implemented in this layer, without having to update
+    the tool-specific subclasses or clutter the tests themselves
+    with platform-specific code.
+    """
+    if kw.has_key('SYMROOT'):
+      del kw['SYMROOT']
+    super(TestGypBase, self).run(*args, **kw)
+
+  def set_configuration(self, configuration):
+    """
+    Sets the configuration, to be used for invoking the build
+    tool and testing potential built output.
+    """
+    self.configuration = configuration
+
+  def configuration_dirname(self):
+    if self.configuration:
+      return self.configuration.split('|')[0]
+    else:
+      return 'Default'
+
+  def configuration_buildname(self):
+    if self.configuration:
+      return self.configuration
+    else:
+      return 'Default'
+
+  #
+  # Abstract methods to be defined by format-specific subclasses.
+  #
+
+  def build(self, gyp_file, target=None, **kw):
+    """
+    Runs a build of the specified target against the configuration
+    generated from the specified gyp_file.
+
+    A 'target' argument of None or the special value TestGyp.DEFAULT
+    specifies the default argument for the underlying build tool.
+    A 'target' argument of TestGyp.ALL specifies the 'all' target
+    (if any) of the underlying build tool.
+    """
+    raise NotImplementedError
+
+  def built_file_path(self, name, type=None, **kw):
+    """
+    Returns a path to the specified file name, of the specified type.
+    """
+    raise NotImplementedError
+
+  def built_file_basename(self, name, type=None, **kw):
+    """
+    Returns the base name of the specified file name, of the specified type.
+
+    A bare=True keyword argument specifies that prefixes and suffixes shouldn't
+    be applied.
+    """
+    if not kw.get('bare'):
+      if type == self.EXECUTABLE:
+        name = name + self._exe
+      elif type == self.STATIC_LIB:
+        name = self.lib_ + name + self._lib
+      elif type == self.SHARED_LIB:
+        name = self.dll_ + name + self._dll
+    return name
+
+  def run_built_executable(self, name, *args, **kw):
+    """
+    Runs an executable program built from a gyp-generated configuration.
+
+    The specified name should be independent of any particular generator.
+    Subclasses should find the output executable in the appropriate
+    output build directory, tack on any necessary executable suffix, etc.
+    """
+    raise NotImplementedError
+
+  def up_to_date(self, gyp_file, target=None, **kw):
+    """
+    Verifies that a build of the specified target is up to date.
+
+    The subclass should implement this by calling build()
+    (or a reasonable equivalent), checking whatever conditions
+    will tell it the build was an "up to date" null build, and
+    failing if it isn't.
+    """
+    raise NotImplementedError
+
+
+class TestGypGypd(TestGypBase):
+  """
+  Subclass for testing the GYP 'gypd' generator (spit out the
+  internal data structure as pretty-printed Python).
+  """
+  format = 'gypd'
+  def __init__(self, gyp=None, *args, **kw):
+    super(TestGypGypd, self).__init__(*args, **kw)
+    # gypd implies the use of 'golden' files, so parallelizing conflicts as it
+    # causes ordering changes.
+    self.no_parallel = True
+
+
+class TestGypCustom(TestGypBase):
+  """
+  Subclass for testing the GYP with custom generator
+  """
+
+  def __init__(self, gyp=None, *args, **kw):
+    self.format = kw.pop("format")
+    super(TestGypCustom, self).__init__(*args, **kw)
+
+
+class TestGypAndroid(TestGypBase):
+  """
+  Subclass for testing the GYP Android makefile generator. Note that
+  build/envsetup.sh and lunch must have been run before running tests.
+  """
+  format = 'android'
+
+  # Note that we can't use mmm as the build tool because ...
+  # - it builds all targets, whereas we need to pass a target
+  # - it is a function, whereas the test runner assumes the build tool is a file
+  # Instead we use make and duplicate the logic from mmm.
+  build_tool_list = ['make']
+
+  # We use our custom target 'gyp_all_modules', as opposed to the 'all_modules'
+  # target used by mmm, to build only those targets which are part of the gyp
+  # target 'all'.
+  ALL = 'gyp_all_modules'
+
+  def __init__(self, gyp=None, *args, **kw):
+    # Android requires build and test output to be inside its source tree.
+    # We use the following working directory for the test's source, but the
+    # test's build output still goes to $ANDROID_PRODUCT_OUT.
+    # Note that some tests explicitly set format='gypd' to invoke the gypd
+    # backend. This writes to the source tree, but there's no way around this.
+    kw['workdir'] = os.path.join('/tmp', 'gyptest',
+                                 kw.get('workdir', 'testworkarea'))
+    # We need to remove all gyp outputs from out/. Ths is because some tests
+    # don't have rules to regenerate output, so they will simply re-use stale
+    # output if present. Since the test working directory gets regenerated for
+    # each test run, this can confuse things.
+    # We don't have a list of build outputs because we don't know which
+    # dependent targets were built. Instead we delete all gyp-generated output.
+    # This may be excessive, but should be safe.
+    out_dir = os.environ['ANDROID_PRODUCT_OUT']
+    obj_dir = os.path.join(out_dir, 'obj')
+    shutil.rmtree(os.path.join(obj_dir, 'GYP'), ignore_errors = True)
+    for x in ['EXECUTABLES', 'STATIC_LIBRARIES', 'SHARED_LIBRARIES']:
+      for d in os.listdir(os.path.join(obj_dir, x)):
+        if d.endswith('_gyp_intermediates'):
+          shutil.rmtree(os.path.join(obj_dir, x, d), ignore_errors = True)
+    for x in [os.path.join('obj', 'lib'), os.path.join('system', 'lib')]:
+      for d in os.listdir(os.path.join(out_dir, x)):
+        if d.endswith('_gyp.so'):
+          os.remove(os.path.join(out_dir, x, d))
+
+    super(TestGypAndroid, self).__init__(*args, **kw)
+    self._adb_path = os.path.join(os.environ['ANDROID_HOST_OUT'], 'bin', 'adb')
+    self._device_serial = None
+    adb_devices_out = self._call_adb(['devices'])
+    devices = [l.split()[0] for l in adb_devices_out.splitlines()[1:-1]
+               if l.split()[1] == 'device']
+    if len(devices) == 0:
+      self._device_serial = None
+    else:
+      if len(devices) > 1:
+        self._device_serial = random.choice(devices)
+      else:
+        self._device_serial = devices[0]
+      self._call_adb(['root'])
+    self._to_install = set()
+
+  def target_name(self, target):
+    if target == self.ALL:
+      return self.ALL
+    # The default target is 'droid'. However, we want to use our special target
+    # to build only the gyp target 'all'.
+    if target in (None, self.DEFAULT):
+      return self.ALL
+    return target
+
+  _INSTALLABLE_PREFIX = 'Install: '
+
+  def build(self, gyp_file, target=None, **kw):
+    """
+    Runs a build using the Android makefiles generated from the specified
+    gyp_file. This logic is taken from Android's mmm.
+    """
+    arguments = kw.get('arguments', [])[:]
+    arguments.append(self.target_name(target))
+    arguments.append('-C')
+    arguments.append(os.environ['ANDROID_BUILD_TOP'])
+    kw['arguments'] = arguments
+    chdir = kw.get('chdir', '')
+    makefile = os.path.join(self.workdir, chdir, 'GypAndroid.mk')
+    os.environ['ONE_SHOT_MAKEFILE'] = makefile
+    result = self.run(program=self.build_tool, **kw)
+    for l in self.stdout().splitlines():
+      if l.startswith(TestGypAndroid._INSTALLABLE_PREFIX):
+        self._to_install.add(os.path.abspath(os.path.join(
+            os.environ['ANDROID_BUILD_TOP'],
+            l[len(TestGypAndroid._INSTALLABLE_PREFIX):])))
+    del os.environ['ONE_SHOT_MAKEFILE']
+    return result
+
+  def android_module(self, group, name, subdir):
+    if subdir:
+      name = '%s_%s' % (subdir, name)
+    if group == 'SHARED_LIBRARIES':
+      name = 'lib_%s' % name
+    return '%s_gyp' % name
+
+  def intermediates_dir(self, group, module_name):
+    return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', group,
+                        '%s_intermediates' % module_name)
+
+  def built_file_path(self, name, type=None, **kw):
+    """
+    Returns a path to the specified file name, of the specified type,
+    as built by Android. Note that we don't support the configuration
+    parameter.
+    """
+    # Built files are in $ANDROID_PRODUCT_OUT. This requires copying logic from
+    # the Android build system.
+    if type == None or type == self.EXECUTABLE:
+      return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', 'GYP',
+                          'shared_intermediates', name)
+    subdir = kw.get('subdir')
+    if type == self.STATIC_LIB:
+      group = 'STATIC_LIBRARIES'
+      module_name = self.android_module(group, name, subdir)
+      return os.path.join(self.intermediates_dir(group, module_name),
+                          '%s.a' % module_name)
+    if type == self.SHARED_LIB:
+      group = 'SHARED_LIBRARIES'
+      module_name = self.android_module(group, name, subdir)
+      return os.path.join(self.intermediates_dir(group, module_name), 'LINKED',
+                          '%s.so' % module_name)
+    assert False, 'Unhandled type'
+
+  def _adb_failure(self, command, msg, stdout, stderr):
+    """ Reports a failed adb command and fails the containing test.
+
+    Args:
+      command: The adb command that failed.
+      msg: The error description.
+      stdout: The standard output.
+      stderr: The standard error.
+    """
+    print '%s failed%s' % (' '.join(command), ': %s' % msg if msg else '')
+    print self.banner('STDOUT ')
+    stdout.seek(0)
+    print stdout.read()
+    print self.banner('STDERR ')
+    stderr.seek(0)
+    print stderr.read()
+    self.fail_test()
+
+  def _call_adb(self, command):
+    """ Calls the provided adb command.
+
+    If the command fails, the test fails.
+
+    Args:
+      command: The adb command to call.
+    Returns:
+      The command's output.
+    """
+    with tempfile.TemporaryFile(bufsize=0) as adb_out:
+      with tempfile.TemporaryFile(bufsize=0) as adb_err:
+        adb_command = [self._adb_path]
+        if self._device_serial:
+          adb_command += ['-s', self._device_serial]
+        is_shell = (command[0] == 'shell')
+        if is_shell:
+          command = [command[0], '%s; echo "\n$?";' % ' '.join(command[1:])]
+        adb_command += command
+        if subprocess.call(adb_command, stdout=adb_out, stderr=adb_err) != 0:
+          self._adb_failure(adb_command, None, adb_out, adb_err)
+        else:
+          adb_out.seek(0)
+          output = adb_out.read()
+          if is_shell:
+            output = output.splitlines(True)
+            try:
+              output[-2] = output[-2].rstrip('\r\n')
+              output, rc = (''.join(output[:-1]), int(output[-1]))
+            except ValueError:
+              self._adb_failure(adb_command, 'unexpected output format',
+                                adb_out, adb_err)
+            if rc != 0:
+              self._adb_failure(adb_command, 'exited with %d' % rc, adb_out,
+                                adb_err)
+          return output
+
+  def run_built_executable(self, name, *args, **kw):
+    """
+    Runs an executable program built from a gyp-generated configuration.
+    """
+    match = kw.pop('match', self.match)
+
+    executable_file = self.built_file_path(name, type=self.EXECUTABLE, **kw)
+    if executable_file not in self._to_install:
+      self.fail_test()
+
+    if not self._device_serial:
+      self.skip_test(message='No devices attached.\n')
+
+    storage = self._call_adb(['shell', 'echo', '$ANDROID_DATA']).strip()
+    if not len(storage):
+      self.fail_test()
+
+    installed = set()
+    try:
+      for i in self._to_install:
+        a = os.path.abspath(
+            os.path.join(os.environ['ANDROID_BUILD_TOP'], i))
+        dest = '%s/%s' % (storage, os.path.basename(a))
+        self._call_adb(['push', os.path.abspath(a), dest])
+        installed.add(dest)
+        if i == executable_file:
+          device_executable = dest
+          self._call_adb(['shell', 'chmod', '755', device_executable])
+
+      out = self._call_adb(
+          ['shell', 'LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%s' % storage,
+           device_executable])
+      out = out.replace('\r\n', '\n')
+      self._complete(out, kw.pop('stdout', None), None, None, None, match)
+    finally:
+      if len(installed):
+        self._call_adb(['shell', 'rm'] + list(installed))
+
+  def match_single_line(self, lines = None, expected_line = None):
+    """
+    Checks that specified line appears in the text.
+    """
+    for line in lines.split('\n'):
+        if line == expected_line:
+            return 1
+    return
+
+  def up_to_date(self, gyp_file, target=None, **kw):
+    """
+    Verifies that a build of the specified target is up to date.
+    """
+    kw['stdout'] = ("make: Nothing to be done for `%s'." %
+                    self.target_name(target))
+
+    # We need to supply a custom matcher, since we don't want to depend on the
+    # exact stdout string.
+    kw['match'] = self.match_single_line
+    return self.build(gyp_file, target, **kw)
+
+
+class TestGypCMake(TestGypBase):
+  """
+  Subclass for testing the GYP CMake generator, using cmake's ninja backend.
+  """
+  format = 'cmake'
+  build_tool_list = ['cmake']
+  ALL = 'all'
+
+  def cmake_build(self, gyp_file, target=None, **kw):
+    arguments = kw.get('arguments', [])[:]
+
+    self.build_tool_list = ['cmake']
+    self.initialize_build_tool()
+
+    chdir = os.path.join(kw.get('chdir', '.'),
+                         'out',
+                         self.configuration_dirname())
+    kw['chdir'] = chdir
+
+    arguments.append('-G')
+    arguments.append('Ninja')
+
+    kw['arguments'] = arguments
+
+    stderr = kw.get('stderr', None)
+    if stderr:
+      kw['stderr'] = stderr.split('$$$')[0]
+
+    self.run(program=self.build_tool, **kw)
+
+  def ninja_build(self, gyp_file, target=None, **kw):
+    arguments = kw.get('arguments', [])[:]
+
+    self.build_tool_list = ['ninja']
+    self.initialize_build_tool()
+
+    # Add a -C output/path to the command line.
+    arguments.append('-C')
+    arguments.append(os.path.join('out', self.configuration_dirname()))
+
+    if target not in (None, self.DEFAULT):
+      arguments.append(target)
+
+    kw['arguments'] = arguments
+
+    stderr = kw.get('stderr', None)
+    if stderr:
+      stderrs = stderr.split('$$$')
+      kw['stderr'] = stderrs[1] if len(stderrs) > 1 else ''
+
+    return self.run(program=self.build_tool, **kw)
+
+  def build(self, gyp_file, target=None, status=0, **kw):
+    # Two tools must be run to build, cmake and the ninja.
+    # Allow cmake to succeed when the overall expectation is to fail.
+    if status is None:
+      kw['status'] = None
+    else:
+      if not isinstance(status, collections.Iterable): status = (status,)
+      kw['status'] = list(itertools.chain((0,), status))
+    self.cmake_build(gyp_file, target, **kw)
+    kw['status'] = status
+    self.ninja_build(gyp_file, target, **kw)
+
+  def run_built_executable(self, name, *args, **kw):
+    # Enclosing the name in a list avoids prepending the original dir.
+    program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
+    if sys.platform == 'darwin':
+      configuration = self.configuration_dirname()
+      os.environ['DYLD_LIBRARY_PATH'] = os.path.join('out', configuration)
+    return self.run(program=program, *args, **kw)
+
+  def built_file_path(self, name, type=None, **kw):
+    result = []
+    chdir = kw.get('chdir')
+    if chdir:
+      result.append(chdir)
+    result.append('out')
+    result.append(self.configuration_dirname())
+    if type == self.STATIC_LIB:
+      if sys.platform != 'darwin':
+        result.append('obj.target')
+    elif type == self.SHARED_LIB:
+      if sys.platform != 'darwin' and sys.platform != 'win32':
+        result.append('lib.target')
+    subdir = kw.get('subdir')
+    if subdir and type != self.SHARED_LIB:
+      result.append(subdir)
+    result.append(self.built_file_basename(name, type, **kw))
+    return self.workpath(*result)
+
+  def up_to_date(self, gyp_file, target=None, **kw):
+    result = self.ninja_build(gyp_file, target, **kw)
+    if not result:
+      stdout = self.stdout()
+      if 'ninja: no work to do' not in stdout:
+        self.report_not_up_to_date()
+        self.fail_test()
+    return result
+
+
+class TestGypMake(TestGypBase):
+  """
+  Subclass for testing the GYP Make generator.
+  """
+  format = 'make'
+  build_tool_list = ['make']
+  ALL = 'all'
+  def build(self, gyp_file, target=None, **kw):
+    """
+    Runs a Make build using the Makefiles generated from the specified
+    gyp_file.
+    """
+    arguments = kw.get('arguments', [])[:]
+    if self.configuration:
+      arguments.append('BUILDTYPE=' + self.configuration)
+    if target not in (None, self.DEFAULT):
+      arguments.append(target)
+    # Sub-directory builds provide per-gyp Makefiles (i.e.
+    # Makefile.gyp_filename), so use that if there is no Makefile.
+    chdir = kw.get('chdir', '')
+    if not os.path.exists(os.path.join(chdir, 'Makefile')):
+      print "NO Makefile in " + os.path.join(chdir, 'Makefile')
+      arguments.insert(0, '-f')
+      arguments.insert(1, os.path.splitext(gyp_file)[0] + '.Makefile')
+    kw['arguments'] = arguments
+    return self.run(program=self.build_tool, **kw)
+  def up_to_date(self, gyp_file, target=None, **kw):
+    """
+    Verifies that a build of the specified Make target is up to date.
+    """
+    if target in (None, self.DEFAULT):
+      message_target = 'all'
+    else:
+      message_target = target
+    kw['stdout'] = "make: Nothing to be done for `%s'.\n" % message_target
+    return self.build(gyp_file, target, **kw)
+  def run_built_executable(self, name, *args, **kw):
+    """
+    Runs an executable built by Make.
+    """
+    configuration = self.configuration_dirname()
+    libdir = os.path.join('out', configuration, 'lib')
+    # TODO(piman): when everything is cross-compile safe, remove lib.target
+    if sys.platform == 'darwin':
+      # Mac puts target shared libraries right in the product directory.
+      configuration = self.configuration_dirname()
+      os.environ['DYLD_LIBRARY_PATH'] = (
+          libdir + '.host:' + os.path.join('out', configuration))
+    else:
+      os.environ['LD_LIBRARY_PATH'] = libdir + '.host:' + libdir + '.target'
+    # Enclosing the name in a list avoids prepending the original dir.
+    program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
+    return self.run(program=program, *args, **kw)
+  def built_file_path(self, name, type=None, **kw):
+    """
+    Returns a path to the specified file name, of the specified type,
+    as built by Make.
+
+    Built files are in the subdirectory 'out/{configuration}'.
+    The default is 'out/Default'.
+
+    A chdir= keyword argument specifies the source directory
+    relative to which  the output subdirectory can be found.
+
+    "type" values of STATIC_LIB or SHARED_LIB append the necessary
+    prefixes and suffixes to a platform-independent library base name.
+
+    A subdir= keyword argument specifies a library subdirectory within
+    the default 'obj.target'.
+    """
+    result = []
+    chdir = kw.get('chdir')
+    if chdir:
+      result.append(chdir)
+    configuration = self.configuration_dirname()
+    result.extend(['out', configuration])
+    if type == self.STATIC_LIB and sys.platform != 'darwin':
+      result.append('obj.target')
+    elif type == self.SHARED_LIB and sys.platform != 'darwin':
+      result.append('lib.target')
+    subdir = kw.get('subdir')
+    if subdir and type != self.SHARED_LIB:
+      result.append(subdir)
+    result.append(self.built_file_basename(name, type, **kw))
+    return self.workpath(*result)
+
+
+def ConvertToCygpath(path):
+  """Convert to cygwin path if we are using cygwin."""
+  if sys.platform == 'cygwin':
+    p = subprocess.Popen(['cygpath', path], stdout=subprocess.PIPE)
+    path = p.communicate()[0].strip()
+  return path
+
+
+def FindMSBuildInstallation(msvs_version = 'auto'):
+  """Returns path to MSBuild for msvs_version or latest available.
+
+  Looks in the registry to find install location of MSBuild.
+  MSBuild before v4.0 will not build c++ projects, so only use newer versions.
+  """
+  import TestWin
+  registry = TestWin.Registry()
+
+  msvs_to_msbuild = {
+      '2013': r'12.0',
+      '2012': r'4.0',  # Really v4.0.30319 which comes with .NET 4.5.
+      '2010': r'4.0'}
+
+  msbuild_basekey = r'HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions'
+  if not registry.KeyExists(msbuild_basekey):
+    print 'Error: could not find MSBuild base registry entry'
+    return None
+
+  msbuild_version = None
+  if msvs_version in msvs_to_msbuild:
+    msbuild_test_version = msvs_to_msbuild[msvs_version]
+    if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version):
+      msbuild_version = msbuild_test_version
+    else:
+      print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
+             'but corresponding MSBuild "%s" was not found.' %
+             (msvs_version, msbuild_version))
+  if not msbuild_version:
+    for msvs_version in sorted(msvs_to_msbuild, reverse=True):
+      msbuild_test_version = msvs_to_msbuild[msvs_version]
+      if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version):
+        msbuild_version = msbuild_test_version
+        break
+  if not msbuild_version:
+    print 'Error: could not find MSBuild registry entry'
+    return None
+
+  msbuild_path = registry.GetValue(msbuild_basekey + '\\' + msbuild_version,
+                                   'MSBuildToolsPath')
+  if not msbuild_path:
+    print 'Error: could not get MSBuild registry entry value'
+    return None
+
+  return os.path.join(msbuild_path, 'MSBuild.exe')
+
+
+def FindVisualStudioInstallation():
+  """Returns appropriate values for .build_tool and .uses_msbuild fields
+  of TestGypBase for Visual Studio.
+
+  We use the value specified by GYP_MSVS_VERSION.  If not specified, we
+  search %PATH% and %PATHEXT% for a devenv.{exe,bat,...} executable.
+  Failing that, we search for likely deployment paths.
+  """
+  possible_roots = ['%s:\\Program Files%s' % (chr(drive), suffix)
+                    for drive in range(ord('C'), ord('Z') + 1)
+                    for suffix in ['', ' (x86)']]
+  possible_paths = {
+      '2013': r'Microsoft Visual Studio 12.0\Common7\IDE\devenv.com',
+      '2012': r'Microsoft Visual Studio 11.0\Common7\IDE\devenv.com',
+      '2010': r'Microsoft Visual Studio 10.0\Common7\IDE\devenv.com',
+      '2008': r'Microsoft Visual Studio 9.0\Common7\IDE\devenv.com',
+      '2005': r'Microsoft Visual Studio 8\Common7\IDE\devenv.com'}
+
+  possible_roots = [ConvertToCygpath(r) for r in possible_roots]
+
+  msvs_version = 'auto'
+  for flag in (f for f in sys.argv if f.startswith('msvs_version=')):
+    msvs_version = flag.split('=')[-1]
+  msvs_version = os.environ.get('GYP_MSVS_VERSION', msvs_version)
+
+  if msvs_version in possible_paths:
+    # Check that the path to the specified GYP_MSVS_VERSION exists.
+    path = possible_paths[msvs_version]
+    for r in possible_roots:
+      build_tool = os.path.join(r, path)
+      if os.path.exists(build_tool):
+        uses_msbuild = msvs_version >= '2010'
+        msbuild_path = FindMSBuildInstallation(msvs_version)
+        return build_tool, uses_msbuild, msbuild_path
+    else:
+      print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
+              'but corresponding "%s" was not found.' % (msvs_version, path))
+  # Neither GYP_MSVS_VERSION nor the path help us out.  Iterate through
+  # the choices looking for a match.
+  for version in sorted(possible_paths, reverse=True):
+    path = possible_paths[version]
+    for r in possible_roots:
+      build_tool = os.path.join(r, path)
+      if os.path.exists(build_tool):
+        uses_msbuild = msvs_version >= '2010'
+        msbuild_path = FindMSBuildInstallation(msvs_version)
+        return build_tool, uses_msbuild, msbuild_path
+  print 'Error: could not find devenv'
+  sys.exit(1)
+
+class TestGypOnMSToolchain(TestGypBase):
+  """
+  Common subclass for testing generators that target the Microsoft Visual
+  Studio toolchain (cl, link, dumpbin, etc.)
+  """
+  @staticmethod
+  def _ComputeVsvarsPath(devenv_path):
+    devenv_dir = os.path.split(devenv_path)[0]
+    vsvars_path = os.path.join(devenv_path, '../../Tools/vsvars32.bat')
+    return vsvars_path
+
+  def initialize_build_tool(self):
+    super(TestGypOnMSToolchain, self).initialize_build_tool()
+    if sys.platform in ('win32', 'cygwin'):
+      build_tools = FindVisualStudioInstallation()
+      self.devenv_path, self.uses_msbuild, self.msbuild_path = build_tools
+      self.vsvars_path = TestGypOnMSToolchain._ComputeVsvarsPath(
+          self.devenv_path)
+
+  def run_dumpbin(self, *dumpbin_args):
+    """Run the dumpbin tool with the specified arguments, and capturing and
+    returning stdout."""
+    assert sys.platform in ('win32', 'cygwin')
+    cmd = os.environ.get('COMSPEC', 'cmd.exe')
+    arguments = [cmd, '/c', self.vsvars_path, '&&', 'dumpbin']
+    arguments.extend(dumpbin_args)
+    proc = subprocess.Popen(arguments, stdout=subprocess.PIPE)
+    output = proc.communicate()[0]
+    assert not proc.returncode
+    return output
+
+class TestGypNinja(TestGypOnMSToolchain):
+  """
+  Subclass for testing the GYP Ninja generator.
+  """
+  format = 'ninja'
+  build_tool_list = ['ninja']
+  ALL = 'all'
+  DEFAULT = 'all'
+
+  def run_gyp(self, gyp_file, *args, **kw):
+    TestGypBase.run_gyp(self, gyp_file, *args, **kw)
+
+  def build(self, gyp_file, target=None, **kw):
+    arguments = kw.get('arguments', [])[:]
+
+    # Add a -C output/path to the command line.
+    arguments.append('-C')
+    arguments.append(os.path.join('out', self.configuration_dirname()))
+
+    if target is None:
+      target = 'all'
+    arguments.append(target)
+
+    kw['arguments'] = arguments
+    return self.run(program=self.build_tool, **kw)
+
+  def run_built_executable(self, name, *args, **kw):
+    # Enclosing the name in a list avoids prepending the original dir.
+    program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
+    if sys.platform == 'darwin':
+      configuration = self.configuration_dirname()
+      os.environ['DYLD_LIBRARY_PATH'] = os.path.join('out', configuration)
+    return self.run(program=program, *args, **kw)
+
+  def built_file_path(self, name, type=None, **kw):
+    result = []
+    chdir = kw.get('chdir')
+    if chdir:
+      result.append(chdir)
+    result.append('out')
+    result.append(self.configuration_dirname())
+    if type == self.STATIC_LIB:
+      if sys.platform != 'darwin':
+        result.append('obj')
+    elif type == self.SHARED_LIB:
+      if sys.platform != 'darwin' and sys.platform != 'win32':
+        result.append('lib')
+    subdir = kw.get('subdir')
+    if subdir and type != self.SHARED_LIB:
+      result.append(subdir)
+    result.append(self.built_file_basename(name, type, **kw))
+    return self.workpath(*result)
+
+  def up_to_date(self, gyp_file, target=None, **kw):
+    result = self.build(gyp_file, target, **kw)
+    if not result:
+      stdout = self.stdout()
+      if 'ninja: no work to do' not in stdout:
+        self.report_not_up_to_date()
+        self.fail_test()
+    return result
+
+
+class TestGypMSVS(TestGypOnMSToolchain):
+  """
+  Subclass for testing the GYP Visual Studio generator.
+  """
+  format = 'msvs'
+
+  u = r'=== Build: 0 succeeded, 0 failed, (\d+) up-to-date, 0 skipped ==='
+  up_to_date_re = re.compile(u, re.M)
+
+  # Initial None element will indicate to our .initialize_build_tool()
+  # method below that 'devenv' was not found on %PATH%.
+  #
+  # Note:  we must use devenv.com to be able to capture build output.
+  # Directly executing devenv.exe only sends output to BuildLog.htm.
+  build_tool_list = [None, 'devenv.com']
+
+  def initialize_build_tool(self):
+    super(TestGypMSVS, self).initialize_build_tool()
+    self.build_tool = self.devenv_path
+
+  def build(self, gyp_file, target=None, rebuild=False, clean=False, **kw):
+    """
+    Runs a Visual Studio build using the configuration generated
+    from the specified gyp_file.
+    """
+    configuration = self.configuration_buildname()
+    if clean:
+      build = '/Clean'
+    elif rebuild:
+      build = '/Rebuild'
+    else:
+      build = '/Build'
+    arguments = kw.get('arguments', [])[:]
+    arguments.extend([gyp_file.replace('.gyp', '.sln'),
+                      build, configuration])
+    # Note:  the Visual Studio generator doesn't add an explicit 'all'
+    # target, so we just treat it the same as the default.
+    if target not in (None, self.ALL, self.DEFAULT):
+      arguments.extend(['/Project', target])
+    if self.configuration:
+      arguments.extend(['/ProjectConfig', self.configuration])
+    kw['arguments'] = arguments
+    return self.run(program=self.build_tool, **kw)
+  def up_to_date(self, gyp_file, target=None, **kw):
+    """
+    Verifies that a build of the specified Visual Studio target is up to date.
+
+    Beware that VS2010 will behave strangely if you build under
+    C:\USERS\yourname\AppData\Local. It will cause needless work.  The ouptut
+    will be "1 succeeded and 0 up to date".  MSBuild tracing reveals that:
+    "Project 'C:\Users\...\AppData\Local\...vcxproj' not up to date because
+    'C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO 10.0\VC\BIN\1033\CLUI.DLL'
+    was modified at 02/21/2011 17:03:30, which is newer than '' which was
+    modified at 01/01/0001 00:00:00.
+
+    The workaround is to specify a workdir when instantiating the test, e.g.
+    test = TestGyp.TestGyp(workdir='workarea')
+    """
+    result = self.build(gyp_file, target, **kw)
+    if not result:
+      stdout = self.stdout()
+
+      m = self.up_to_date_re.search(stdout)
+      up_to_date = m and int(m.group(1)) > 0
+      if not up_to_date:
+        self.report_not_up_to_date()
+        self.fail_test()
+    return result
+  def run_built_executable(self, name, *args, **kw):
+    """
+    Runs an executable built by Visual Studio.
+    """
+    configuration = self.configuration_dirname()
+    # Enclosing the name in a list avoids prepending the original dir.
+    program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
+    return self.run(program=program, *args, **kw)
+  def built_file_path(self, name, type=None, **kw):
+    """
+    Returns a path to the specified file name, of the specified type,
+    as built by Visual Studio.
+
+    Built files are in a subdirectory that matches the configuration
+    name.  The default is 'Default'.
+
+    A chdir= keyword argument specifies the source directory
+    relative to which  the output subdirectory can be found.
+
+    "type" values of STATIC_LIB or SHARED_LIB append the necessary
+    prefixes and suffixes to a platform-independent library base name.
+    """
+    result = []
+    chdir = kw.get('chdir')
+    if chdir:
+      result.append(chdir)
+    result.append(self.configuration_dirname())
+    if type == self.STATIC_LIB:
+      result.append('lib')
+    result.append(self.built_file_basename(name, type, **kw))
+    return self.workpath(*result)
+
+
+class TestGypMSVSNinja(TestGypNinja):
+  """
+  Subclass for testing the GYP Visual Studio Ninja generator.
+  """
+  format = 'msvs-ninja'
+
+  def initialize_build_tool(self):
+    super(TestGypMSVSNinja, self).initialize_build_tool()
+    # When using '--build', make sure ninja is first in the format list.
+    self.formats.insert(0, 'ninja')
+
+  def build(self, gyp_file, target=None, rebuild=False, clean=False, **kw):
+    """
+    Runs a Visual Studio build using the configuration generated
+    from the specified gyp_file.
+    """
+    arguments = kw.get('arguments', [])[:]
+    if target in (None, self.ALL, self.DEFAULT):
+      # Note: the Visual Studio generator doesn't add an explicit 'all' target.
+      # This will build each project. This will work if projects are hermetic,
+      # but may fail if they are not (a project may run more than once).
+      # It would be nice to supply an all.metaproj for MSBuild.
+      arguments.extend([gyp_file.replace('.gyp', '.sln')])
+    else:
+      # MSBuild documentation claims that one can specify a sln but then build a
+      # project target like 'msbuild a.sln /t:proj:target' but this format only
+      # supports 'Clean', 'Rebuild', and 'Publish' (with none meaning Default).
+      # This limitation is due to the .sln -> .sln.metaproj conversion.
+      # The ':' is not special, 'proj:target' is a target in the metaproj.
+      arguments.extend([target+'.vcxproj'])
+
+    if clean:
+      build = 'Clean'
+    elif rebuild:
+      build = 'Rebuild'
+    else:
+      build = 'Build'
+    arguments.extend(['/target:'+build])
+    configuration = self.configuration_buildname()
+    config = configuration.split('|')
+    arguments.extend(['/property:Configuration='+config[0]])
+    if len(config) > 1:
+      arguments.extend(['/property:Platform='+config[1]])
+    arguments.extend(['/property:BuildInParallel=false'])
+    arguments.extend(['/verbosity:minimal'])
+
+    kw['arguments'] = arguments
+    return self.run(program=self.msbuild_path, **kw)
+
+
+class TestGypXcode(TestGypBase):
+  """
+  Subclass for testing the GYP Xcode generator.
+  """
+  format = 'xcode'
+  build_tool_list = ['xcodebuild']
+
+  phase_script_execution = ("\n"
+                            "PhaseScriptExecution /\\S+/Script-[0-9A-F]+\\.sh\n"
+                            "    cd /\\S+\n"
+                            "    /bin/sh -c /\\S+/Script-[0-9A-F]+\\.sh\n"
+                            "(make: Nothing to be done for `all'\\.\n)?")
+
+  strip_up_to_date_expressions = [
+    # Various actions or rules can run even when the overall build target
+    # is up to date.  Strip those phases' GYP-generated output.
+    re.compile(phase_script_execution, re.S),
+
+    # The message from distcc_pump can trail the "BUILD SUCCEEDED"
+    # message, so strip that, too.
+    re.compile('__________Shutting down distcc-pump include server\n', re.S),
+  ]
+
+  up_to_date_endings = (
+    'Checking Dependencies...\n** BUILD SUCCEEDED **\n', # Xcode 3.0/3.1
+    'Check dependencies\n** BUILD SUCCEEDED **\n\n',     # Xcode 3.2
+    'Check dependencies\n\n\n** BUILD SUCCEEDED **\n\n', # Xcode 4.2
+    'Check dependencies\n\n** BUILD SUCCEEDED **\n\n',   # Xcode 5.0
+  )
+
+  def build(self, gyp_file, target=None, **kw):
+    """
+    Runs an xcodebuild using the .xcodeproj generated from the specified
+    gyp_file.
+    """
+    # Be sure we're working with a copy of 'arguments' since we modify it.
+    # The caller may not be expecting it to be modified.
+    arguments = kw.get('arguments', [])[:]
+    arguments.extend(['-project', gyp_file.replace('.gyp', '.xcodeproj')])
+    if target == self.ALL:
+      arguments.append('-alltargets',)
+    elif target not in (None, self.DEFAULT):
+      arguments.extend(['-target', target])
+    if self.configuration:
+      arguments.extend(['-configuration', self.configuration])
+    symroot = kw.get('SYMROOT', '$SRCROOT/build')
+    if symroot:
+      arguments.append('SYMROOT='+symroot)
+    kw['arguments'] = arguments
+
+    # Work around spurious stderr output from Xcode 4, http://crbug.com/181012
+    match = kw.pop('match', self.match)
+    def match_filter_xcode(actual, expected):
+      if actual:
+        if not TestCmd.is_List(actual):
+          actual = actual.split('\n')
+        if not TestCmd.is_List(expected):
+          expected = expected.split('\n')
+        actual = [a for a in actual
+                    if 'No recorder, buildTask: <Xcode3BuildTask:' not in a]
+      return match(actual, expected)
+    kw['match'] = match_filter_xcode
+
+    return self.run(program=self.build_tool, **kw)
+  def up_to_date(self, gyp_file, target=None, **kw):
+    """
+    Verifies that a build of the specified Xcode target is up to date.
+    """
+    result = self.build(gyp_file, target, **kw)
+    if not result:
+      output = self.stdout()
+      for expression in self.strip_up_to_date_expressions:
+        output = expression.sub('', output)
+      if not output.endswith(self.up_to_date_endings):
+        self.report_not_up_to_date()
+        self.fail_test()
+    return result
+  def run_built_executable(self, name, *args, **kw):
+    """
+    Runs an executable built by xcodebuild.
+    """
+    configuration = self.configuration_dirname()
+    os.environ['DYLD_LIBRARY_PATH'] = os.path.join('build', configuration)
+    # Enclosing the name in a list avoids prepending the original dir.
+    program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
+    return self.run(program=program, *args, **kw)
+  def built_file_path(self, name, type=None, **kw):
+    """
+    Returns a path to the specified file name, of the specified type,
+    as built by Xcode.
+
+    Built files are in the subdirectory 'build/{configuration}'.
+    The default is 'build/Default'.
+
+    A chdir= keyword argument specifies the source directory
+    relative to which  the output subdirectory can be found.
+
+    "type" values of STATIC_LIB or SHARED_LIB append the necessary
+    prefixes and suffixes to a platform-independent library base name.
+    """
+    result = []
+    chdir = kw.get('chdir')
+    if chdir:
+      result.append(chdir)
+    configuration = self.configuration_dirname()
+    result.extend(['build', configuration])
+    result.append(self.built_file_basename(name, type, **kw))
+    return self.workpath(*result)
+
+
+format_class_list = [
+  TestGypGypd,
+  TestGypAndroid,
+  TestGypCMake,
+  TestGypMake,
+  TestGypMSVS,
+  TestGypMSVSNinja,
+  TestGypNinja,
+  TestGypXcode,
+]
+
+def TestGyp(*args, **kw):
+  """
+  Returns an appropriate TestGyp* instance for a specified GYP format.
+  """
+  format = kw.pop('format', os.environ.get('TESTGYP_FORMAT'))
+  for format_class in format_class_list:
+    if format == format_class.format:
+      return format_class(*args, **kw)
+  raise Exception, "unknown format %r" % format
diff --git a/gyp/test/lib/TestMac.py b/gyp/test/lib/TestMac.py
new file mode 100644 (file)
index 0000000..68605d7
--- /dev/null
@@ -0,0 +1,73 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+TestMac.py:  a collection of helper function shared between test on Mac OS X.
+"""
+
+import re
+import subprocess
+
+__all__ = ['Xcode', 'CheckFileType']
+
+
+def CheckFileType(test, file, archs):
+  """Check that |file| contains exactly |archs| or fails |test|."""
+  proc = subprocess.Popen(['lipo', '-info', file], stdout=subprocess.PIPE)
+  o = proc.communicate()[0].strip()
+  assert not proc.returncode
+  if len(archs) == 1:
+    pattern = re.compile('^Non-fat file: (.*) is architecture: (.*)$')
+  else:
+    pattern = re.compile('^Architectures in the fat file: (.*) are: (.*)$')
+  match = pattern.match(o)
+  if match is None:
+    print 'Ouput does not match expected pattern: %s' % (pattern.pattern)
+    test.fail_test()
+  else:
+    found_file, found_archs = match.groups()
+    if found_file != file or set(found_archs.split()) != set(archs):
+      print 'Expected file %s with arch %s, got %s with arch %s' % (
+          file, ' '.join(archs), found_file, found_archs)
+      test.fail_test()
+
+
+class XcodeInfo(object):
+  """Simplify access to Xcode informations."""
+
+  def __init__(self):
+    self._cache = {}
+
+  def _XcodeVersion(self):
+    lines = subprocess.check_output(['xcodebuild', '-version']).splitlines()
+    version = ''.join(lines[0].split()[-1].split('.'))
+    version = (version + '0' * (3 - len(version))).zfill(4)
+    return version, lines[-1].split()[-1]
+
+  def Version(self):
+    if 'Version' not in self._cache:
+      self._cache['Version'], self._cache['Build'] = self._XcodeVersion()
+    return self._cache['Version']
+
+  def Build(self):
+    if 'Build' not in self._cache:
+      self._cache['Version'], self._cache['Build'] = self._XcodeVersion()
+    return self._cache['Build']
+
+  def SDKBuild(self):
+    if 'SDKBuild' not in self._cache:
+      self._cache['SDKBuild'] = subprocess.check_output(
+          ['xcodebuild', '-version', '-sdk', '', 'ProductBuildVersion'])
+      self._cache['SDKBuild'] = self._cache['SDKBuild'].rstrip('\n')
+    return self._cache['SDKBuild']
+
+  def SDKVersion(self):
+    if 'SDKVersion' not in self._cache:
+      self._cache['SDKVersion'] = subprocess.check_output(
+          ['xcodebuild', '-version', '-sdk', '', 'SDKVersion'])
+      self._cache['SDKVersion'] = self._cache['SDKVersion'].rstrip('\n')
+    return self._cache['SDKVersion']
+
+
+Xcode = XcodeInfo()
diff --git a/gyp/test/lib/TestWin.py b/gyp/test/lib/TestWin.py
new file mode 100644 (file)
index 0000000..1571c85
--- /dev/null
@@ -0,0 +1,101 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+TestWin.py:  a collection of helpers for testing on Windows.
+"""
+
+import errno
+import os
+import re
+import sys
+import subprocess
+
+class Registry(object):
+  def _QueryBase(self, sysdir, key, value):
+    """Use reg.exe to read a particular key.
+
+    While ideally we might use the win32 module, we would like gyp to be
+    python neutral, so for instance cygwin python lacks this module.
+
+    Arguments:
+      sysdir: The system subdirectory to attempt to launch reg.exe from.
+      key: The registry key to read from.
+      value: The particular value to read.
+    Return:
+      stdout from reg.exe, or None for failure.
+    """
+    # Skip if not on Windows or Python Win32 setup issue
+    if sys.platform not in ('win32', 'cygwin'):
+      return None
+    # Setup params to pass to and attempt to launch reg.exe
+    cmd = [os.path.join(os.environ.get('WINDIR', ''), sysdir, 'reg.exe'),
+           'query', key]
+    if value:
+      cmd.extend(['/v', value])
+    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    # Get the stdout from reg.exe, reading to the end so p.returncode is valid
+    # Note that the error text may be in [1] in some cases
+    text = p.communicate()[0]
+    # Check return code from reg.exe; officially 0==success and 1==error
+    if p.returncode:
+      return None
+    return text
+
+  def Query(self, key, value=None):
+    """Use reg.exe to read a particular key through _QueryBase.
+
+    First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If
+    that fails, it falls back to System32.  Sysnative is available on Vista and
+    up and available on Windows Server 2003 and XP through KB patch 942589. Note
+    that Sysnative will always fail if using 64-bit python due to it being a
+    virtual directory and System32 will work correctly in the first place.
+
+    KB 942589 - http://support.microsoft.com/kb/942589/en-us.
+
+    Arguments:
+      key: The registry key.
+      value: The particular registry value to read (optional).
+    Return:
+      stdout from reg.exe, or None for failure.
+    """
+    text = None
+    try:
+      text = self._QueryBase('Sysnative', key, value)
+    except OSError, e:
+      if e.errno == errno.ENOENT:
+        text = self._QueryBase('System32', key, value)
+      else:
+        raise
+    return text
+
+  def GetValue(self, key, value):
+    """Use reg.exe to obtain the value of a registry key.
+
+    Args:
+      key: The registry key.
+      value: The particular registry value to read.
+    Return:
+      contents of the registry key's value, or None on failure.
+    """
+    text = self.Query(key, value)
+    if not text:
+      return None
+    # Extract value.
+    match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text)
+    if not match:
+      return None
+    return match.group(1)
+
+  def KeyExists(self, key):
+    """Use reg.exe to see if a key exists.
+
+    Args:
+      key: The registry key to check.
+    Return:
+      True if the key exists
+    """
+    if not self.Query(key):
+      return False
+    return True
diff --git a/gyp/test/library/gyptest-shared-obj-install-path.py b/gyp/test/library/gyptest-shared-obj-install-path.py
new file mode 100755 (executable)
index 0000000..04f32e5
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that .so files that are order only dependencies are specified by
+their install location rather than by their alias.
+"""
+
+# Python 2.5 needs this for the with statement.
+from __future__ import with_statement
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['make'])
+
+test.run_gyp('shared_dependency.gyp',
+             chdir='src')
+test.relocate('src', 'relocate/src')
+
+test.build('shared_dependency.gyp', test.ALL, chdir='relocate/src')
+
+if test.format=='android':
+  makefile_path = 'relocate/src/GypAndroid.mk'
+else:
+  makefile_path = 'relocate/src/Makefile'
+
+with open(makefile_path) as makefile:
+  make_contents = makefile.read()
+
+# If we remove the code to generate lib1, Make should still be able
+# to build lib2 since lib1.so already exists.
+make_contents = make_contents.replace('include lib1.target.mk', '')
+with open(makefile_path, 'w') as makefile:
+  makefile.write(make_contents)
+
+test.build('shared_dependency.gyp', test.ALL, chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/library/gyptest-shared.py b/gyp/test/library/gyptest-shared.py
new file mode 100755 (executable)
index 0000000..b30b50c
--- /dev/null
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple build of a "Hello, world!" program with shared libraries,
+including verifying that libraries are rebuilt correctly when functions
+move between libraries.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+if test.format == 'android':
+  # This test currently fails on android. Investigate why, fix the issues
+  # responsible, and reenable this test on android. See bug:
+  # https://code.google.com/p/gyp/issues/detail?id=436
+  test.skip_test(message='Test fails on android. Fix and reenable.\n')
+
+test.run_gyp('library.gyp',
+             '-Dlibrary=shared_library',
+             '-Dmoveable_function=lib1',
+             chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib1_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.run_gyp('library.gyp',
+             '-Dlibrary=shared_library',
+             '-Dmoveable_function=lib2',
+             chdir='relocate/src')
+
+# Update program.c to force a rebuild.
+test.sleep()
+contents = test.read('relocate/src/program.c')
+contents = contents.replace('Hello', 'Hello again')
+test.write('relocate/src/program.c', contents)
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello again from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib2_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.run_gyp('library.gyp',
+             '-Dlibrary=shared_library',
+             '-Dmoveable_function=lib1',
+             chdir='relocate/src')
+
+# Update program.c to force a rebuild.
+test.sleep()
+contents = test.read('relocate/src/program.c')
+contents = contents.replace('again', 'again again')
+test.write('relocate/src/program.c', contents)
+
+# TODO(sgk):  we have to force a rebuild of lib2 so that it weeds out
+# the "moved" module.  This should be done in gyp by adding a dependency
+# on the generated .vcproj file itself.
+test.touch('relocate/src/lib2.c')
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello again again from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib1_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.pass_test()
diff --git a/gyp/test/library/gyptest-static.py b/gyp/test/library/gyptest-static.py
new file mode 100755 (executable)
index 0000000..27d8aa3
--- /dev/null
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple build of a "Hello, world!" program with static libraries,
+including verifying that libraries are rebuilt correctly when functions
+move between libraries.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+if test.format == 'android':
+  # This test currently fails on android. Investigate why, fix the issues
+  # responsible, and reenable this test on android. See bug:
+  # https://code.google.com/p/gyp/issues/detail?id=436
+  test.skip_test(message='Test fails on android. Fix and reenable.\n')
+
+test.run_gyp('library.gyp',
+             '-Dlibrary=static_library',
+             '-Dmoveable_function=lib1',
+             chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib1_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.run_gyp('library.gyp',
+             '-Dlibrary=static_library',
+             '-Dmoveable_function=lib2',
+             chdir='relocate/src')
+
+# Update program.c to force a rebuild.
+test.sleep()
+contents = test.read('relocate/src/program.c')
+contents = contents.replace('Hello', 'Hello again')
+test.write('relocate/src/program.c', contents)
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello again from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib2_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.run_gyp('library.gyp',
+             '-Dlibrary=static_library',
+             '-Dmoveable_function=lib1',
+             chdir='relocate/src')
+
+# Update program.c and lib2.c to force a rebuild.
+test.sleep()
+contents = test.read('relocate/src/program.c')
+contents = contents.replace('again', 'again again')
+test.write('relocate/src/program.c', contents)
+
+# TODO(sgk):  we have to force a rebuild of lib2 so that it weeds out
+# the "moved" module.  This should be done in gyp by adding a dependency
+# on the generated .vcproj file itself.
+test.touch('relocate/src/lib2.c')
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello again again from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib1_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.pass_test()
diff --git a/gyp/test/library/src/lib1.c b/gyp/test/library/src/lib1.c
new file mode 100644 (file)
index 0000000..3866b1b
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void lib1_function(void)
+{
+  fprintf(stdout, "Hello from lib1.c\n");
+  fflush(stdout);
+}
diff --git a/gyp/test/library/src/lib1_moveable.c b/gyp/test/library/src/lib1_moveable.c
new file mode 100644 (file)
index 0000000..5d3cc1d
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void moveable_function(void)
+{
+  fprintf(stdout, "Hello from lib1_moveable.c\n");
+  fflush(stdout);
+}
diff --git a/gyp/test/library/src/lib2.c b/gyp/test/library/src/lib2.c
new file mode 100644 (file)
index 0000000..21dda72
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void lib2_function(void)
+{
+  fprintf(stdout, "Hello from lib2.c\n");
+  fflush(stdout);
+}
diff --git a/gyp/test/library/src/lib2_moveable.c b/gyp/test/library/src/lib2_moveable.c
new file mode 100644 (file)
index 0000000..f645071
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void moveable_function(void)
+{
+  fprintf(stdout, "Hello from lib2_moveable.c\n");
+  fflush(stdout);
+}
diff --git a/gyp/test/library/src/library.gyp b/gyp/test/library/src/library.gyp
new file mode 100644 (file)
index 0000000..bc35516
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'moveable_function%': 0,
+  },
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'dependencies': [
+        'lib1',
+        'lib2',
+      ],
+      'sources': [
+        'program.c',
+      ],
+    },
+    {
+      'target_name': 'lib1',
+      'type': '<(library)',
+      'sources': [
+        'lib1.c',
+      ],
+      'conditions': [
+        ['moveable_function=="lib1"', {
+          'sources': [
+            'lib1_moveable.c',
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'lib2',
+      'type': '<(library)',
+      'sources': [
+        'lib2.c',
+      ],
+      'conditions': [
+        ['moveable_function=="lib2"', {
+          'sources': [
+            'lib2_moveable.c',
+          ],
+        }],
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="linux"', {
+      'target_defaults': {
+        # Support 64-bit shared libs (also works fine for 32-bit).
+        'cflags': ['-fPIC'],
+      },
+    }],
+  ],
+}
diff --git a/gyp/test/library/src/program.c b/gyp/test/library/src/program.c
new file mode 100644 (file)
index 0000000..d460f60
--- /dev/null
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+extern void lib1_function(void);
+extern void lib2_function(void);
+extern void moveable_function(void);
+
+int main(void)
+{
+  fprintf(stdout, "Hello from program.c\n");
+  fflush(stdout);
+  lib1_function();
+  lib2_function();
+  moveable_function();
+  return 0;
+}
diff --git a/gyp/test/library/src/shared_dependency.gyp b/gyp/test/library/src/shared_dependency.gyp
new file mode 100644 (file)
index 0000000..7d29f5d
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'lib1',
+      'type': 'shared_library',
+      'sources': [
+        'lib1.c',
+      ],
+    },
+    {
+      'target_name': 'lib2',
+      'type': 'shared_library',
+      'sources': [
+        'lib2.c',
+      ],
+      'dependencies': [
+        'lib1',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="linux"', {
+      'target_defaults': {
+        # Support 64-bit shared libs (also works fine for 32-bit).
+        'cflags': ['-fPIC'],
+      },
+    }],
+  ],
+}
diff --git a/gyp/test/library_dirs/gyptest-library-dirs.py b/gyp/test/library_dirs/gyptest-library-dirs.py
new file mode 100644 (file)
index 0000000..5edd6e7
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies library_dirs (in link_settings) are properly found.
+"""
+
+import sys
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['!android'])
+
+lib_dir = test.tempdir('secret_location')
+
+test.run_gyp('test.gyp',
+             '-D', 'abs_path_to_secret_library_location={0}'.format(lib_dir),
+             chdir='subdir')
+
+# Must build each target independently, since they are not in each others'
+# 'dependencies' (test.ALL does NOT work here for some builders, and in any case
+# would not ensure the correct ordering).
+test.build('test.gyp', 'mylib', chdir='subdir')
+test.build('test.gyp', 'libraries-search-path-test', chdir='subdir')
+
+expect = """Hello world
+"""
+test.run_built_executable(
+    'libraries-search-path-test', chdir='subdir', stdout=expect)
+
+if sys.platform in ('win32', 'cygwin'):
+  test.run_gyp('test-win.gyp',
+               '-D',
+               'abs_path_to_secret_library_location={0}'.format(lib_dir),
+               chdir='subdir')
+
+  test.build('test.gyp', 'mylib', chdir='subdir')
+  test.build('test-win.gyp',
+             'libraries-search-path-test-lib-suffix',
+             chdir='subdir')
+
+  test.run_built_executable(
+        'libraries-search-path-test-lib-suffix', chdir='subdir', stdout=expect)
+
+
+test.pass_test()
+test.cleanup()
diff --git a/gyp/test/library_dirs/subdir/README.txt b/gyp/test/library_dirs/subdir/README.txt
new file mode 100644 (file)
index 0000000..4031ded
--- /dev/null
@@ -0,0 +1 @@
+Make things live in a subdirectory, to make sure that DEPTH works correctly.
diff --git a/gyp/test/library_dirs/subdir/hello.cc b/gyp/test/library_dirs/subdir/hello.cc
new file mode 100644 (file)
index 0000000..5dbbd48
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iostream>
+#include "mylib.h"
+
+int main() {
+  std::cout << "Hello " << my_foo(99) << std::endl;
+  return 0;
+}
diff --git a/gyp/test/library_dirs/subdir/mylib.cc b/gyp/test/library_dirs/subdir/mylib.cc
new file mode 100644 (file)
index 0000000..654f3d0
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mylib.h"
+
+std::string my_foo(int x) {
+  return std::string("world");
+}
diff --git a/gyp/test/library_dirs/subdir/mylib.h b/gyp/test/library_dirs/subdir/mylib.h
new file mode 100644 (file)
index 0000000..84b4022
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TEST_LIBRARY_DIRS_SUBDIR_MYLIB_H
+#define TEST_LIBRARY_DIRS_SUBDIR_MYLIB_H
+
+#include <string>
+
+std::string my_foo(int);
+
+#endif  // TEST_LIBRARY_DIRS_SUBDIR_MYLIB_H
diff --git a/gyp/test/library_dirs/subdir/test-win.gyp b/gyp/test/library_dirs/subdir/test-win.gyp
new file mode 100644 (file)
index 0000000..033b6f7
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      # This creates a static library and puts it in a nonstandard location for
+      # libraries-search-path-test.
+      'target_name': 'mylib',
+      'type': 'static_library',
+      'standalone_static_library': 1,
+      # This directory is NOT in the default library search locations. It also
+      # MUST be passed in on the gyp command line:
+      #
+      #  -D abs_path_to_secret_library_location=/some_absolute_path
+      #
+      # The gyptest itself (../gyptest-library-dirs.py) provides this.
+      'product_dir': '<(abs_path_to_secret_library_location)',
+      'sources': [
+        'mylib.cc',
+      ],
+    },
+    {
+      'target_name': 'libraries-search-path-test-lib-suffix',
+      'type': 'executable',
+      'dependencies': [
+        # It is important to NOT list the mylib as a dependency here, because
+        # some build systems will track it down based on its product_dir,
+        # such that the link succeeds even without the library_dirs below.
+        #
+        # The point of this weird structuring is to ensure that 'library_dirs'
+        # works as advertised, such that just '-lmylib' (or its equivalent)
+        # works based on the directories that library_dirs puts in the library
+        # link path.
+        #
+        # If 'mylib' was listed as a proper dependency here, the build system
+        # would find it and link with its path on disk.
+        #
+        # Note that this implies 'mylib' must already be built when building
+        # 'libraries-search-path-test' (see ../gyptest-library-dirs.py).
+        #
+        #'mylib',
+      ],
+      'sources': [
+        'hello.cc',
+      ],
+      # Note that without this, the mylib library would not be found and
+      # successfully linked.
+      'library_dirs': [
+        '<(abs_path_to_secret_library_location)',
+      ],
+      'link_settings': {
+        'libraries': [
+          '-lmylib.lib',
+        ],
+      },
+    },
+  ],
+}
diff --git a/gyp/test/library_dirs/subdir/test.gyp b/gyp/test/library_dirs/subdir/test.gyp
new file mode 100644 (file)
index 0000000..f83d7f2
--- /dev/null
@@ -0,0 +1,68 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      # This creates a static library and puts it in a nonstandard location for
+      # libraries-search-path-test.
+      'target_name': 'mylib',
+      'type': 'static_library',
+      'standalone_static_library': 1,
+      # This directory is NOT in the default library search locations. It also
+      # MUST be passed in on the gyp command line:
+      #
+      #  -D abs_path_to_secret_library_location=/some_absolute_path
+      #
+      # The gyptest itself (../gyptest-library-dirs.py) provides this.
+      'product_dir': '<(abs_path_to_secret_library_location)',
+      'sources': [
+        'mylib.cc',
+      ],
+    },
+    {
+      'target_name': 'libraries-search-path-test',
+      'type': 'executable',
+      'dependencies': [
+        # It is important to NOT list the mylib as a dependency here, because
+        # some build systems will track it down based on its product_dir,
+        # such that the link succeeds even without the library_dirs below.
+        #
+        # The point of this weird structuring is to ensure that 'library_dirs'
+        # works as advertised, such that just '-lmylib' (or its equivalent)
+        # works based on the directories that library_dirs puts in the library
+        # link path.
+        #
+        # If 'mylib' was listed as a proper dependency here, the build system
+        # would find it and link with its path on disk.
+        #
+        # Note that this implies 'mylib' must already be built when building
+        # 'libraries-search-path-test' (see ../gyptest-library-dirs.py).
+        #
+        #'mylib',
+      ],
+      'sources': [
+        'hello.cc',
+      ],
+      # Note that without this, the mylib library would not be found and
+      # successfully linked.
+      'library_dirs': [
+        '<(abs_path_to_secret_library_location)',
+      ],
+      'link_settings': {
+        'conditions': [
+          ['OS=="linux"', {
+            'libraries': [
+              '-lmylib',
+            ],
+          }, { # else
+            'libraries': [
+              '<(STATIC_LIB_PREFIX)mylib<(STATIC_LIB_SUFFIX)',
+            ],
+          }],
+        ],  # conditions
+      },
+    },
+  ],
+}
diff --git a/gyp/test/link-dependency/gyptest-link-dependency.py b/gyp/test/link-dependency/gyptest-link-dependency.py
new file mode 100755 (executable)
index 0000000..3a8300d
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that a target marked as 'link_dependency==1' isn't being pulled into
+the 'none' target's dependency (which would otherwise lead to a dependency
+cycle in ninja).
+"""
+
+import TestGyp
+
+# See https://codereview.chromium.org/177043010/#msg15 for why this doesn't
+# work with cmake.
+test = TestGyp.TestGyp(formats=['!cmake'])
+
+test.run_gyp('test.gyp')
+test.build('test.gyp', 'main')
+
+# If running gyp worked, all is well.
+test.pass_test()
diff --git a/gyp/test/link-dependency/main.c b/gyp/test/link-dependency/main.c
new file mode 100644 (file)
index 0000000..543d8b6
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <stdlib.h>
+int main() {
+  void *p = malloc(1);
+  printf("p: %p\n", p);
+  return 0;
+}
diff --git a/gyp/test/link-dependency/mymalloc.c b/gyp/test/link-dependency/mymalloc.c
new file mode 100644 (file)
index 0000000..f80bc02
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+
+// The windows ninja generator is expecting an import library to get generated,
+// but it doesn't if there are no exports.
+#ifdef _MSC_VER
+__declspec(dllexport) void foo() {}
+#endif
+
+void *malloc(size_t size) {
+  (void)size;
+  return (void*)0xdeadbeef;
+}
diff --git a/gyp/test/link-dependency/test.gyp b/gyp/test/link-dependency/test.gyp
new file mode 100644 (file)
index 0000000..47cec15
--- /dev/null
@@ -0,0 +1,37 @@
+{
+  'variables': {
+    'custom_malloc%' : 1,
+  },
+  'target_defaults': {
+    'conditions': [
+      ['custom_malloc==1', {
+        'dependencies': [
+          'malloc',
+        ],
+      }],
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'main',
+      'type': 'none',
+      'dependencies': [ 'main_initial',],
+    },
+    {
+      'target_name': 'main_initial',
+      'type': 'executable',
+      'product_name': 'main',
+      'sources': [ 'main.c' ],
+    },
+    {
+      'target_name': 'malloc',
+      'type': 'shared_library',
+      'variables': {
+        'prune_self_dependency': 1,
+        # Targets with type 'none' won't depend on this target.
+        'link_dependency': 1,
+      },  
+      'sources': [ 'mymalloc.c' ],
+    },
+  ],
+}
diff --git a/gyp/test/link-objects/base.c b/gyp/test/link-objects/base.c
new file mode 100644 (file)
index 0000000..3327459
--- /dev/null
@@ -0,0 +1,6 @@
+void extra();
+
+int main(void) {
+  extra();
+  return 0;
+}
diff --git a/gyp/test/link-objects/extra.c b/gyp/test/link-objects/extra.c
new file mode 100644 (file)
index 0000000..1d7ee09
--- /dev/null
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+void extra() {
+  printf("PASS\n");
+}
diff --git a/gyp/test/link-objects/gyptest-all.py b/gyp/test/link-objects/gyptest-all.py
new file mode 100755 (executable)
index 0000000..45bd6e1
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Put an object file on the sources list.
+Expect the result to link ok.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform != 'darwin':
+  # Currently only works under the linux make build.
+  test = TestGyp.TestGyp(formats=['make'])
+
+  test.run_gyp('link-objects.gyp')
+
+  test.build('link-objects.gyp', test.ALL)
+
+  test.run_built_executable('link-objects', stdout="PASS\n")
+
+  test.up_to_date('link-objects.gyp', test.ALL)
+
+  test.pass_test()
diff --git a/gyp/test/link-objects/link-objects.gyp b/gyp/test/link-objects/link-objects.gyp
new file mode 100644 (file)
index 0000000..ab72855
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'link-objects',
+      'type': 'executable',
+      'actions': [
+        {
+          'action_name': 'build extra object',
+          'inputs': ['extra.c'],
+          'outputs': ['extra.o'],
+          'action': ['gcc', '-o', 'extra.o', '-c', 'extra.c'],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+      'sources': [
+        'base.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/linux/gyptest-implicit-rpath.py b/gyp/test/linux/gyptest-implicit-rpath.py
new file mode 100644 (file)
index 0000000..dd7718c
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that the implicit rpath is added only when needed.
+"""
+
+import TestGyp
+
+import re
+import subprocess
+import sys
+
+if sys.platform.startswith('linux'):
+  test = TestGyp.TestGyp(formats=['ninja', 'make'])
+
+  CHDIR = 'implicit-rpath'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+  def GetRpaths(p):
+    p = test.built_file_path(p, chdir=CHDIR)
+    r = re.compile(r'Library rpath: \[([^\]]+)\]')
+    proc = subprocess.Popen(['readelf', '-d', p], stdout=subprocess.PIPE)
+    o = proc.communicate()[0]
+    assert not proc.returncode
+    return r.findall(o)
+
+  if test.format == 'ninja':
+    expect = '$ORIGIN/lib/'
+  elif test.format == 'make':
+    expect = '$ORIGIN/lib.target/'
+  else:
+    test.fail_test()
+
+  if GetRpaths('shared_executable') != [expect]:
+    test.fail_test()
+
+  if GetRpaths('shared_executable_no_so_suffix') != [expect]:
+    test.fail_test()
+
+  if GetRpaths('static_executable'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/linux/implicit-rpath/file.c b/gyp/test/linux/implicit-rpath/file.c
new file mode 100644 (file)
index 0000000..56757a7
--- /dev/null
@@ -0,0 +1 @@
+void f() {}
diff --git a/gyp/test/linux/implicit-rpath/main.c b/gyp/test/linux/implicit-rpath/main.c
new file mode 100644 (file)
index 0000000..237c8ce
--- /dev/null
@@ -0,0 +1 @@
+int main() {}
diff --git a/gyp/test/linux/implicit-rpath/test.gyp b/gyp/test/linux/implicit-rpath/test.gyp
new file mode 100644 (file)
index 0000000..b546106
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'shared',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+    },
+    {
+      'target_name': 'shared_no_so_suffix',
+      'product_extension': 'so.0.1',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+    },
+    {
+      'target_name': 'static',
+      'type': 'static_library',
+      'sources': [ 'file.c' ],
+    },
+    {
+      'target_name': 'shared_executable',
+      'type': 'executable',
+      'sources': [ 'main.c' ],
+      'dependencies': [
+        'shared',
+      ]
+    },
+    {
+      'target_name': 'shared_executable_no_so_suffix',
+      'type': 'executable',
+      'sources': [ 'main.c' ],
+      'dependencies': [
+        'shared_no_so_suffix',
+      ]
+    },
+    {
+      'target_name': 'static_executable',
+      'type': 'executable',
+      'sources': [ 'main.c' ],
+      'dependencies': [
+        'static',
+      ]
+    },
+  ],
+}
diff --git a/gyp/test/mac/action-envvars/action/action.gyp b/gyp/test/mac/action-envvars/action/action.gyp
new file mode 100644 (file)
index 0000000..d9d6574
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'action',
+      'type': 'none',
+      'actions': [
+        {
+          'inputs': [ ],
+          'outputs': [
+            '<(PRODUCT_DIR)/result',
+            '<(SHARED_INTERMEDIATE_DIR)/tempfile',
+          ],
+          'action_name': 'Test action',
+          'action': ['./action.sh', '<(SHARED_INTERMEDIATE_DIR)/tempfile' ],
+        },
+        {
+          'inputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/tempfile',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/other_result',
+          ],
+          'action_name': 'Other test action',
+          'action': ['cp', '<(SHARED_INTERMEDIATE_DIR)/tempfile',
+                           '<(PRODUCT_DIR)/other_result' ],
+        },
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/action-envvars/action/action.sh b/gyp/test/mac/action-envvars/action/action.sh
new file mode 100755 (executable)
index 0000000..48d5f6b
--- /dev/null
@@ -0,0 +1,8 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+echo 'Test output' > "${BUILT_PRODUCTS_DIR}/result"
+echo 'Other output' > "$1"
diff --git a/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist-error.strings b/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist-error.strings
new file mode 100644 (file)
index 0000000..452e7fa
--- /dev/null
@@ -0,0 +1,3 @@
+/* Localized versions of Info.plist keys */
+
+NSHumanReadableCopyright = "Copyright Â©2011 Google Inc."
diff --git a/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist.strings b/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist.strings
new file mode 100644 (file)
index 0000000..35bd33a
--- /dev/null
@@ -0,0 +1,3 @@
+/* Localized versions of Info.plist keys */
+
+NSHumanReadableCopyright = "Copyright Â©2011 Google Inc.";
diff --git a/gyp/test/mac/app-bundle/TestApp/English.lproj/MainMenu.xib b/gyp/test/mac/app-bundle/TestApp/English.lproj/MainMenu.xib
new file mode 100644 (file)
index 0000000..4524596
--- /dev/null
@@ -0,0 +1,4119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
+       <data>
+               <int key="IBDocument.SystemTarget">1060</int>
+               <string key="IBDocument.SystemVersion">10A324</string>
+               <string key="IBDocument.InterfaceBuilderVersion">719</string>
+               <string key="IBDocument.AppKitVersion">1015</string>
+               <string key="IBDocument.HIToolboxVersion">418.00</string>
+               <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+                       <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+                       <string key="NS.object.0">719</string>
+               </object>
+               <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+                       <bool key="EncodedWithXMLCoder">YES</bool>
+                       <integer value="371"/>
+                       <integer value="29"/>
+               </object>
+               <object class="NSArray" key="IBDocument.PluginDependencies">
+                       <bool key="EncodedWithXMLCoder">YES</bool>
+                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+               </object>
+               <object class="NSMutableDictionary" key="IBDocument.Metadata">
+                       <bool key="EncodedWithXMLCoder">YES</bool>
+                       <object class="NSArray" key="dict.sortedKeys" id="0">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                       </object>
+                       <object class="NSMutableArray" key="dict.values">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                       </object>
+               </object>
+               <object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
+                       <bool key="EncodedWithXMLCoder">YES</bool>
+                       <object class="NSCustomObject" id="1021">
+                               <string key="NSClassName">NSApplication</string>
+                       </object>
+                       <object class="NSCustomObject" id="1014">
+                               <string key="NSClassName">FirstResponder</string>
+                       </object>
+                       <object class="NSCustomObject" id="1050">
+                               <string key="NSClassName">NSApplication</string>
+                       </object>
+                       <object class="NSMenu" id="649796088">
+                               <string key="NSTitle">AMainMenu</string>
+                               <object class="NSMutableArray" key="NSMenuItems">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                       <object class="NSMenuItem" id="694149608">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">TestApp</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSKeyEquivModMask">1048576</int>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <object class="NSCustomResource" key="NSOnImage" id="35465992">
+                                                       <string key="NSClassName">NSImage</string>
+                                                       <string key="NSResourceName">NSMenuCheckmark</string>
+                                               </object>
+                                               <object class="NSCustomResource" key="NSMixedImage" id="502551668">
+                                                       <string key="NSClassName">NSImage</string>
+                                                       <string key="NSResourceName">NSMenuMixedState</string>
+                                               </object>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="110575045">
+                                                       <string key="NSTitle">TestApp</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="238522557">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">About TestApp</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="304266470">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="609285721">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Preferences…</string>
+                                                                       <string key="NSKeyEquiv">,</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="481834944">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1046388886">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Services</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="752062318">
+                                                                               <string key="NSTitle">Services</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                               </object>
+                                                                               <string key="NSName">_NSServicesMenu</string>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="646227648">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="755159360">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Hide TestApp</string>
+                                                                       <string key="NSKeyEquiv">h</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="342932134">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Hide Others</string>
+                                                                       <string key="NSKeyEquiv">h</string>
+                                                                       <int key="NSKeyEquivModMask">1572864</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="908899353">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Show All</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1056857174">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="632727374">
+                                                                       <reference key="NSMenu" ref="110575045"/>
+                                                                       <string key="NSTitle">Quit TestApp</string>
+                                                                       <string key="NSKeyEquiv">q</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                       </object>
+                                                       <string key="NSName">_NSAppleMenu</string>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="379814623">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">File</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSKeyEquivModMask">1048576</int>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="720053764">
+                                                       <string key="NSTitle">File</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="705341025">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">New</string>
+                                                                       <string key="NSKeyEquiv">n</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="722745758">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Open…</string>
+                                                                       <string key="NSKeyEquiv">o</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1025936716">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Open Recent</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="1065607017">
+                                                                               <string key="NSTitle">Open Recent</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="759406840">
+                                                                                               <reference key="NSMenu" ref="1065607017"/>
+                                                                                               <string key="NSTitle">Clear Menu</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                               <string key="NSName">_NSRecentDocumentsMenu</string>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="425164168">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="776162233">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Close</string>
+                                                                       <string key="NSKeyEquiv">w</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1023925487">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Save</string>
+                                                                       <string key="NSKeyEquiv">s</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="117038363">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Save As…</string>
+                                                                       <string key="NSKeyEquiv">S</string>
+                                                                       <int key="NSKeyEquivModMask">1179648</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="579971712">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Revert to Saved</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1010469920">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="294629803">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Page Setup...</string>
+                                                                       <string key="NSKeyEquiv">P</string>
+                                                                       <int key="NSKeyEquivModMask">1179648</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSToolTip"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="49223823">
+                                                                       <reference key="NSMenu" ref="720053764"/>
+                                                                       <string key="NSTitle">Print…</string>
+                                                                       <string key="NSKeyEquiv">p</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                       </object>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="952259628">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">Edit</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSKeyEquivModMask">1048576</int>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="789758025">
+                                                       <string key="NSTitle">Edit</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="1058277027">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Undo</string>
+                                                                       <string key="NSKeyEquiv">z</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="790794224">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Redo</string>
+                                                                       <string key="NSKeyEquiv">Z</string>
+                                                                       <int key="NSKeyEquivModMask">1179648</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="1040322652">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="296257095">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Cut</string>
+                                                                       <string key="NSKeyEquiv">x</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="860595796">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Copy</string>
+                                                                       <string key="NSKeyEquiv">c</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="29853731">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Paste</string>
+                                                                       <string key="NSKeyEquiv">v</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="82994268">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Paste and Match Style</string>
+                                                                       <string key="NSKeyEquiv">V</string>
+                                                                       <int key="NSKeyEquivModMask">1572864</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="437104165">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Delete</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="583158037">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Select All</string>
+                                                                       <string key="NSKeyEquiv">a</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="212016141">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="892235320">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Find</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="963351320">
+                                                                               <string key="NSTitle">Find</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="447796847">
+                                                                                               <reference key="NSMenu" ref="963351320"/>
+                                                                                               <string key="NSTitle">Find…</string>
+                                                                                               <string key="NSKeyEquiv">f</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">1</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="326711663">
+                                                                                               <reference key="NSMenu" ref="963351320"/>
+                                                                                               <string key="NSTitle">Find Next</string>
+                                                                                               <string key="NSKeyEquiv">g</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">2</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="270902937">
+                                                                                               <reference key="NSMenu" ref="963351320"/>
+                                                                                               <string key="NSTitle">Find Previous</string>
+                                                                                               <string key="NSKeyEquiv">G</string>
+                                                                                               <int key="NSKeyEquivModMask">1179648</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">3</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="159080638">
+                                                                                               <reference key="NSMenu" ref="963351320"/>
+                                                                                               <string key="NSTitle">Use Selection for Find</string>
+                                                                                               <string key="NSKeyEquiv">e</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">7</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="88285865">
+                                                                                               <reference key="NSMenu" ref="963351320"/>
+                                                                                               <string key="NSTitle">Jump to Selection</string>
+                                                                                               <string key="NSKeyEquiv">j</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="972420730">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Spelling and Grammar</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="769623530">
+                                                                               <string key="NSTitle">Spelling and Grammar</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="679648819">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <string key="NSTitle">Show Spelling and Grammar</string>
+                                                                                               <string key="NSKeyEquiv">:</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="96193923">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <string key="NSTitle">Check Document Now</string>
+                                                                                               <string key="NSKeyEquiv">;</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="859480356">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="948374510">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <string key="NSTitle">Check Spelling While Typing</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="967646866">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <string key="NSTitle">Check Grammar With Spelling</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="795346622">
+                                                                                               <reference key="NSMenu" ref="769623530"/>
+                                                                                               <string key="NSTitle">Correct Spelling Automatically</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="507821607">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Substitutions</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="698887838">
+                                                                               <string key="NSTitle">Substitutions</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="65139061">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Show Substitutions</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="19036812">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="605118523">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Smart Copy/Paste</string>
+                                                                                               <string key="NSKeyEquiv">f</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">1</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="197661976">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Smart Quotes</string>
+                                                                                               <string key="NSKeyEquiv">g</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">2</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="672708820">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Smart Dashes</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="708854459">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Smart Links</string>
+                                                                                               <string key="NSKeyEquiv">G</string>
+                                                                                               <int key="NSKeyEquivModMask">1179648</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">3</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="537092702">
+                                                                                               <reference key="NSMenu" ref="698887838"/>
+                                                                                               <string key="NSTitle">Text Replacement</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="288088188">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Transformations</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="579392910">
+                                                                               <string key="NSTitle">Transformations</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="1060694897">
+                                                                                               <reference key="NSMenu" ref="579392910"/>
+                                                                                               <string key="NSTitle">Make Upper Case</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="879586729">
+                                                                                               <reference key="NSMenu" ref="579392910"/>
+                                                                                               <string key="NSTitle">Make Lower Case</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="56570060">
+                                                                                               <reference key="NSMenu" ref="579392910"/>
+                                                                                               <string key="NSTitle">Capitalize</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="676164635">
+                                                                       <reference key="NSMenu" ref="789758025"/>
+                                                                       <string key="NSTitle">Speech</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="785027613">
+                                                                               <string key="NSTitle">Speech</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="731782645">
+                                                                                               <reference key="NSMenu" ref="785027613"/>
+                                                                                               <string key="NSTitle">Start Speaking</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="680220178">
+                                                                                               <reference key="NSMenu" ref="785027613"/>
+                                                                                               <string key="NSTitle">Stop Speaking</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                       </object>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="302598603">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">Format</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="941447902">
+                                                       <string key="NSTitle">Format</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="792887677">
+                                                                       <reference key="NSMenu" ref="941447902"/>
+                                                                       <string key="NSTitle">Font</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="786677654">
+                                                                               <string key="NSTitle">Font</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="159677712">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Show Fonts</string>
+                                                                                               <string key="NSKeyEquiv">t</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="305399458">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Bold</string>
+                                                                                               <string key="NSKeyEquiv">b</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">2</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="814362025">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Italic</string>
+                                                                                               <string key="NSKeyEquiv">i</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">1</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="330926929">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Underline</string>
+                                                                                               <string key="NSKeyEquiv">u</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="533507878">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="158063935">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Bigger</string>
+                                                                                               <string key="NSKeyEquiv">+</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">3</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="885547335">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Smaller</string>
+                                                                                               <string key="NSKeyEquiv">-</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <int key="NSTag">4</int>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="901062459">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="767671776">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Kern</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <string key="NSAction">submenuAction:</string>
+                                                                                               <object class="NSMenu" key="NSSubmenu" id="175441468">
+                                                                                                       <string key="NSTitle">Kern</string>
+                                                                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                                               <object class="NSMenuItem" id="252969304">
+                                                                                                                       <reference key="NSMenu" ref="175441468"/>
+                                                                                                                       <string key="NSTitle">Use Default</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="766922938">
+                                                                                                                       <reference key="NSMenu" ref="175441468"/>
+                                                                                                                       <string key="NSTitle">Use None</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="677519740">
+                                                                                                                       <reference key="NSMenu" ref="175441468"/>
+                                                                                                                       <string key="NSTitle">Tighten</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="238351151">
+                                                                                                                       <reference key="NSMenu" ref="175441468"/>
+                                                                                                                       <string key="NSTitle">Loosen</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                       </object>
+                                                                                               </object>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="691570813">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Ligature</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <string key="NSAction">submenuAction:</string>
+                                                                                               <object class="NSMenu" key="NSSubmenu" id="1058217995">
+                                                                                                       <string key="NSTitle">Ligature</string>
+                                                                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                                               <object class="NSMenuItem" id="706297211">
+                                                                                                                       <reference key="NSMenu" ref="1058217995"/>
+                                                                                                                       <string key="NSTitle">Use Default</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="568384683">
+                                                                                                                       <reference key="NSMenu" ref="1058217995"/>
+                                                                                                                       <string key="NSTitle">Use None</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="663508465">
+                                                                                                                       <reference key="NSMenu" ref="1058217995"/>
+                                                                                                                       <string key="NSTitle">Use All</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                       </object>
+                                                                                               </object>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="769124883">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Baseline</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <string key="NSAction">submenuAction:</string>
+                                                                                               <object class="NSMenu" key="NSSubmenu" id="18263474">
+                                                                                                       <string key="NSTitle">Baseline</string>
+                                                                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                                               <object class="NSMenuItem" id="257962622">
+                                                                                                                       <reference key="NSMenu" ref="18263474"/>
+                                                                                                                       <string key="NSTitle">Use Default</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="644725453">
+                                                                                                                       <reference key="NSMenu" ref="18263474"/>
+                                                                                                                       <string key="NSTitle">Superscript</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="1037576581">
+                                                                                                                       <reference key="NSMenu" ref="18263474"/>
+                                                                                                                       <string key="NSTitle">Subscript</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="941806246">
+                                                                                                                       <reference key="NSMenu" ref="18263474"/>
+                                                                                                                       <string key="NSTitle">Raise</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="1045724900">
+                                                                                                                       <reference key="NSMenu" ref="18263474"/>
+                                                                                                                       <string key="NSTitle">Lower</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                       </object>
+                                                                                               </object>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="739652853">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="1012600125">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Show Colors</string>
+                                                                                               <string key="NSKeyEquiv">C</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="214559597">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="596732606">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Copy Style</string>
+                                                                                               <string key="NSKeyEquiv">c</string>
+                                                                                               <int key="NSKeyEquivModMask">1572864</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="393423671">
+                                                                                               <reference key="NSMenu" ref="786677654"/>
+                                                                                               <string key="NSTitle">Paste Style</string>
+                                                                                               <string key="NSKeyEquiv">v</string>
+                                                                                               <int key="NSKeyEquivModMask">1572864</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                               <string key="NSName">_NSFontMenu</string>
+                                                                       </object>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="215659978">
+                                                                       <reference key="NSMenu" ref="941447902"/>
+                                                                       <string key="NSTitle">Text</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                       <string key="NSAction">submenuAction:</string>
+                                                                       <object class="NSMenu" key="NSSubmenu" id="446991534">
+                                                                               <string key="NSTitle">Text</string>
+                                                                               <object class="NSMutableArray" key="NSMenuItems">
+                                                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                       <object class="NSMenuItem" id="875092757">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Align Left</string>
+                                                                                               <string key="NSKeyEquiv">{</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="630155264">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Center</string>
+                                                                                               <string key="NSKeyEquiv">|</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="945678886">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Justify</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="512868991">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Align Right</string>
+                                                                                               <string key="NSKeyEquiv">}</string>
+                                                                                               <int key="NSKeyEquivModMask">1048576</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="163117631">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="31516759">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Writing Direction</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                               <string key="NSAction">submenuAction:</string>
+                                                                                               <object class="NSMenu" key="NSSubmenu" id="956096989">
+                                                                                                       <string key="NSTitle">Writing Direction</string>
+                                                                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                                                                               <object class="NSMenuItem" id="257099033">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                                                                       <string key="NSTitle">Paragraph</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="551969625">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="249532473">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="607364498">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="508151438">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                                                                       <string key="NSTitle"/>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="981751889">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                                                                       <string key="NSTitle">Selection</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="380031999">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="825984362">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                               <object class="NSMenuItem" id="560145579">
+                                                                                                                       <reference key="NSMenu" ref="956096989"/>
+                                                                                                                       <string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
+                                                                                                                       <string key="NSKeyEquiv"/>
+                                                                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                                                                               </object>
+                                                                                                       </object>
+                                                                                               </object>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="908105787">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <bool key="NSIsDisabled">YES</bool>
+                                                                                               <bool key="NSIsSeparator">YES</bool>
+                                                                                               <string key="NSTitle"/>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="644046920">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Show Ruler</string>
+                                                                                               <string key="NSKeyEquiv"/>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="231811626">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Copy Ruler</string>
+                                                                                               <string key="NSKeyEquiv">c</string>
+                                                                                               <int key="NSKeyEquivModMask">1310720</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                                       <object class="NSMenuItem" id="883618387">
+                                                                                               <reference key="NSMenu" ref="446991534"/>
+                                                                                               <string key="NSTitle">Paste Ruler</string>
+                                                                                               <string key="NSKeyEquiv">v</string>
+                                                                                               <int key="NSKeyEquivModMask">1310720</int>
+                                                                                               <int key="NSMnemonicLoc">2147483647</int>
+                                                                                               <reference key="NSOnImage" ref="35465992"/>
+                                                                                               <reference key="NSMixedImage" ref="502551668"/>
+                                                                                       </object>
+                                                                               </object>
+                                                                       </object>
+                                                               </object>
+                                                       </object>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="586577488">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">View</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSKeyEquivModMask">1048576</int>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="466310130">
+                                                       <string key="NSTitle">View</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="102151532">
+                                                                       <reference key="NSMenu" ref="466310130"/>
+                                                                       <string key="NSTitle">Show Toolbar</string>
+                                                                       <string key="NSKeyEquiv">t</string>
+                                                                       <int key="NSKeyEquivModMask">1572864</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="237841660">
+                                                                       <reference key="NSMenu" ref="466310130"/>
+                                                                       <string key="NSTitle">Customize Toolbar…</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                       </object>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="713487014">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">Window</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSKeyEquivModMask">1048576</int>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="835318025">
+                                                       <string key="NSTitle">Window</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="1011231497">
+                                                                       <reference key="NSMenu" ref="835318025"/>
+                                                                       <string key="NSTitle">Minimize</string>
+                                                                       <string key="NSKeyEquiv">m</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="575023229">
+                                                                       <reference key="NSMenu" ref="835318025"/>
+                                                                       <string key="NSTitle">Zoom</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="299356726">
+                                                                       <reference key="NSMenu" ref="835318025"/>
+                                                                       <bool key="NSIsDisabled">YES</bool>
+                                                                       <bool key="NSIsSeparator">YES</bool>
+                                                                       <string key="NSTitle"/>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                               <object class="NSMenuItem" id="625202149">
+                                                                       <reference key="NSMenu" ref="835318025"/>
+                                                                       <string key="NSTitle">Bring All to Front</string>
+                                                                       <string key="NSKeyEquiv"/>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                       </object>
+                                                       <string key="NSName">_NSWindowsMenu</string>
+                                               </object>
+                                       </object>
+                                       <object class="NSMenuItem" id="448692316">
+                                               <reference key="NSMenu" ref="649796088"/>
+                                               <string key="NSTitle">Help</string>
+                                               <string key="NSKeyEquiv"/>
+                                               <int key="NSMnemonicLoc">2147483647</int>
+                                               <reference key="NSOnImage" ref="35465992"/>
+                                               <reference key="NSMixedImage" ref="502551668"/>
+                                               <string key="NSAction">submenuAction:</string>
+                                               <object class="NSMenu" key="NSSubmenu" id="992780483">
+                                                       <string key="NSTitle">Help</string>
+                                                       <object class="NSMutableArray" key="NSMenuItems">
+                                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                                               <object class="NSMenuItem" id="105068016">
+                                                                       <reference key="NSMenu" ref="992780483"/>
+                                                                       <string key="NSTitle">TestApp Help</string>
+                                                                       <string key="NSKeyEquiv">?</string>
+                                                                       <int key="NSKeyEquivModMask">1048576</int>
+                                                                       <int key="NSMnemonicLoc">2147483647</int>
+                                                                       <reference key="NSOnImage" ref="35465992"/>
+                                                                       <reference key="NSMixedImage" ref="502551668"/>
+                                                               </object>
+                                                       </object>
+                                                       <string key="NSName">_NSHelpMenu</string>
+                                               </object>
+                                       </object>
+                               </object>
+                               <string key="NSName">_NSMainMenu</string>
+                       </object>
+                       <object class="NSWindowTemplate" id="972006081">
+                               <int key="NSWindowStyleMask">15</int>
+                               <int key="NSWindowBacking">2</int>
+                               <string key="NSWindowRect">{{335, 390}, {480, 360}}</string>
+                               <int key="NSWTFlags">1954021376</int>
+                               <string key="NSWindowTitle">TestApp</string>
+                               <string key="NSWindowClass">NSWindow</string>
+                               <nil key="NSViewClass"/>
+                               <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
+                               <object class="NSView" key="NSWindowView" id="439893737">
+                                       <reference key="NSNextResponder"/>
+                                       <int key="NSvFlags">256</int>
+                                       <string key="NSFrameSize">{480, 360}</string>
+                                       <reference key="NSSuperview"/>
+                               </object>
+                               <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
+                               <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
+                       </object>
+                       <object class="NSCustomObject" id="976324537">
+                               <string key="NSClassName">TestAppAppDelegate</string>
+                       </object>
+                       <object class="NSCustomObject" id="755631768">
+                               <string key="NSClassName">NSFontManager</string>
+                       </object>
+               </object>
+               <object class="IBObjectContainer" key="IBDocument.Objects">
+                       <object class="NSMutableArray" key="connectionRecords">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performMiniaturize:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1011231497"/>
+                                       </object>
+                                       <int key="connectionID">37</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">arrangeInFront:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="625202149"/>
+                                       </object>
+                                       <int key="connectionID">39</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">print:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="49223823"/>
+                                       </object>
+                                       <int key="connectionID">86</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">runPageLayout:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="294629803"/>
+                                       </object>
+                                       <int key="connectionID">87</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">clearRecentDocuments:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="759406840"/>
+                                       </object>
+                                       <int key="connectionID">127</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">orderFrontStandardAboutPanel:</string>
+                                               <reference key="source" ref="1021"/>
+                                               <reference key="destination" ref="238522557"/>
+                                       </object>
+                                       <int key="connectionID">142</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performClose:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="776162233"/>
+                                       </object>
+                                       <int key="connectionID">193</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleContinuousSpellChecking:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="948374510"/>
+                                       </object>
+                                       <int key="connectionID">222</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">undo:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1058277027"/>
+                                       </object>
+                                       <int key="connectionID">223</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">copy:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="860595796"/>
+                                       </object>
+                                       <int key="connectionID">224</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">checkSpelling:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="96193923"/>
+                                       </object>
+                                       <int key="connectionID">225</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">paste:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="29853731"/>
+                                       </object>
+                                       <int key="connectionID">226</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">stopSpeaking:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="680220178"/>
+                                       </object>
+                                       <int key="connectionID">227</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">cut:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="296257095"/>
+                                       </object>
+                                       <int key="connectionID">228</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">showGuessPanel:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="679648819"/>
+                                       </object>
+                                       <int key="connectionID">230</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">redo:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="790794224"/>
+                                       </object>
+                                       <int key="connectionID">231</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">selectAll:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="583158037"/>
+                                       </object>
+                                       <int key="connectionID">232</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">startSpeaking:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="731782645"/>
+                                       </object>
+                                       <int key="connectionID">233</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">delete:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="437104165"/>
+                                       </object>
+                                       <int key="connectionID">235</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performZoom:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="575023229"/>
+                                       </object>
+                                       <int key="connectionID">240</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performFindPanelAction:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="447796847"/>
+                                       </object>
+                                       <int key="connectionID">241</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">centerSelectionInVisibleArea:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="88285865"/>
+                                       </object>
+                                       <int key="connectionID">245</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleGrammarChecking:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="967646866"/>
+                                       </object>
+                                       <int key="connectionID">347</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleSmartInsertDelete:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="605118523"/>
+                                       </object>
+                                       <int key="connectionID">355</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleAutomaticQuoteSubstitution:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="197661976"/>
+                                       </object>
+                                       <int key="connectionID">356</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleAutomaticLinkDetection:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="708854459"/>
+                                       </object>
+                                       <int key="connectionID">357</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">saveDocument:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1023925487"/>
+                                       </object>
+                                       <int key="connectionID">362</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">saveDocumentAs:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="117038363"/>
+                                       </object>
+                                       <int key="connectionID">363</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">revertDocumentToSaved:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="579971712"/>
+                                       </object>
+                                       <int key="connectionID">364</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">runToolbarCustomizationPalette:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="237841660"/>
+                                       </object>
+                                       <int key="connectionID">365</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleToolbarShown:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="102151532"/>
+                                       </object>
+                                       <int key="connectionID">366</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">hide:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="755159360"/>
+                                       </object>
+                                       <int key="connectionID">367</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">hideOtherApplications:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="342932134"/>
+                                       </object>
+                                       <int key="connectionID">368</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">unhideAllApplications:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="908899353"/>
+                                       </object>
+                                       <int key="connectionID">370</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">newDocument:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="705341025"/>
+                                       </object>
+                                       <int key="connectionID">373</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">openDocument:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="722745758"/>
+                                       </object>
+                                       <int key="connectionID">374</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">addFontTrait:</string>
+                                               <reference key="source" ref="755631768"/>
+                                               <reference key="destination" ref="305399458"/>
+                                       </object>
+                                       <int key="connectionID">421</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">addFontTrait:</string>
+                                               <reference key="source" ref="755631768"/>
+                                               <reference key="destination" ref="814362025"/>
+                                       </object>
+                                       <int key="connectionID">422</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">modifyFont:</string>
+                                               <reference key="source" ref="755631768"/>
+                                               <reference key="destination" ref="885547335"/>
+                                       </object>
+                                       <int key="connectionID">423</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">orderFrontFontPanel:</string>
+                                               <reference key="source" ref="755631768"/>
+                                               <reference key="destination" ref="159677712"/>
+                                       </object>
+                                       <int key="connectionID">424</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">modifyFont:</string>
+                                               <reference key="source" ref="755631768"/>
+                                               <reference key="destination" ref="158063935"/>
+                                       </object>
+                                       <int key="connectionID">425</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">raiseBaseline:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="941806246"/>
+                                       </object>
+                                       <int key="connectionID">426</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">lowerBaseline:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1045724900"/>
+                                       </object>
+                                       <int key="connectionID">427</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">copyFont:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="596732606"/>
+                                       </object>
+                                       <int key="connectionID">428</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">subscript:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1037576581"/>
+                                       </object>
+                                       <int key="connectionID">429</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">superscript:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="644725453"/>
+                                       </object>
+                                       <int key="connectionID">430</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">tightenKerning:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="677519740"/>
+                                       </object>
+                                       <int key="connectionID">431</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">underline:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="330926929"/>
+                                       </object>
+                                       <int key="connectionID">432</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">orderFrontColorPanel:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1012600125"/>
+                                       </object>
+                                       <int key="connectionID">433</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">useAllLigatures:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="663508465"/>
+                                       </object>
+                                       <int key="connectionID">434</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">loosenKerning:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="238351151"/>
+                                       </object>
+                                       <int key="connectionID">435</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">pasteFont:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="393423671"/>
+                                       </object>
+                                       <int key="connectionID">436</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">unscript:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="257962622"/>
+                                       </object>
+                                       <int key="connectionID">437</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">useStandardKerning:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="252969304"/>
+                                       </object>
+                                       <int key="connectionID">438</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">useStandardLigatures:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="706297211"/>
+                                       </object>
+                                       <int key="connectionID">439</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">turnOffLigatures:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="568384683"/>
+                                       </object>
+                                       <int key="connectionID">440</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">turnOffKerning:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="766922938"/>
+                                       </object>
+                                       <int key="connectionID">441</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">terminate:</string>
+                                               <reference key="source" ref="1050"/>
+                                               <reference key="destination" ref="632727374"/>
+                                       </object>
+                                       <int key="connectionID">449</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleAutomaticSpellingCorrection:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="795346622"/>
+                                       </object>
+                                       <int key="connectionID">456</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">orderFrontSubstitutionsPanel:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="65139061"/>
+                                       </object>
+                                       <int key="connectionID">458</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleAutomaticDashSubstitution:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="672708820"/>
+                                       </object>
+                                       <int key="connectionID">461</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleAutomaticTextReplacement:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="537092702"/>
+                                       </object>
+                                       <int key="connectionID">463</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">uppercaseWord:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="1060694897"/>
+                                       </object>
+                                       <int key="connectionID">464</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">capitalizeWord:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="56570060"/>
+                                       </object>
+                                       <int key="connectionID">467</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">lowercaseWord:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="879586729"/>
+                                       </object>
+                                       <int key="connectionID">468</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">pasteAsPlainText:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="82994268"/>
+                                       </object>
+                                       <int key="connectionID">486</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performFindPanelAction:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="326711663"/>
+                                       </object>
+                                       <int key="connectionID">487</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performFindPanelAction:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="270902937"/>
+                                       </object>
+                                       <int key="connectionID">488</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">performFindPanelAction:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="159080638"/>
+                                       </object>
+                                       <int key="connectionID">489</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">showHelp:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="105068016"/>
+                                       </object>
+                                       <int key="connectionID">493</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">delegate</string>
+                                               <reference key="source" ref="1021"/>
+                                               <reference key="destination" ref="976324537"/>
+                                       </object>
+                                       <int key="connectionID">495</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">alignCenter:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="630155264"/>
+                                       </object>
+                                       <int key="connectionID">518</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">pasteRuler:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="883618387"/>
+                                       </object>
+                                       <int key="connectionID">519</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">toggleRuler:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="644046920"/>
+                                       </object>
+                                       <int key="connectionID">520</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">alignRight:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="512868991"/>
+                                       </object>
+                                       <int key="connectionID">521</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">copyRuler:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="231811626"/>
+                                       </object>
+                                       <int key="connectionID">522</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">alignJustified:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="945678886"/>
+                                       </object>
+                                       <int key="connectionID">523</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">alignLeft:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="875092757"/>
+                                       </object>
+                                       <int key="connectionID">524</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeBaseWritingDirectionNatural:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="551969625"/>
+                                       </object>
+                                       <int key="connectionID">525</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeBaseWritingDirectionLeftToRight:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="249532473"/>
+                                       </object>
+                                       <int key="connectionID">526</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeBaseWritingDirectionRightToLeft:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="607364498"/>
+                                       </object>
+                                       <int key="connectionID">527</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeTextWritingDirectionNatural:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="380031999"/>
+                                       </object>
+                                       <int key="connectionID">528</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeTextWritingDirectionLeftToRight:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="825984362"/>
+                                       </object>
+                                       <int key="connectionID">529</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">makeTextWritingDirectionRightToLeft:</string>
+                                               <reference key="source" ref="1014"/>
+                                               <reference key="destination" ref="560145579"/>
+                                       </object>
+                                       <int key="connectionID">530</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">window</string>
+                                               <reference key="source" ref="976324537"/>
+                                               <reference key="destination" ref="972006081"/>
+                                       </object>
+                                       <int key="connectionID">532</int>
+                               </object>
+                       </object>
+                       <object class="IBMutableOrderedSet" key="objectRecords">
+                               <object class="NSArray" key="orderedObjects">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">0</int>
+                                               <reference key="object" ref="0"/>
+                                               <reference key="children" ref="1048"/>
+                                               <nil key="parent"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">-2</int>
+                                               <reference key="object" ref="1021"/>
+                                               <reference key="parent" ref="0"/>
+                                               <string key="objectName">File's Owner</string>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">-1</int>
+                                               <reference key="object" ref="1014"/>
+                                               <reference key="parent" ref="0"/>
+                                               <string key="objectName">First Responder</string>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">-3</int>
+                                               <reference key="object" ref="1050"/>
+                                               <reference key="parent" ref="0"/>
+                                               <string key="objectName">Application</string>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">29</int>
+                                               <reference key="object" ref="649796088"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="713487014"/>
+                                                       <reference ref="694149608"/>
+                                                       <reference ref="952259628"/>
+                                                       <reference ref="379814623"/>
+                                                       <reference ref="586577488"/>
+                                                       <reference ref="302598603"/>
+                                                       <reference ref="448692316"/>
+                                               </object>
+                                               <reference key="parent" ref="0"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">19</int>
+                                               <reference key="object" ref="713487014"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="835318025"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">56</int>
+                                               <reference key="object" ref="694149608"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="110575045"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">217</int>
+                                               <reference key="object" ref="952259628"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="789758025"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">83</int>
+                                               <reference key="object" ref="379814623"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="720053764"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">81</int>
+                                               <reference key="object" ref="720053764"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="1023925487"/>
+                                                       <reference ref="117038363"/>
+                                                       <reference ref="49223823"/>
+                                                       <reference ref="722745758"/>
+                                                       <reference ref="705341025"/>
+                                                       <reference ref="1025936716"/>
+                                                       <reference ref="294629803"/>
+                                                       <reference ref="776162233"/>
+                                                       <reference ref="425164168"/>
+                                                       <reference ref="579971712"/>
+                                                       <reference ref="1010469920"/>
+                                               </object>
+                                               <reference key="parent" ref="379814623"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">75</int>
+                                               <reference key="object" ref="1023925487"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">80</int>
+                                               <reference key="object" ref="117038363"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">78</int>
+                                               <reference key="object" ref="49223823"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">72</int>
+                                               <reference key="object" ref="722745758"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">82</int>
+                                               <reference key="object" ref="705341025"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">124</int>
+                                               <reference key="object" ref="1025936716"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="1065607017"/>
+                                               </object>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">77</int>
+                                               <reference key="object" ref="294629803"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">73</int>
+                                               <reference key="object" ref="776162233"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">79</int>
+                                               <reference key="object" ref="425164168"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">112</int>
+                                               <reference key="object" ref="579971712"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">74</int>
+                                               <reference key="object" ref="1010469920"/>
+                                               <reference key="parent" ref="720053764"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">125</int>
+                                               <reference key="object" ref="1065607017"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="759406840"/>
+                                               </object>
+                                               <reference key="parent" ref="1025936716"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">126</int>
+                                               <reference key="object" ref="759406840"/>
+                                               <reference key="parent" ref="1065607017"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">205</int>
+                                               <reference key="object" ref="789758025"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="437104165"/>
+                                                       <reference ref="583158037"/>
+                                                       <reference ref="1058277027"/>
+                                                       <reference ref="212016141"/>
+                                                       <reference ref="296257095"/>
+                                                       <reference ref="29853731"/>
+                                                       <reference ref="860595796"/>
+                                                       <reference ref="1040322652"/>
+                                                       <reference ref="790794224"/>
+                                                       <reference ref="892235320"/>
+                                                       <reference ref="972420730"/>
+                                                       <reference ref="676164635"/>
+                                                       <reference ref="507821607"/>
+                                                       <reference ref="288088188"/>
+                                                       <reference ref="82994268"/>
+                                               </object>
+                                               <reference key="parent" ref="952259628"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">202</int>
+                                               <reference key="object" ref="437104165"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">198</int>
+                                               <reference key="object" ref="583158037"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">207</int>
+                                               <reference key="object" ref="1058277027"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">214</int>
+                                               <reference key="object" ref="212016141"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">199</int>
+                                               <reference key="object" ref="296257095"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">203</int>
+                                               <reference key="object" ref="29853731"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">197</int>
+                                               <reference key="object" ref="860595796"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">206</int>
+                                               <reference key="object" ref="1040322652"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">215</int>
+                                               <reference key="object" ref="790794224"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">218</int>
+                                               <reference key="object" ref="892235320"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="963351320"/>
+                                               </object>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">216</int>
+                                               <reference key="object" ref="972420730"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="769623530"/>
+                                               </object>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">200</int>
+                                               <reference key="object" ref="769623530"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="948374510"/>
+                                                       <reference ref="96193923"/>
+                                                       <reference ref="679648819"/>
+                                                       <reference ref="967646866"/>
+                                                       <reference ref="859480356"/>
+                                                       <reference ref="795346622"/>
+                                               </object>
+                                               <reference key="parent" ref="972420730"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">219</int>
+                                               <reference key="object" ref="948374510"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">201</int>
+                                               <reference key="object" ref="96193923"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">204</int>
+                                               <reference key="object" ref="679648819"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">220</int>
+                                               <reference key="object" ref="963351320"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="270902937"/>
+                                                       <reference ref="88285865"/>
+                                                       <reference ref="159080638"/>
+                                                       <reference ref="326711663"/>
+                                                       <reference ref="447796847"/>
+                                               </object>
+                                               <reference key="parent" ref="892235320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">213</int>
+                                               <reference key="object" ref="270902937"/>
+                                               <reference key="parent" ref="963351320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">210</int>
+                                               <reference key="object" ref="88285865"/>
+                                               <reference key="parent" ref="963351320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">221</int>
+                                               <reference key="object" ref="159080638"/>
+                                               <reference key="parent" ref="963351320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">208</int>
+                                               <reference key="object" ref="326711663"/>
+                                               <reference key="parent" ref="963351320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">209</int>
+                                               <reference key="object" ref="447796847"/>
+                                               <reference key="parent" ref="963351320"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">57</int>
+                                               <reference key="object" ref="110575045"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="238522557"/>
+                                                       <reference ref="755159360"/>
+                                                       <reference ref="908899353"/>
+                                                       <reference ref="632727374"/>
+                                                       <reference ref="646227648"/>
+                                                       <reference ref="609285721"/>
+                                                       <reference ref="481834944"/>
+                                                       <reference ref="304266470"/>
+                                                       <reference ref="1046388886"/>
+                                                       <reference ref="1056857174"/>
+                                                       <reference ref="342932134"/>
+                                               </object>
+                                               <reference key="parent" ref="694149608"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">58</int>
+                                               <reference key="object" ref="238522557"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">134</int>
+                                               <reference key="object" ref="755159360"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">150</int>
+                                               <reference key="object" ref="908899353"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">136</int>
+                                               <reference key="object" ref="632727374"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">144</int>
+                                               <reference key="object" ref="646227648"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">129</int>
+                                               <reference key="object" ref="609285721"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">143</int>
+                                               <reference key="object" ref="481834944"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">236</int>
+                                               <reference key="object" ref="304266470"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">131</int>
+                                               <reference key="object" ref="1046388886"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="752062318"/>
+                                               </object>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">149</int>
+                                               <reference key="object" ref="1056857174"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">145</int>
+                                               <reference key="object" ref="342932134"/>
+                                               <reference key="parent" ref="110575045"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">130</int>
+                                               <reference key="object" ref="752062318"/>
+                                               <reference key="parent" ref="1046388886"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">24</int>
+                                               <reference key="object" ref="835318025"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="299356726"/>
+                                                       <reference ref="625202149"/>
+                                                       <reference ref="575023229"/>
+                                                       <reference ref="1011231497"/>
+                                               </object>
+                                               <reference key="parent" ref="713487014"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">92</int>
+                                               <reference key="object" ref="299356726"/>
+                                               <reference key="parent" ref="835318025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">5</int>
+                                               <reference key="object" ref="625202149"/>
+                                               <reference key="parent" ref="835318025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">239</int>
+                                               <reference key="object" ref="575023229"/>
+                                               <reference key="parent" ref="835318025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">23</int>
+                                               <reference key="object" ref="1011231497"/>
+                                               <reference key="parent" ref="835318025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">295</int>
+                                               <reference key="object" ref="586577488"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="466310130"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">296</int>
+                                               <reference key="object" ref="466310130"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="102151532"/>
+                                                       <reference ref="237841660"/>
+                                               </object>
+                                               <reference key="parent" ref="586577488"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">297</int>
+                                               <reference key="object" ref="102151532"/>
+                                               <reference key="parent" ref="466310130"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">298</int>
+                                               <reference key="object" ref="237841660"/>
+                                               <reference key="parent" ref="466310130"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">211</int>
+                                               <reference key="object" ref="676164635"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="785027613"/>
+                                               </object>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">212</int>
+                                               <reference key="object" ref="785027613"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="680220178"/>
+                                                       <reference ref="731782645"/>
+                                               </object>
+                                               <reference key="parent" ref="676164635"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">195</int>
+                                               <reference key="object" ref="680220178"/>
+                                               <reference key="parent" ref="785027613"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">196</int>
+                                               <reference key="object" ref="731782645"/>
+                                               <reference key="parent" ref="785027613"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">346</int>
+                                               <reference key="object" ref="967646866"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">348</int>
+                                               <reference key="object" ref="507821607"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="698887838"/>
+                                               </object>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">349</int>
+                                               <reference key="object" ref="698887838"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="605118523"/>
+                                                       <reference ref="197661976"/>
+                                                       <reference ref="708854459"/>
+                                                       <reference ref="65139061"/>
+                                                       <reference ref="19036812"/>
+                                                       <reference ref="672708820"/>
+                                                       <reference ref="537092702"/>
+                                               </object>
+                                               <reference key="parent" ref="507821607"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">350</int>
+                                               <reference key="object" ref="605118523"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">351</int>
+                                               <reference key="object" ref="197661976"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">354</int>
+                                               <reference key="object" ref="708854459"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">371</int>
+                                               <reference key="object" ref="972006081"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="439893737"/>
+                                               </object>
+                                               <reference key="parent" ref="0"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">372</int>
+                                               <reference key="object" ref="439893737"/>
+                                               <reference key="parent" ref="972006081"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">375</int>
+                                               <reference key="object" ref="302598603"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="941447902"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">376</int>
+                                               <reference key="object" ref="941447902"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="792887677"/>
+                                                       <reference ref="215659978"/>
+                                               </object>
+                                               <reference key="parent" ref="302598603"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">377</int>
+                                               <reference key="object" ref="792887677"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="786677654"/>
+                                               </object>
+                                               <reference key="parent" ref="941447902"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">388</int>
+                                               <reference key="object" ref="786677654"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="159677712"/>
+                                                       <reference ref="305399458"/>
+                                                       <reference ref="814362025"/>
+                                                       <reference ref="330926929"/>
+                                                       <reference ref="533507878"/>
+                                                       <reference ref="158063935"/>
+                                                       <reference ref="885547335"/>
+                                                       <reference ref="901062459"/>
+                                                       <reference ref="767671776"/>
+                                                       <reference ref="691570813"/>
+                                                       <reference ref="769124883"/>
+                                                       <reference ref="739652853"/>
+                                                       <reference ref="1012600125"/>
+                                                       <reference ref="214559597"/>
+                                                       <reference ref="596732606"/>
+                                                       <reference ref="393423671"/>
+                                               </object>
+                                               <reference key="parent" ref="792887677"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">389</int>
+                                               <reference key="object" ref="159677712"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">390</int>
+                                               <reference key="object" ref="305399458"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">391</int>
+                                               <reference key="object" ref="814362025"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">392</int>
+                                               <reference key="object" ref="330926929"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">393</int>
+                                               <reference key="object" ref="533507878"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">394</int>
+                                               <reference key="object" ref="158063935"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">395</int>
+                                               <reference key="object" ref="885547335"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">396</int>
+                                               <reference key="object" ref="901062459"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">397</int>
+                                               <reference key="object" ref="767671776"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="175441468"/>
+                                               </object>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">398</int>
+                                               <reference key="object" ref="691570813"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="1058217995"/>
+                                               </object>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">399</int>
+                                               <reference key="object" ref="769124883"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="18263474"/>
+                                               </object>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">400</int>
+                                               <reference key="object" ref="739652853"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">401</int>
+                                               <reference key="object" ref="1012600125"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">402</int>
+                                               <reference key="object" ref="214559597"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">403</int>
+                                               <reference key="object" ref="596732606"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">404</int>
+                                               <reference key="object" ref="393423671"/>
+                                               <reference key="parent" ref="786677654"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">405</int>
+                                               <reference key="object" ref="18263474"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="257962622"/>
+                                                       <reference ref="644725453"/>
+                                                       <reference ref="1037576581"/>
+                                                       <reference ref="941806246"/>
+                                                       <reference ref="1045724900"/>
+                                               </object>
+                                               <reference key="parent" ref="769124883"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">406</int>
+                                               <reference key="object" ref="257962622"/>
+                                               <reference key="parent" ref="18263474"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">407</int>
+                                               <reference key="object" ref="644725453"/>
+                                               <reference key="parent" ref="18263474"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">408</int>
+                                               <reference key="object" ref="1037576581"/>
+                                               <reference key="parent" ref="18263474"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">409</int>
+                                               <reference key="object" ref="941806246"/>
+                                               <reference key="parent" ref="18263474"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">410</int>
+                                               <reference key="object" ref="1045724900"/>
+                                               <reference key="parent" ref="18263474"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">411</int>
+                                               <reference key="object" ref="1058217995"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="706297211"/>
+                                                       <reference ref="568384683"/>
+                                                       <reference ref="663508465"/>
+                                               </object>
+                                               <reference key="parent" ref="691570813"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">412</int>
+                                               <reference key="object" ref="706297211"/>
+                                               <reference key="parent" ref="1058217995"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">413</int>
+                                               <reference key="object" ref="568384683"/>
+                                               <reference key="parent" ref="1058217995"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">414</int>
+                                               <reference key="object" ref="663508465"/>
+                                               <reference key="parent" ref="1058217995"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">415</int>
+                                               <reference key="object" ref="175441468"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="252969304"/>
+                                                       <reference ref="766922938"/>
+                                                       <reference ref="677519740"/>
+                                                       <reference ref="238351151"/>
+                                               </object>
+                                               <reference key="parent" ref="767671776"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">416</int>
+                                               <reference key="object" ref="252969304"/>
+                                               <reference key="parent" ref="175441468"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">417</int>
+                                               <reference key="object" ref="766922938"/>
+                                               <reference key="parent" ref="175441468"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">418</int>
+                                               <reference key="object" ref="677519740"/>
+                                               <reference key="parent" ref="175441468"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">419</int>
+                                               <reference key="object" ref="238351151"/>
+                                               <reference key="parent" ref="175441468"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">420</int>
+                                               <reference key="object" ref="755631768"/>
+                                               <reference key="parent" ref="0"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">450</int>
+                                               <reference key="object" ref="288088188"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="579392910"/>
+                                               </object>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">451</int>
+                                               <reference key="object" ref="579392910"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="1060694897"/>
+                                                       <reference ref="879586729"/>
+                                                       <reference ref="56570060"/>
+                                               </object>
+                                               <reference key="parent" ref="288088188"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">452</int>
+                                               <reference key="object" ref="1060694897"/>
+                                               <reference key="parent" ref="579392910"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">453</int>
+                                               <reference key="object" ref="859480356"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">454</int>
+                                               <reference key="object" ref="795346622"/>
+                                               <reference key="parent" ref="769623530"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">457</int>
+                                               <reference key="object" ref="65139061"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">459</int>
+                                               <reference key="object" ref="19036812"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">460</int>
+                                               <reference key="object" ref="672708820"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">462</int>
+                                               <reference key="object" ref="537092702"/>
+                                               <reference key="parent" ref="698887838"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">465</int>
+                                               <reference key="object" ref="879586729"/>
+                                               <reference key="parent" ref="579392910"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">466</int>
+                                               <reference key="object" ref="56570060"/>
+                                               <reference key="parent" ref="579392910"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">485</int>
+                                               <reference key="object" ref="82994268"/>
+                                               <reference key="parent" ref="789758025"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">490</int>
+                                               <reference key="object" ref="448692316"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="992780483"/>
+                                               </object>
+                                               <reference key="parent" ref="649796088"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">491</int>
+                                               <reference key="object" ref="992780483"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="105068016"/>
+                                               </object>
+                                               <reference key="parent" ref="448692316"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">492</int>
+                                               <reference key="object" ref="105068016"/>
+                                               <reference key="parent" ref="992780483"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">494</int>
+                                               <reference key="object" ref="976324537"/>
+                                               <reference key="parent" ref="0"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">496</int>
+                                               <reference key="object" ref="215659978"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="446991534"/>
+                                               </object>
+                                               <reference key="parent" ref="941447902"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">497</int>
+                                               <reference key="object" ref="446991534"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="875092757"/>
+                                                       <reference ref="630155264"/>
+                                                       <reference ref="945678886"/>
+                                                       <reference ref="512868991"/>
+                                                       <reference ref="163117631"/>
+                                                       <reference ref="31516759"/>
+                                                       <reference ref="908105787"/>
+                                                       <reference ref="644046920"/>
+                                                       <reference ref="231811626"/>
+                                                       <reference ref="883618387"/>
+                                               </object>
+                                               <reference key="parent" ref="215659978"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">498</int>
+                                               <reference key="object" ref="875092757"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">499</int>
+                                               <reference key="object" ref="630155264"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">500</int>
+                                               <reference key="object" ref="945678886"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">501</int>
+                                               <reference key="object" ref="512868991"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">502</int>
+                                               <reference key="object" ref="163117631"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">503</int>
+                                               <reference key="object" ref="31516759"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="956096989"/>
+                                               </object>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">504</int>
+                                               <reference key="object" ref="908105787"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">505</int>
+                                               <reference key="object" ref="644046920"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">506</int>
+                                               <reference key="object" ref="231811626"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">507</int>
+                                               <reference key="object" ref="883618387"/>
+                                               <reference key="parent" ref="446991534"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">508</int>
+                                               <reference key="object" ref="956096989"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <reference ref="257099033"/>
+                                                       <reference ref="551969625"/>
+                                                       <reference ref="249532473"/>
+                                                       <reference ref="607364498"/>
+                                                       <reference ref="508151438"/>
+                                                       <reference ref="981751889"/>
+                                                       <reference ref="380031999"/>
+                                                       <reference ref="825984362"/>
+                                                       <reference ref="560145579"/>
+                                               </object>
+                                               <reference key="parent" ref="31516759"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">509</int>
+                                               <reference key="object" ref="257099033"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">510</int>
+                                               <reference key="object" ref="551969625"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">511</int>
+                                               <reference key="object" ref="249532473"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">512</int>
+                                               <reference key="object" ref="607364498"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">513</int>
+                                               <reference key="object" ref="508151438"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">514</int>
+                                               <reference key="object" ref="981751889"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">515</int>
+                                               <reference key="object" ref="380031999"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">516</int>
+                                               <reference key="object" ref="825984362"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">517</int>
+                                               <reference key="object" ref="560145579"/>
+                                               <reference key="parent" ref="956096989"/>
+                                       </object>
+                               </object>
+                       </object>
+                       <object class="NSMutableDictionary" key="flattenedProperties">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <object class="NSArray" key="dict.sortedKeys">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                       <string>-3.IBPluginDependency</string>
+                                       <string>112.IBPluginDependency</string>
+                                       <string>112.ImportedFromIB2</string>
+                                       <string>124.IBPluginDependency</string>
+                                       <string>124.ImportedFromIB2</string>
+                                       <string>125.IBPluginDependency</string>
+                                       <string>125.ImportedFromIB2</string>
+                                       <string>125.editorWindowContentRectSynchronizationRect</string>
+                                       <string>126.IBPluginDependency</string>
+                                       <string>126.ImportedFromIB2</string>
+                                       <string>129.IBPluginDependency</string>
+                                       <string>129.ImportedFromIB2</string>
+                                       <string>130.IBPluginDependency</string>
+                                       <string>130.ImportedFromIB2</string>
+                                       <string>130.editorWindowContentRectSynchronizationRect</string>
+                                       <string>131.IBPluginDependency</string>
+                                       <string>131.ImportedFromIB2</string>
+                                       <string>134.IBPluginDependency</string>
+                                       <string>134.ImportedFromIB2</string>
+                                       <string>136.IBPluginDependency</string>
+                                       <string>136.ImportedFromIB2</string>
+                                       <string>143.IBPluginDependency</string>
+                                       <string>143.ImportedFromIB2</string>
+                                       <string>144.IBPluginDependency</string>
+                                       <string>144.ImportedFromIB2</string>
+                                       <string>145.IBPluginDependency</string>
+                                       <string>145.ImportedFromIB2</string>
+                                       <string>149.IBPluginDependency</string>
+                                       <string>149.ImportedFromIB2</string>
+                                       <string>150.IBPluginDependency</string>
+                                       <string>150.ImportedFromIB2</string>
+                                       <string>19.IBPluginDependency</string>
+                                       <string>19.ImportedFromIB2</string>
+                                       <string>195.IBPluginDependency</string>
+                                       <string>195.ImportedFromIB2</string>
+                                       <string>196.IBPluginDependency</string>
+                                       <string>196.ImportedFromIB2</string>
+                                       <string>197.IBPluginDependency</string>
+                                       <string>197.ImportedFromIB2</string>
+                                       <string>198.IBPluginDependency</string>
+                                       <string>198.ImportedFromIB2</string>
+                                       <string>199.IBPluginDependency</string>
+                                       <string>199.ImportedFromIB2</string>
+                                       <string>200.IBEditorWindowLastContentRect</string>
+                                       <string>200.IBPluginDependency</string>
+                                       <string>200.ImportedFromIB2</string>
+                                       <string>200.editorWindowContentRectSynchronizationRect</string>
+                                       <string>201.IBPluginDependency</string>
+                                       <string>201.ImportedFromIB2</string>
+                                       <string>202.IBPluginDependency</string>
+                                       <string>202.ImportedFromIB2</string>
+                                       <string>203.IBPluginDependency</string>
+                                       <string>203.ImportedFromIB2</string>
+                                       <string>204.IBPluginDependency</string>
+                                       <string>204.ImportedFromIB2</string>
+                                       <string>205.IBEditorWindowLastContentRect</string>
+                                       <string>205.IBPluginDependency</string>
+                                       <string>205.ImportedFromIB2</string>
+                                       <string>205.editorWindowContentRectSynchronizationRect</string>
+                                       <string>206.IBPluginDependency</string>
+                                       <string>206.ImportedFromIB2</string>
+                                       <string>207.IBPluginDependency</string>
+                                       <string>207.ImportedFromIB2</string>
+                                       <string>208.IBPluginDependency</string>
+                                       <string>208.ImportedFromIB2</string>
+                                       <string>209.IBPluginDependency</string>
+                                       <string>209.ImportedFromIB2</string>
+                                       <string>210.IBPluginDependency</string>
+                                       <string>210.ImportedFromIB2</string>
+                                       <string>211.IBPluginDependency</string>
+                                       <string>211.ImportedFromIB2</string>
+                                       <string>212.IBPluginDependency</string>
+                                       <string>212.ImportedFromIB2</string>
+                                       <string>212.editorWindowContentRectSynchronizationRect</string>
+                                       <string>213.IBPluginDependency</string>
+                                       <string>213.ImportedFromIB2</string>
+                                       <string>214.IBPluginDependency</string>
+                                       <string>214.ImportedFromIB2</string>
+                                       <string>215.IBPluginDependency</string>
+                                       <string>215.ImportedFromIB2</string>
+                                       <string>216.IBPluginDependency</string>
+                                       <string>216.ImportedFromIB2</string>
+                                       <string>217.IBPluginDependency</string>
+                                       <string>217.ImportedFromIB2</string>
+                                       <string>218.IBPluginDependency</string>
+                                       <string>218.ImportedFromIB2</string>
+                                       <string>219.IBPluginDependency</string>
+                                       <string>219.ImportedFromIB2</string>
+                                       <string>220.IBEditorWindowLastContentRect</string>
+                                       <string>220.IBPluginDependency</string>
+                                       <string>220.ImportedFromIB2</string>
+                                       <string>220.editorWindowContentRectSynchronizationRect</string>
+                                       <string>221.IBPluginDependency</string>
+                                       <string>221.ImportedFromIB2</string>
+                                       <string>23.IBPluginDependency</string>
+                                       <string>23.ImportedFromIB2</string>
+                                       <string>236.IBPluginDependency</string>
+                                       <string>236.ImportedFromIB2</string>
+                                       <string>239.IBPluginDependency</string>
+                                       <string>239.ImportedFromIB2</string>
+                                       <string>24.IBEditorWindowLastContentRect</string>
+                                       <string>24.IBPluginDependency</string>
+                                       <string>24.ImportedFromIB2</string>
+                                       <string>24.editorWindowContentRectSynchronizationRect</string>
+                                       <string>29.IBEditorWindowLastContentRect</string>
+                                       <string>29.IBPluginDependency</string>
+                                       <string>29.ImportedFromIB2</string>
+                                       <string>29.WindowOrigin</string>
+                                       <string>29.editorWindowContentRectSynchronizationRect</string>
+                                       <string>295.IBPluginDependency</string>
+                                       <string>296.IBEditorWindowLastContentRect</string>
+                                       <string>296.IBPluginDependency</string>
+                                       <string>296.editorWindowContentRectSynchronizationRect</string>
+                                       <string>297.IBPluginDependency</string>
+                                       <string>298.IBPluginDependency</string>
+                                       <string>346.IBPluginDependency</string>
+                                       <string>346.ImportedFromIB2</string>
+                                       <string>348.IBPluginDependency</string>
+                                       <string>348.ImportedFromIB2</string>
+                                       <string>349.IBEditorWindowLastContentRect</string>
+                                       <string>349.IBPluginDependency</string>
+                                       <string>349.ImportedFromIB2</string>
+                                       <string>349.editorWindowContentRectSynchronizationRect</string>
+                                       <string>350.IBPluginDependency</string>
+                                       <string>350.ImportedFromIB2</string>
+                                       <string>351.IBPluginDependency</string>
+                                       <string>351.ImportedFromIB2</string>
+                                       <string>354.IBPluginDependency</string>
+                                       <string>354.ImportedFromIB2</string>
+                                       <string>371.IBEditorWindowLastContentRect</string>
+                                       <string>371.IBPluginDependency</string>
+                                       <string>371.IBWindowTemplateEditedContentRect</string>
+                                       <string>371.NSWindowTemplate.visibleAtLaunch</string>
+                                       <string>371.editorWindowContentRectSynchronizationRect</string>
+                                       <string>371.windowTemplate.maxSize</string>
+                                       <string>372.IBPluginDependency</string>
+                                       <string>375.IBPluginDependency</string>
+                                       <string>376.IBEditorWindowLastContentRect</string>
+                                       <string>376.IBPluginDependency</string>
+                                       <string>377.IBPluginDependency</string>
+                                       <string>388.IBEditorWindowLastContentRect</string>
+                                       <string>388.IBPluginDependency</string>
+                                       <string>389.IBPluginDependency</string>
+                                       <string>390.IBPluginDependency</string>
+                                       <string>391.IBPluginDependency</string>
+                                       <string>392.IBPluginDependency</string>
+                                       <string>393.IBPluginDependency</string>
+                                       <string>394.IBPluginDependency</string>
+                                       <string>395.IBPluginDependency</string>
+                                       <string>396.IBPluginDependency</string>
+                                       <string>397.IBPluginDependency</string>
+                                       <string>398.IBPluginDependency</string>
+                                       <string>399.IBPluginDependency</string>
+                                       <string>400.IBPluginDependency</string>
+                                       <string>401.IBPluginDependency</string>
+                                       <string>402.IBPluginDependency</string>
+                                       <string>403.IBPluginDependency</string>
+                                       <string>404.IBPluginDependency</string>
+                                       <string>405.IBPluginDependency</string>
+                                       <string>406.IBPluginDependency</string>
+                                       <string>407.IBPluginDependency</string>
+                                       <string>408.IBPluginDependency</string>
+                                       <string>409.IBPluginDependency</string>
+                                       <string>410.IBPluginDependency</string>
+                                       <string>411.IBPluginDependency</string>
+                                       <string>412.IBPluginDependency</string>
+                                       <string>413.IBPluginDependency</string>
+                                       <string>414.IBPluginDependency</string>
+                                       <string>415.IBPluginDependency</string>
+                                       <string>416.IBPluginDependency</string>
+                                       <string>417.IBPluginDependency</string>
+                                       <string>418.IBPluginDependency</string>
+                                       <string>419.IBPluginDependency</string>
+                                       <string>450.IBPluginDependency</string>
+                                       <string>451.IBEditorWindowLastContentRect</string>
+                                       <string>451.IBPluginDependency</string>
+                                       <string>452.IBPluginDependency</string>
+                                       <string>453.IBPluginDependency</string>
+                                       <string>454.IBPluginDependency</string>
+                                       <string>457.IBPluginDependency</string>
+                                       <string>459.IBPluginDependency</string>
+                                       <string>460.IBPluginDependency</string>
+                                       <string>462.IBPluginDependency</string>
+                                       <string>465.IBPluginDependency</string>
+                                       <string>466.IBPluginDependency</string>
+                                       <string>485.IBPluginDependency</string>
+                                       <string>490.IBPluginDependency</string>
+                                       <string>491.IBEditorWindowLastContentRect</string>
+                                       <string>491.IBPluginDependency</string>
+                                       <string>492.IBPluginDependency</string>
+                                       <string>496.IBPluginDependency</string>
+                                       <string>497.IBEditorWindowLastContentRect</string>
+                                       <string>497.IBPluginDependency</string>
+                                       <string>498.IBPluginDependency</string>
+                                       <string>499.IBPluginDependency</string>
+                                       <string>5.IBPluginDependency</string>
+                                       <string>5.ImportedFromIB2</string>
+                                       <string>500.IBPluginDependency</string>
+                                       <string>501.IBPluginDependency</string>
+                                       <string>502.IBPluginDependency</string>
+                                       <string>503.IBPluginDependency</string>
+                                       <string>504.IBPluginDependency</string>
+                                       <string>505.IBPluginDependency</string>
+                                       <string>506.IBPluginDependency</string>
+                                       <string>507.IBPluginDependency</string>
+                                       <string>508.IBEditorWindowLastContentRect</string>
+                                       <string>508.IBPluginDependency</string>
+                                       <string>509.IBPluginDependency</string>
+                                       <string>510.IBPluginDependency</string>
+                                       <string>511.IBPluginDependency</string>
+                                       <string>512.IBPluginDependency</string>
+                                       <string>513.IBPluginDependency</string>
+                                       <string>514.IBPluginDependency</string>
+                                       <string>515.IBPluginDependency</string>
+                                       <string>516.IBPluginDependency</string>
+                                       <string>517.IBPluginDependency</string>
+                                       <string>56.IBPluginDependency</string>
+                                       <string>56.ImportedFromIB2</string>
+                                       <string>57.IBEditorWindowLastContentRect</string>
+                                       <string>57.IBPluginDependency</string>
+                                       <string>57.ImportedFromIB2</string>
+                                       <string>57.editorWindowContentRectSynchronizationRect</string>
+                                       <string>58.IBPluginDependency</string>
+                                       <string>58.ImportedFromIB2</string>
+                                       <string>72.IBPluginDependency</string>
+                                       <string>72.ImportedFromIB2</string>
+                                       <string>73.IBPluginDependency</string>
+                                       <string>73.ImportedFromIB2</string>
+                                       <string>74.IBPluginDependency</string>
+                                       <string>74.ImportedFromIB2</string>
+                                       <string>75.IBPluginDependency</string>
+                                       <string>75.ImportedFromIB2</string>
+                                       <string>77.IBPluginDependency</string>
+                                       <string>77.ImportedFromIB2</string>
+                                       <string>78.IBPluginDependency</string>
+                                       <string>78.ImportedFromIB2</string>
+                                       <string>79.IBPluginDependency</string>
+                                       <string>79.ImportedFromIB2</string>
+                                       <string>80.IBPluginDependency</string>
+                                       <string>80.ImportedFromIB2</string>
+                                       <string>81.IBEditorWindowLastContentRect</string>
+                                       <string>81.IBPluginDependency</string>
+                                       <string>81.ImportedFromIB2</string>
+                                       <string>81.editorWindowContentRectSynchronizationRect</string>
+                                       <string>82.IBPluginDependency</string>
+                                       <string>82.ImportedFromIB2</string>
+                                       <string>83.IBPluginDependency</string>
+                                       <string>83.ImportedFromIB2</string>
+                                       <string>92.IBPluginDependency</string>
+                                       <string>92.ImportedFromIB2</string>
+                               </object>
+                               <object class="NSMutableArray" key="dict.values">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{522, 812}, {146, 23}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{436, 809}, {64, 6}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{753, 187}, {275, 113}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{608, 612}, {275, 83}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{547, 180}, {254, 283}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{187, 434}, {243, 243}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{608, 612}, {167, 43}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{753, 217}, {238, 103}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{608, 612}, {241, 103}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{654, 239}, {194, 73}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{525, 802}, {197, 73}}</string>
+                                       <string>{{380, 836}, {512, 20}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{74, 862}</string>
+                                       <string>{{6, 978}, {478, 20}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{604, 269}, {231, 43}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{475, 832}, {234, 43}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{746, 287}, {220, 133}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{608, 612}, {215, 63}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{380, 496}, {480, 360}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{380, 496}, {480, 360}}</string>
+                                       <integer value="1"/>
+                                       <string>{{33, 99}, {480, 360}}</string>
+                                       <string>{3.40282e+38, 3.40282e+38}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{591, 420}, {83, 43}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{523, 2}, {178, 283}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{753, 197}, {170, 63}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{725, 289}, {246, 23}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{674, 260}, {204, 183}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>{{878, 180}, {164, 173}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{286, 129}, {275, 183}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{23, 794}, {245, 183}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{452, 109}, {196, 203}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>{{145, 474}, {199, 203}}</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <integer value="1"/>
+                               </object>
+                       </object>
+                       <object class="NSMutableDictionary" key="unlocalizedProperties">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <reference key="dict.sortedKeys" ref="0"/>
+                               <object class="NSMutableArray" key="dict.values">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                               </object>
+                       </object>
+                       <nil key="activeLocalization"/>
+                       <object class="NSMutableDictionary" key="localizations">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <reference key="dict.sortedKeys" ref="0"/>
+                               <object class="NSMutableArray" key="dict.values">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                               </object>
+                       </object>
+                       <nil key="sourceID"/>
+                       <int key="maxID">532</int>
+               </object>
+               <object class="IBClassDescriber" key="IBDocument.Classes">
+                       <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">TestAppAppDelegate</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="NSMutableDictionary" key="outlets">
+                                               <string key="NS.key.0">window</string>
+                                               <string key="NS.object.0">NSWindow</string>
+                                       </object>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBProjectSource</string>
+                                               <string key="minorKey">TestAppAppDelegate.h</string>
+                                       </object>
+                               </object>
+                       </object>
+                       <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
+                               <bool key="EncodedWithXMLCoder">YES</bool>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <string key="superclassName">NSResponder</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="822405504">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSApplication.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="850738725">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSApplicationScripting.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="624831158">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSColorPanel.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSHelpManager.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSPageLayout.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSApplication</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSUserInterfaceItemSearching.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSBrowser</string>
+                                       <string key="superclassName">NSControl</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSBrowser.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSControl</string>
+                                       <string key="superclassName">NSView</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="310914472">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSControl.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSDocument</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="NSMutableDictionary" key="actions">
+                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                               <object class="NSArray" key="dict.sortedKeys">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <string>printDocument:</string>
+                                                       <string>revertDocumentToSaved:</string>
+                                                       <string>runPageLayout:</string>
+                                                       <string>saveDocument:</string>
+                                                       <string>saveDocumentAs:</string>
+                                                       <string>saveDocumentTo:</string>
+                                               </object>
+                                               <object class="NSMutableArray" key="dict.values">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                               </object>
+                                       </object>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDocument.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSDocument</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDocumentScripting.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSDocumentController</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="NSMutableDictionary" key="actions">
+                                               <bool key="EncodedWithXMLCoder">YES</bool>
+                                               <object class="NSArray" key="dict.sortedKeys">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <string>clearRecentDocuments:</string>
+                                                       <string>newDocument:</string>
+                                                       <string>openDocument:</string>
+                                                       <string>saveAllDocuments:</string>
+                                               </object>
+                                               <object class="NSMutableArray" key="dict.values">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                                       <string>id</string>
+                                               </object>
+                                       </object>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDocumentController.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSFontManager</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="946436764">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSFormatter</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSMatrix</string>
+                                       <string key="superclassName">NSControl</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSMatrix.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSMenu</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="1056362899">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSMenu.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSMenuItem</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="472958451">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSMovieView</string>
+                                       <string key="superclassName">NSView</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSMovieView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSAccessibility.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="822405504"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="850738725"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="624831158"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="310914472"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDictionaryController.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDragging.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="946436764"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSFontPanel.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSKeyValueBinding.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <reference key="sourceIdentifier" ref="1056362899"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSNibLoading.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSPasteboard.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSSavePanel.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="809545482">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSTableView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSToolbarItem.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier" id="260078765">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSArchiver.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSClassDescription.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSError.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSObjectScripting.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSPortCoder.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSScriptClassDescription.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSScriptKeyValueCoding.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSScriptObjectSpecifiers.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSScriptWhoseTests.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">Foundation.framework/Headers/NSURLDownload.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSResponder</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSInterfaceStyle.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSResponder</string>
+                                       <string key="superclassName">NSObject</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSResponder.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSTableView</string>
+                                       <string key="superclassName">NSControl</string>
+                                       <reference key="sourceIdentifier" ref="809545482"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSText</string>
+                                       <string key="superclassName">NSView</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSText.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSTextView</string>
+                                       <string key="superclassName">NSText</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSTextView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSView</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSClipView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSView</string>
+                                       <reference key="sourceIdentifier" ref="472958451"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSView</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSRulerView.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSView</string>
+                                       <string key="superclassName">NSResponder</string>
+                                       <reference key="sourceIdentifier" ref="260078765"/>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSWindow</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSDrawer.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSWindow</string>
+                                       <string key="superclassName">NSResponder</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSWindow.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NSWindow</string>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBFrameworkSource</string>
+                                               <string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string>
+                                       </object>
+                               </object>
+                       </object>
+               </object>
+               <int key="IBDocument.localizationMode">0</int>
+               <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
+                       <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
+                       <integer value="1060" key="NS.object.0"/>
+               </object>
+               <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+                       <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
+                       <integer value="3000" key="NS.object.0"/>
+               </object>
+               <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+               <string key="IBDocument.LastKnownRelativeProjectPath">../TestApp.xcodeproj</string>
+               <int key="IBDocument.defaultPropertyAccessControl">3</int>
+       </data>
+</archive>
diff --git a/gyp/test/mac/app-bundle/TestApp/English.lproj/utf-16be.strings b/gyp/test/mac/app-bundle/TestApp/English.lproj/utf-16be.strings
new file mode 100644 (file)
index 0000000..5807837
Binary files /dev/null and b/gyp/test/mac/app-bundle/TestApp/English.lproj/utf-16be.strings differ
diff --git a/gyp/test/mac/app-bundle/TestApp/English.lproj/utf-16le.strings b/gyp/test/mac/app-bundle/TestApp/English.lproj/utf-16le.strings
new file mode 100644 (file)
index 0000000..eeb3837
Binary files /dev/null and b/gyp/test/mac/app-bundle/TestApp/English.lproj/utf-16le.strings differ
diff --git a/gyp/test/mac/app-bundle/TestApp/TestApp-Info.plist b/gyp/test/mac/app-bundle/TestApp/TestApp-Info.plist
new file mode 100644 (file)
index 0000000..e005852
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>BuildMachineOSBuild</key>
+       <string>Doesn't matter, will be overwritten</string>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.google.${PRODUCT_NAME:rfc1034identifier}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>ause</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+       <key>NSMainNibFile</key>
+       <string>MainMenu</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.h b/gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.h
new file mode 100644 (file)
index 0000000..518645e
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+@interface TestAppAppDelegate : NSObject <NSApplicationDelegate> {
+    NSWindow *window;
+}
+
+@property (assign) IBOutlet NSWindow *window;
+
+@end
diff --git a/gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.m b/gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.m
new file mode 100644 (file)
index 0000000..9aafa42
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "TestAppAppDelegate.h"
+
+@implementation TestAppAppDelegate
+
+@synthesize window;
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+  // Insert code here to initialize your application
+}
+
+@end
diff --git a/gyp/test/mac/app-bundle/TestApp/main.m b/gyp/test/mac/app-bundle/TestApp/main.m
new file mode 100644 (file)
index 0000000..df6a12d
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+int main(int argc, char *argv[])
+{
+    return NSApplicationMain(argc,  (const char **) argv);
+}
diff --git a/gyp/test/mac/app-bundle/empty.c b/gyp/test/mac/app-bundle/empty.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/mac/app-bundle/test-error.gyp b/gyp/test/mac/app-bundle/test-error.gyp
new file mode 100644 (file)
index 0000000..370772c
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test App Gyp',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'TestApp/main.m',
+        'TestApp/TestApp_Prefix.pch',
+        'TestApp/TestAppAppDelegate.h',
+        'TestApp/TestAppAppDelegate.m',
+      ],
+      'mac_bundle_resources': [
+        'TestApp/English.lproj/InfoPlist-error.strings',
+        'TestApp/English.lproj/MainMenu.xib',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
+        ],
+      },
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/app-bundle/test.gyp b/gyp/test/mac/app-bundle/test.gyp
new file mode 100644 (file)
index 0000000..21973c3
--- /dev/null
@@ -0,0 +1,41 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'dep_framework',
+      'product_name': 'Dependency Framework',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'empty.c', ],
+    },
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test App Gyp',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'dependencies': [ 'dep_framework', ],
+      'sources': [
+        'TestApp/main.m',
+        'TestApp/TestApp_Prefix.pch',
+        'TestApp/TestAppAppDelegate.h',
+        'TestApp/TestAppAppDelegate.m',
+      ],
+      'mac_bundle_resources': [
+        'TestApp/English.lproj/InfoPlist.strings',  # UTF-8
+        'TestApp/English.lproj/utf-16be.strings',
+        'TestApp/English.lproj/utf-16le.strings',
+        'TestApp/English.lproj/MainMenu.xib',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
+        ],
+      },
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/archs/empty_main.cc b/gyp/test/mac/archs/empty_main.cc
new file mode 100644 (file)
index 0000000..237c8ce
--- /dev/null
@@ -0,0 +1 @@
+int main() {}
diff --git a/gyp/test/mac/archs/file.mm b/gyp/test/mac/archs/file.mm
new file mode 100644 (file)
index 0000000..d0b39d1
--- /dev/null
@@ -0,0 +1 @@
+MyInt f() { return 0; }
diff --git a/gyp/test/mac/archs/header.h b/gyp/test/mac/archs/header.h
new file mode 100644 (file)
index 0000000..0716e50
--- /dev/null
@@ -0,0 +1 @@
+typedef int MyInt;
diff --git a/gyp/test/mac/archs/my_file.cc b/gyp/test/mac/archs/my_file.cc
new file mode 100644 (file)
index 0000000..94216a7
--- /dev/null
@@ -0,0 +1,4 @@
+/* Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+int x = 1;
diff --git a/gyp/test/mac/archs/my_main_file.cc b/gyp/test/mac/archs/my_main_file.cc
new file mode 100644 (file)
index 0000000..f1fa06f
--- /dev/null
@@ -0,0 +1,9 @@
+/* Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+#include <stdio.h>
+extern int x;
+int main() {
+  printf("hello, world %d\n", x);
+}
+
diff --git a/gyp/test/mac/archs/test-archs-multiarch.gyp b/gyp/test/mac/archs/test-archs-multiarch.gyp
new file mode 100644 (file)
index 0000000..567e8a6
--- /dev/null
@@ -0,0 +1,92 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'static_32_64',
+      'type': 'static_library',
+      'sources': [ 'my_file.cc' ],
+      'xcode_settings': {
+        'ARCHS': [ 'i386', 'x86_64' ],
+      },
+    },
+    {
+      'target_name': 'shared_32_64',
+      'type': 'shared_library',
+      'sources': [ 'my_file.cc' ],
+      'xcode_settings': {
+        'ARCHS': [ 'i386', 'x86_64' ],
+      },
+    },
+    {
+      'target_name': 'shared_32_64_bundle',
+      'product_name': 'My Framework',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'my_file.cc' ],
+      'xcode_settings': {
+        'ARCHS': [ 'i386', 'x86_64' ],
+      },
+    },
+    {
+      'target_name': 'module_32_64',
+      'type': 'loadable_module',
+      'sources': [ 'my_file.cc' ],
+      'xcode_settings': {
+        'ARCHS': [ 'i386', 'x86_64' ],
+      },
+    },
+    {
+      'target_name': 'module_32_64_bundle',
+      'product_name': 'My Bundle',
+      'type': 'loadable_module',
+      'mac_bundle': 1,
+      'sources': [ 'my_file.cc' ],
+      'xcode_settings': {
+        'ARCHS': [ 'i386', 'x86_64' ],
+      },
+    },
+    {
+      'target_name': 'exe_32_64',
+      'type': 'executable',
+      'sources': [ 'empty_main.cc' ],
+      'xcode_settings': {
+        'ARCHS': [ 'i386', 'x86_64' ],
+      },
+    },
+    {
+      'target_name': 'exe_32_64_bundle',
+      'product_name': 'Test App',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [ 'empty_main.cc' ],
+      'xcode_settings': {
+        'ARCHS': [ 'i386', 'x86_64' ],
+      },
+    },
+    # This only needs to compile.
+    {
+      'target_name': 'precompiled_prefix_header_mm_32_64',
+      'type': 'shared_library',
+      'sources': [ 'file.mm', ],
+      'xcode_settings': {
+        'GCC_PREFIX_HEADER': 'header.h',
+        'GCC_PRECOMPILE_PREFIX_HEADER': 'YES',
+      },
+    },
+    # This does not compile but should not cause generation errors.
+    {
+      'target_name': 'exe_32_64_no_sources',
+      'type': 'executable',
+      'dependencies': [
+        'static_32_64',
+      ],
+      'sources': [],
+      'xcode_settings': {
+        'ARCHS': ['i386', 'x86_64'],
+      },
+    },
+  ]
+}
diff --git a/gyp/test/mac/archs/test-archs-x86_64.gyp b/gyp/test/mac/archs/test-archs-x86_64.gyp
new file mode 100644 (file)
index 0000000..d11a896
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+  {
+   'target_name': 'lib',
+   'product_name': 'Test64',
+   'type': 'static_library',
+   'sources': [ 'my_file.cc' ],
+   'xcode_settings': {
+     'ARCHS': [ 'x86_64' ],
+   },
+  },
+  {
+   'target_name': 'exe',
+   'product_name': 'Test64',
+   'type': 'executable',
+   'dependencies': [ 'lib' ],
+   'sources': [ 'my_main_file.cc' ],
+   'xcode_settings': {
+     'ARCHS': [ 'x86_64' ],
+   },
+  },
+ ]
+}
diff --git a/gyp/test/mac/archs/test-no-archs.gyp b/gyp/test/mac/archs/test-no-archs.gyp
new file mode 100644 (file)
index 0000000..8f3b6b4
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+  {
+   'target_name': 'lib',
+   'product_name': 'Test',
+   'type': 'static_library',
+   'sources': [ 'my_file.cc' ],
+  },
+  {
+   'target_name': 'exe',
+   'product_name': 'Test',
+   'type': 'executable',
+   'dependencies': [ 'lib' ],
+   'sources': [ 'my_main_file.cc' ],
+  },
+ ]
+}
diff --git a/gyp/test/mac/archs/test-valid-archs.gyp b/gyp/test/mac/archs/test-valid-archs.gyp
new file mode 100644 (file)
index 0000000..c90ec1f
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+  {
+    'target_name': 'lib',
+    'product_name': 'Test',
+    'type': 'static_library',
+    'sources': [ 'my_file.cc' ],
+    'xcode_settings': {
+      'ARCHS': ['i386', 'x86_64', 'unknown-arch'],
+      'VALID_ARCHS': ['x86_64'],
+    },
+  },
+  {
+    'target_name': 'exe',
+    'product_name': 'Test',
+    'type': 'executable',
+    'dependencies': [ 'lib' ],
+    'sources': [ 'my_main_file.cc' ],
+    'xcode_settings': {
+      'ARCHS': ['i386', 'x86_64', 'unknown-arch'],
+      'VALID_ARCHS': ['x86_64'],
+    },
+  }]
+}
diff --git a/gyp/test/mac/bundle-resources/change.sh b/gyp/test/mac/bundle-resources/change.sh
new file mode 100755 (executable)
index 0000000..6d0fe6c
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+tr a-z A-Z < "${1}" > "${2}"
diff --git a/gyp/test/mac/bundle-resources/executable-file.sh b/gyp/test/mac/bundle-resources/executable-file.sh
new file mode 100755 (executable)
index 0000000..796953a
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo echo echo echo cho ho o o
diff --git a/gyp/test/mac/bundle-resources/secret.txt b/gyp/test/mac/bundle-resources/secret.txt
new file mode 100644 (file)
index 0000000..8baef1b
--- /dev/null
@@ -0,0 +1 @@
+abc
diff --git a/gyp/test/mac/bundle-resources/test.gyp b/gyp/test/mac/bundle-resources/test.gyp
new file mode 100644 (file)
index 0000000..af034ce
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'resource',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'mac_bundle_resources': [
+        'secret.txt',
+        'executable-file.sh',
+      ],
+    },
+    # A rule with process_outputs_as_mac_bundle_resources should copy files
+    # into the Resources folder.
+    {
+      'target_name': 'source_rule',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'secret.txt',
+      ],
+      'rules': [
+        {
+          'rule_name': 'bundlerule',
+          'extension': 'txt',
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).txt',
+          ],
+          'action': ['./change.sh', '<(RULE_INPUT_PATH)', '<@(_outputs)'],
+          'message': 'Running rule on <(RULE_INPUT_PATH)',
+          'process_outputs_as_mac_bundle_resources': 1,
+        },
+      ],
+    },
+    # So should an ordinary rule acting on mac_bundle_resources.
+    {
+      'target_name': 'resource_rule',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'mac_bundle_resources': [
+        'secret.txt',
+      ],
+      'rules': [
+        {
+          'rule_name': 'bundlerule',
+          'extension': 'txt',
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).txt',
+          ],
+          'action': ['./change.sh', '<(RULE_INPUT_PATH)', '<@(_outputs)'],
+          'message': 'Running rule on <(RULE_INPUT_PATH)',
+        },
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/cflags/ccfile.cc b/gyp/test/mac/cflags/ccfile.cc
new file mode 100644 (file)
index 0000000..1a54d18
--- /dev/null
@@ -0,0 +1,7 @@
+#ifdef CFLAG
+#error CFLAG should not be set
+#endif
+
+#ifndef CCFLAG
+#error CCFLAG should be set
+#endif
diff --git a/gyp/test/mac/cflags/ccfile_withcflags.cc b/gyp/test/mac/cflags/ccfile_withcflags.cc
new file mode 100644 (file)
index 0000000..de078a0
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef CFLAG
+#error CFLAG should be set
+#endif
+
+#ifndef CCFLAG
+#error CCFLAG should be set
+#endif
diff --git a/gyp/test/mac/cflags/cfile.c b/gyp/test/mac/cflags/cfile.c
new file mode 100644 (file)
index 0000000..0af9d0a
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef CFLAG
+#error CFLAG should be set
+#endif
+
+#ifdef CCFLAG
+#error CCFLAG should not be set
+#endif
diff --git a/gyp/test/mac/cflags/cppfile.cpp b/gyp/test/mac/cflags/cppfile.cpp
new file mode 100644 (file)
index 0000000..1a54d18
--- /dev/null
@@ -0,0 +1,7 @@
+#ifdef CFLAG
+#error CFLAG should not be set
+#endif
+
+#ifndef CCFLAG
+#error CCFLAG should be set
+#endif
diff --git a/gyp/test/mac/cflags/cppfile_withcflags.cpp b/gyp/test/mac/cflags/cppfile_withcflags.cpp
new file mode 100644 (file)
index 0000000..de078a0
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef CFLAG
+#error CFLAG should be set
+#endif
+
+#ifndef CCFLAG
+#error CCFLAG should be set
+#endif
diff --git a/gyp/test/mac/cflags/cxxfile.cxx b/gyp/test/mac/cflags/cxxfile.cxx
new file mode 100644 (file)
index 0000000..1a54d18
--- /dev/null
@@ -0,0 +1,7 @@
+#ifdef CFLAG
+#error CFLAG should not be set
+#endif
+
+#ifndef CCFLAG
+#error CCFLAG should be set
+#endif
diff --git a/gyp/test/mac/cflags/cxxfile_withcflags.cxx b/gyp/test/mac/cflags/cxxfile_withcflags.cxx
new file mode 100644 (file)
index 0000000..de078a0
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef CFLAG
+#error CFLAG should be set
+#endif
+
+#ifndef CCFLAG
+#error CCFLAG should be set
+#endif
diff --git a/gyp/test/mac/cflags/mfile.m b/gyp/test/mac/cflags/mfile.m
new file mode 100644 (file)
index 0000000..0af9d0a
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef CFLAG
+#error CFLAG should be set
+#endif
+
+#ifdef CCFLAG
+#error CCFLAG should not be set
+#endif
diff --git a/gyp/test/mac/cflags/mmfile.mm b/gyp/test/mac/cflags/mmfile.mm
new file mode 100644 (file)
index 0000000..1a54d18
--- /dev/null
@@ -0,0 +1,7 @@
+#ifdef CFLAG
+#error CFLAG should not be set
+#endif
+
+#ifndef CCFLAG
+#error CCFLAG should be set
+#endif
diff --git a/gyp/test/mac/cflags/mmfile_withcflags.mm b/gyp/test/mac/cflags/mmfile_withcflags.mm
new file mode 100644 (file)
index 0000000..de078a0
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef CFLAG
+#error CFLAG should be set
+#endif
+
+#ifndef CCFLAG
+#error CCFLAG should be set
+#endif
diff --git a/gyp/test/mac/cflags/test.gyp b/gyp/test/mac/cflags/test.gyp
new file mode 100644 (file)
index 0000000..d330a54
--- /dev/null
@@ -0,0 +1,132 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'mytarget',
+      'type': 'shared_library',
+      'sources': [
+        'cfile.c',
+        'mfile.m',
+        'ccfile.cc',
+        'cppfile.cpp',
+        'cxxfile.cxx',
+        'mmfile.mm',
+      ],
+      'xcode_settings': {
+        # Normally, defines would go in 'defines' instead. This is just for
+        # testing.
+        'OTHER_CFLAGS': [
+          '-DCFLAG',
+        ],
+        'OTHER_CPLUSPLUSFLAGS': [
+          '-DCCFLAG',
+        ],
+        'GCC_C_LANGUAGE_STANDARD': 'c99',
+      },
+    },
+    {
+      'target_name': 'mytarget_reuse_cflags',
+      'type': 'shared_library',
+      'sources': [
+        'cfile.c',
+        'mfile.m',
+        'ccfile_withcflags.cc',
+        'cppfile_withcflags.cpp',
+        'cxxfile_withcflags.cxx',
+        'mmfile_withcflags.mm',
+      ],
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-DCFLAG',
+        ],
+        'OTHER_CPLUSPLUSFLAGS': [
+          '$OTHER_CFLAGS',
+          '-DCCFLAG',
+        ],
+        # This is a C-only flag, to check these don't get added to C++ files.
+        'GCC_C_LANGUAGE_STANDARD': 'c99',
+      },
+    },
+    {
+      'target_name': 'mytarget_inherit_cflags',
+      'type': 'shared_library',
+      'sources': [
+        'cfile.c',
+        'mfile.m',
+        'ccfile_withcflags.cc',
+        'cppfile_withcflags.cpp',
+        'cxxfile_withcflags.cxx',
+        'mmfile_withcflags.mm',
+      ],
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-DCFLAG',
+        ],
+        'OTHER_CPLUSPLUSFLAGS': [
+          '$inherited',
+          '-DCCFLAG',
+        ],
+        'GCC_C_LANGUAGE_STANDARD': 'c99',
+      },
+    },
+    {
+      'target_name': 'mytarget_inherit_cflags_parens',
+      'type': 'shared_library',
+      'sources': [
+        'cfile.c',
+        'mfile.m',
+        'ccfile_withcflags.cc',
+        'cppfile_withcflags.cpp',
+        'cxxfile_withcflags.cxx',
+        'mmfile_withcflags.mm',
+      ],
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-DCFLAG',
+        ],
+        'OTHER_CPLUSPLUSFLAGS': [
+          '$(inherited)',
+          '-DCCFLAG',
+        ],
+        'GCC_C_LANGUAGE_STANDARD': 'c99',
+      },
+    },
+    {
+      'target_name': 'mytarget_inherit_cflags_braces',
+      'type': 'shared_library',
+      'sources': [
+        'cfile.c',
+        'mfile.m',
+        'ccfile_withcflags.cc',
+        'cppfile_withcflags.cpp',
+        'cxxfile_withcflags.cxx',
+        'mmfile_withcflags.mm',
+      ],
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-DCFLAG',
+        ],
+        'OTHER_CPLUSPLUSFLAGS': [
+          '${inherited}',
+          '-DCCFLAG',
+        ],
+        'GCC_C_LANGUAGE_STANDARD': 'c99',
+      },
+    },
+    {
+      'target_name': 'ansi_standard',
+      'type': 'shared_library',
+      'sources': [
+        'cfile.c',
+      ],
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-DCFLAG',
+        ],
+        'GCC_C_LANGUAGE_STANDARD': 'ansi',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/clang-cxx-language-standard/c++11.cc b/gyp/test/mac/clang-cxx-language-standard/c++11.cc
new file mode 100644 (file)
index 0000000..756dc1c
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+static_assert(__cplusplus == 201103L, "wrong c++ standard version");
+
+int main() { return 0; }
+
diff --git a/gyp/test/mac/clang-cxx-language-standard/c++98.cc b/gyp/test/mac/clang-cxx-language-standard/c++98.cc
new file mode 100644 (file)
index 0000000..a6a00c7
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if __cplusplus != 199711L
+#error wrong c++ standard version
+#endif
+
+enum cxx11_keywords {
+  alignas,
+  alignof,
+  char16_t,
+  char32_t,
+  constexpr,
+  decltype,
+  noexcept,
+  nullptr,
+  override,
+  static_assert,
+  thread_local,
+};
+
+int main() { return 0; }
+
diff --git a/gyp/test/mac/clang-cxx-language-standard/clang-cxx-language-standard.gyp b/gyp/test/mac/clang-cxx-language-standard/clang-cxx-language-standard.gyp
new file mode 100644 (file)
index 0000000..eb60bbd
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+    ['CXX', '/usr/bin/clang++'],
+  ],
+  'targets': [
+    {
+      'target_name': 'c++98',
+      'type': 'executable',
+      'sources': [ 'c++98.cc', ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'CLANG_CXX_LANGUAGE_STANDARD': 'c++98',
+      },
+    },
+    {
+      'target_name': 'c++11',
+      'type': 'executable',
+      'sources': [ 'c++11.cc', ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'CLANG_CXX_LANGUAGE_STANDARD': 'c++0x',
+      },
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/clang-cxx-library/clang-cxx-library.gyp b/gyp/test/mac/clang-cxx-library/clang-cxx-library.gyp
new file mode 100644 (file)
index 0000000..67006e5
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+    ['CXX', '/usr/bin/clang++'],
+  ],
+  'targets': [
+    {
+      'target_name': 'libc++',
+      'type': 'executable',
+      'sources': [ 'libc++.cc', ],
+      'xcode_settings': {
+        'CC': 'clang',
+        # libc++ requires OS X 10.7+.
+        'MACOSX_DEPLOYMENT_TARGET': '10.7',
+        'CLANG_CXX_LIBRARY': 'libc++',
+      },
+    },
+    {
+      'target_name': 'libstdc++',
+      'type': 'executable',
+      'sources': [ 'libstdc++.cc', ],
+      'xcode_settings': {
+        'CC': 'clang',
+        'CLANG_CXX_LIBRARY': 'libstdc++',
+      },
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/clang-cxx-library/libc++.cc b/gyp/test/mac/clang-cxx-library/libc++.cc
new file mode 100644 (file)
index 0000000..b8d6e6b
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#ifndef _LIBCPP_VERSION
+#error expected std library: libc++
+#endif
+
+int main() { std::string x; return x.size(); }
+
diff --git a/gyp/test/mac/clang-cxx-library/libstdc++.cc b/gyp/test/mac/clang-cxx-library/libstdc++.cc
new file mode 100644 (file)
index 0000000..474dbf3
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#ifndef __GLIBCXX__
+#error expected std library: libstdc++
+#endif
+
+int main() { std::string x; return x.size(); }
+
diff --git a/gyp/test/mac/copy-dylib/empty.c b/gyp/test/mac/copy-dylib/empty.c
new file mode 100644 (file)
index 0000000..237c8ce
--- /dev/null
@@ -0,0 +1 @@
+int main() {}
diff --git a/gyp/test/mac/copy-dylib/test.gyp b/gyp/test/mac/copy-dylib/test.gyp
new file mode 100644 (file)
index 0000000..4210c51
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'my_dylib',
+      'type': 'shared_library',
+      'sources': [ 'empty.c', ],
+    },
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test App',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'dependencies': [ 'my_dylib', ],
+      'sources': [
+        'empty.c',
+      ],
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/Test App.app/Contents/Resources',
+          'files': [
+            '<(PRODUCT_DIR)/libmy_dylib.dylib',
+          ],
+        },
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/debuginfo/file.c b/gyp/test/mac/debuginfo/file.c
new file mode 100644 (file)
index 0000000..9cddaf1
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+void f() {}
+int main() {}
diff --git a/gyp/test/mac/debuginfo/test.gyp b/gyp/test/mac/debuginfo/test.gyp
new file mode 100644 (file)
index 0000000..3faf6b5
--- /dev/null
@@ -0,0 +1,82 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'nonbundle_static_library',
+      'type': 'static_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+      },
+    },
+    {
+      'target_name': 'nonbundle_shared_library',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+      },
+    },
+    {
+      'target_name': 'nonbundle_loadable_module',
+      'type': 'loadable_module',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+      },
+    },
+    {
+      'target_name': 'nonbundle_executable',
+      'type': 'executable',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+      },
+    },
+
+    {
+      'target_name': 'bundle_shared_library',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+      },
+    },
+    {
+      'target_name': 'bundle_loadable_module',
+      'type': 'loadable_module',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+      },
+    },
+    {
+      'target_name': 'my_app',
+      'product_name': 'My App',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/depend-on-bundle/English.lproj/InfoPlist.strings b/gyp/test/mac/depend-on-bundle/English.lproj/InfoPlist.strings
new file mode 100644 (file)
index 0000000..b92732c
--- /dev/null
@@ -0,0 +1 @@
+/* Localized versions of Info.plist keys */
diff --git a/gyp/test/mac/depend-on-bundle/Info.plist b/gyp/test/mac/depend-on-bundle/Info.plist
new file mode 100644 (file)
index 0000000..5e05a51
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.yourcompany.${PRODUCT_NAME}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>NSPrincipalClass</key>
+       <string></string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/depend-on-bundle/bundle.c b/gyp/test/mac/depend-on-bundle/bundle.c
new file mode 100644 (file)
index 0000000..d64ff8c
--- /dev/null
@@ -0,0 +1 @@
+int f() { return 42; }
diff --git a/gyp/test/mac/depend-on-bundle/executable.c b/gyp/test/mac/depend-on-bundle/executable.c
new file mode 100644 (file)
index 0000000..931bce6
--- /dev/null
@@ -0,0 +1,4 @@
+int f();
+int main() {
+  return f();
+}
diff --git a/gyp/test/mac/depend-on-bundle/test.gyp b/gyp/test/mac/depend-on-bundle/test.gyp
new file mode 100644 (file)
index 0000000..e00b105
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'my_bundle',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'bundle.c' ],
+      'mac_bundle_resources': [
+        'English.lproj/InfoPlist.strings',
+      ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+      }
+    },
+    {
+      'target_name': 'dependent_on_bundle',
+      'type': 'executable',
+      'sources': [ 'executable.c' ],
+      'dependencies': [
+        'my_bundle',
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/deployment-target/check-version-min.c b/gyp/test/mac/deployment-target/check-version-min.c
new file mode 100644 (file)
index 0000000..761c529
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (c) 2013 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <Availability.h>
+
+/* GYPTEST_MAC_VERSION_MIN: should be set to the corresponding value of
+ * xcode setting 'MACOSX_DEPLOYMENT_TARGET', otherwise both should be
+ * left undefined.
+ *
+ * GYPTEST_IOS_VERSION_MIN: should be set to the corresponding value of
+ * xcode setting 'IPHONEOS_DEPLOYMENT_TARGET', otherwise both should be
+ * left undefined.
+ */
+
+#if defined(GYPTEST_MAC_VERSION_MIN)
+# if GYPTEST_MAC_VERSION_MIN != __MAC_OS_X_VERSION_MIN_REQUIRED
+#  error __MAC_OS_X_VERSION_MIN_REQUIRED has wrong value
+# endif
+#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+# error __MAC_OS_X_VERSION_MIN_REQUIRED should be undefined
+#endif
+
+#if defined(GYPTEST_IOS_VERSION_MIN)
+# if GYPTEST_IOS_VERSION_MIN != __IPHONE_OS_VERSION_MIN_REQUIRED
+#  error __IPHONE_OS_VERSION_MIN_REQUIRED has wrong value
+# endif
+#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+# error __IPHONE_OS_VERSION_MIN_REQUIRED should be undefined
+#endif
+
+int main() { return 0; }
+
diff --git a/gyp/test/mac/deployment-target/deployment-target.gyp b/gyp/test/mac/deployment-target/deployment-target.gyp
new file mode 100644 (file)
index 0000000..47e0565
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'macosx-version-min-10.5',
+      'type': 'executable',
+      'sources': [ 'check-version-min.c', ],
+      'defines': [ 'GYPTEST_MAC_VERSION_MIN=1050', ],
+      'xcode_settings': {
+        'SDKROOT': 'macosx',
+        'MACOSX_DEPLOYMENT_TARGET': '10.5',
+      },
+    },
+    {
+      'target_name': 'macosx-version-min-10.6',
+      'type': 'executable',
+      'sources': [ 'check-version-min.c', ],
+      'defines': [ 'GYPTEST_MAC_VERSION_MIN=1060', ],
+      'xcode_settings': {
+        'SDKROOT': 'macosx',
+        'MACOSX_DEPLOYMENT_TARGET': '10.6',
+      },
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/framework-dirs/calculate.c b/gyp/test/mac/framework-dirs/calculate.c
new file mode 100644 (file)
index 0000000..7dc9d2d
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+int CalculatePerformExpression(char* expr,
+                               int significantDigits,
+                               int flags,
+                               char* answer);
+
+int main() {
+  char buffer[1024];
+  return CalculatePerformExpression("42", 1, 0, buffer);
+}
+
diff --git a/gyp/test/mac/framework-dirs/framework-dirs.gyp b/gyp/test/mac/framework-dirs/framework-dirs.gyp
new file mode 100644 (file)
index 0000000..bf1cbde
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'calculate',
+      'type': 'executable',
+      'sources': [
+        'calculate.c',
+      ],
+      'libraries': [
+        '/System/Library/PrivateFrameworks/Calculate.framework',
+      ],
+      'mac_framework_dirs': [
+        '/System/Library/PrivateFrameworks',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/framework-headers/myframework.h b/gyp/test/mac/framework-headers/myframework.h
new file mode 100644 (file)
index 0000000..961fc70
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Foundation/Foundation.h>
+
+@interface TestObject : NSObject
+@end
diff --git a/gyp/test/mac/framework-headers/myframework.m b/gyp/test/mac/framework-headers/myframework.m
new file mode 100644 (file)
index 0000000..13d53a3
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "myframework.h"
+
+@implementation TestObject
+@end
diff --git a/gyp/test/mac/framework-headers/test.gyp b/gyp/test/mac/framework-headers/test.gyp
new file mode 100644 (file)
index 0000000..70ed007
--- /dev/null
@@ -0,0 +1,44 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {    
+      'target_name': 'test_framework_headers_framework',
+      'product_name': 'TestFramework',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [
+        'myframework.h',
+        'myframework.m',
+      ],
+      'mac_framework_headers': [
+        'myframework.h',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+        ],
+      },
+    },{    
+      'target_name': 'test_framework_headers_static',
+      'product_name': 'TestLibrary',
+      'type': 'static_library',
+      'xcode_settings': {
+        'PUBLIC_HEADERS_FOLDER_PATH': 'include',
+      },      
+      'sources': [
+        'myframework.h',
+        'myframework.m',
+      ],
+      'mac_framework_headers': [
+        'myframework.h',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+        ],
+      },      
+    },  
+  ],
+}
diff --git a/gyp/test/mac/framework/TestFramework/English.lproj/InfoPlist.strings b/gyp/test/mac/framework/TestFramework/English.lproj/InfoPlist.strings
new file mode 100644 (file)
index 0000000..88f65cf
--- /dev/null
@@ -0,0 +1,2 @@
+/* Localized versions of Info.plist keys */
+
diff --git a/gyp/test/mac/framework/TestFramework/Info.plist b/gyp/test/mac/framework/TestFramework/Info.plist
new file mode 100644 (file)
index 0000000..a791b3e
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>NSPrincipalClass</key>
+       <string></string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/framework/TestFramework/ObjCVector.h b/gyp/test/mac/framework/TestFramework/ObjCVector.h
new file mode 100644 (file)
index 0000000..c245096
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#ifdef __cplusplus
+struct ObjCVectorImp;
+#else
+typedef struct _ObjCVectorImpT ObjCVectorImp;
+#endif
+
+@interface ObjCVector : NSObject {
+ @private
+  ObjCVectorImp* imp_;
+}
+
+- (id)init;
+
+- (void)addObject:(id)obj;
+- (void)addObject:(id)obj atIndex:(NSUInteger)index;
+
+- (void)removeObject:(id)obj;
+- (void)removeObjectAtIndex:(NSUInteger)index;
+
+- (id)objectAtIndex:(NSUInteger)index;
+
+@end
diff --git a/gyp/test/mac/framework/TestFramework/ObjCVector.mm b/gyp/test/mac/framework/TestFramework/ObjCVector.mm
new file mode 100644 (file)
index 0000000..cbf431f
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ObjCVectorInternal.h"
+#import "ObjCVector.h"
+
+#include <vector>
+
+@interface ObjCVector (Private)
+- (std::vector<id>::iterator)makeIterator:(NSUInteger)index;
+@end
+
+@implementation ObjCVector
+
+- (id)init {
+  if ((self = [super init])) {
+    imp_ = new ObjCVectorImp();
+  }
+  return self;
+}
+
+- (void)dealloc {
+  delete imp_;
+  [super dealloc];
+}
+
+- (void)addObject:(id)obj {
+  imp_->v.push_back([obj retain]);
+}
+
+- (void)addObject:(id)obj atIndex:(NSUInteger)index {
+  imp_->v.insert([self makeIterator:index], [obj retain]);
+}
+
+- (void)removeObject:(id)obj {
+  for (std::vector<id>::iterator it = imp_->v.begin();
+       it != imp_->v.end();
+       ++it) {
+    if ([*it isEqual:obj]) {
+      [*it autorelease];
+      imp_->v.erase(it);
+      return;
+    }
+  }
+}
+
+- (void)removeObjectAtIndex:(NSUInteger)index {
+  [imp_->v[index] autorelease];
+  imp_->v.erase([self makeIterator:index]);
+}
+
+- (id)objectAtIndex:(NSUInteger)index {
+  return imp_->v[index];
+}
+
+- (std::vector<id>::iterator)makeIterator:(NSUInteger)index {
+  std::vector<id>::iterator it = imp_->v.begin();
+  it += index;
+  return it;
+}
+
+@end
diff --git a/gyp/test/mac/framework/TestFramework/ObjCVectorInternal.h b/gyp/test/mac/framework/TestFramework/ObjCVectorInternal.h
new file mode 100644 (file)
index 0000000..fb6c982
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+struct ObjCVectorImp {
+  std::vector<id> v;
+};
diff --git a/gyp/test/mac/framework/TestFramework/TestFramework_Prefix.pch b/gyp/test/mac/framework/TestFramework/TestFramework_Prefix.pch
new file mode 100644 (file)
index 0000000..394f41d
--- /dev/null
@@ -0,0 +1,7 @@
+//
+// Prefix header for all source files of the 'TestFramework' target in the 'TestFramework' project.
+//
+
+#ifdef __OBJC__
+    #import <Cocoa/Cocoa.h>
+#endif
diff --git a/gyp/test/mac/framework/empty.c b/gyp/test/mac/framework/empty.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/mac/framework/framework.gyp b/gyp/test/mac/framework/framework.gyp
new file mode 100644 (file)
index 0000000..ce266c3
--- /dev/null
@@ -0,0 +1,71 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'dep_framework',
+      'product_name': 'Dependency Bundle',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'empty.c', ],
+    },
+    {    
+      'target_name': 'test_framework',
+      'product_name': 'Test Framework',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'dependencies': [ 'dep_framework', ],
+      'sources': [
+        'TestFramework/ObjCVector.h',
+        'TestFramework/ObjCVectorInternal.h',
+        'TestFramework/ObjCVector.mm',
+      ],
+      'mac_bundle_resources': [
+        'TestFramework/English.lproj/InfoPlist.strings',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
+        ],
+      },
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'TestFramework/Info.plist',
+        'GCC_DYNAMIC_NO_PIC': 'NO',
+      },
+      'copies': [
+        # Test copying to a file that has envvars in its dest path.
+        # Needs to be in a mac_bundle target, else CONTENTS_FOLDER_PATH isn't
+        # set.
+        {
+          'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Libraries',
+          'files': [
+            'empty.c',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'copy_target',
+      'type': 'none',
+      'dependencies': [ 'test_framework', 'dep_framework', ],
+      'copies': [
+        # Test copying directories with spaces in src and dest paths.
+        {
+          'destination': '<(PRODUCT_DIR)/Test Framework.framework/foo',
+          'files': [
+            '<(PRODUCT_DIR)/Dependency Bundle.framework',
+          ],
+        },
+      ],
+      'actions': [
+        {
+          'action_name': 'aektschn',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/touched_file'],
+          'action': ['touch', '${BUILT_PRODUCTS_DIR}/action_file'],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/global-settings/src/dir1/dir1.gyp b/gyp/test/mac/global-settings/src/dir1/dir1.gyp
new file mode 100644 (file)
index 0000000..153e34d
--- /dev/null
@@ -0,0 +1,11 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'dir1_target',
+      'type': 'none',
+    },
+  ],
+}
diff --git a/gyp/test/mac/global-settings/src/dir2/dir2.gyp b/gyp/test/mac/global-settings/src/dir2/dir2.gyp
new file mode 100644 (file)
index 0000000..cda46c8
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'dir2_target',
+      'type': 'none',
+      'dependencies': [
+        '../dir1/dir1.gyp:dir1_target',
+      ],
+      'actions': [
+        {
+          'inputs': [ ],
+          'outputs': [ '<(PRODUCT_DIR)/file.txt' ],
+          'action_name': 'Test action',
+          'action': ['cp', 'file.txt', '${BUILT_PRODUCTS_DIR}/file.txt' ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/global-settings/src/dir2/file.txt b/gyp/test/mac/global-settings/src/dir2/file.txt
new file mode 100644 (file)
index 0000000..58da2d8
--- /dev/null
@@ -0,0 +1 @@
+File.
diff --git a/gyp/test/mac/gyptest-action-envvars.py b/gyp/test/mac/gyptest-action-envvars.py
new file mode 100644 (file)
index 0000000..b4f37c4
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that env vars work with actions, with relative directory paths.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'action-envvars'
+  test.run_gyp('action/action.gyp', chdir=CHDIR)
+  test.build('action/action.gyp', 'action', chdir=CHDIR, SYMROOT='../build')
+
+  result_file = test.built_file_path('result', chdir=CHDIR)
+  test.must_exist(result_file)
+  test.must_contain(result_file, 'Test output')
+
+  other_result_file = test.built_file_path('other_result', chdir=CHDIR)
+  test.must_exist(other_result_file)
+  test.must_contain(other_result_file, 'Other output')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-app-error.py b/gyp/test/mac/gyptest-app-error.py
new file mode 100755 (executable)
index 0000000..a62af6b
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that invalid strings files cause the build to fail.
+"""
+
+import TestCmd
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  expected_error = 'Old-style plist parser: missing semicolon in dictionary'
+  saw_expected_error = [False]  # Python2 has no "nonlocal" keyword.
+  def match(a, b):
+    if a == b:
+      return True
+    if not TestCmd.is_List(a):
+      a = a.split('\n')
+    if not TestCmd.is_List(b):
+      b = b.split('\n')
+    if expected_error in '\n'.join(a) + '\n'.join(b):
+      saw_expected_error[0] = True
+      return True
+    return False
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'], match=match)
+
+  test.run_gyp('test-error.gyp', chdir='app-bundle')
+
+  test.build('test-error.gyp', test.ALL, chdir='app-bundle')
+
+  # Ninja pipes stderr of subprocesses to stdout.
+  if test.format == 'ninja' and expected_error in test.stdout():
+    saw_expected_error[0] = True
+
+  if saw_expected_error[0]:
+    test.pass_test()
+  else:
+    test.fail_test()
diff --git a/gyp/test/mac/gyptest-app.py b/gyp/test/mac/gyptest-app.py
new file mode 100755 (executable)
index 0000000..49a5bfa
--- /dev/null
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that app bundles are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import os
+import plistlib
+import subprocess
+import sys
+
+
+def ExpectEq(expected, actual):
+  if expected != actual:
+    print >>sys.stderr, 'Expected "%s", got "%s"' % (expected, actual)
+    test.fail_test()
+
+def ls(path):
+  '''Returns a list of all files in a directory, relative to the directory.'''
+  result = []
+  for dirpath, _, files in os.walk(path):
+    for f in files:
+      result.append(os.path.join(dirpath, f)[len(path) + 1:])
+  return result
+
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('test.gyp', chdir='app-bundle')
+
+  test.build('test.gyp', test.ALL, chdir='app-bundle')
+
+  # Binary
+  test.built_file_must_exist('Test App Gyp.app/Contents/MacOS/Test App Gyp',
+                             chdir='app-bundle')
+
+  # Info.plist
+  info_plist = test.built_file_path('Test App Gyp.app/Contents/Info.plist',
+                                    chdir='app-bundle')
+  test.must_exist(info_plist)
+  test.must_contain(info_plist, 'com.google.Test-App-Gyp')  # Variable expansion
+  test.must_not_contain(info_plist, '${MACOSX_DEPLOYMENT_TARGET}');
+
+  if test.format != 'make':
+    # TODO: Synthesized plist entries aren't hooked up in the make generator.
+    machine = subprocess.check_output(['sw_vers', '-buildVersion']).rstrip('\n')
+    plist = plistlib.readPlist(info_plist)
+    ExpectEq(machine, plist['BuildMachineOSBuild'])
+
+    # Prior to Xcode 5.0.0, SDKROOT (and thus DTSDKName) was only defined if
+    # set in the Xcode project file. Starting with that version, it is always
+    # defined.
+    expected = ''
+    if TestMac.Xcode.Version() >= '0500':
+      version = TestMac.Xcode.SDKVersion()
+      expected = 'macosx' + version
+    ExpectEq(expected, plist['DTSDKName'])
+    sdkbuild = TestMac.Xcode.SDKBuild()
+    if not sdkbuild:
+      # Above command doesn't work in Xcode 4.2.
+      sdkbuild = plist['BuildMachineOSBuild']
+    ExpectEq(sdkbuild, plist['DTSDKBuild'])
+    ExpectEq(TestMac.Xcode.Version(), plist['DTXcode'])
+    ExpectEq(TestMac.Xcode.Build(), plist['DTXcodeBuild'])
+
+  # Resources
+  strings_files = ['InfoPlist.strings', 'utf-16be.strings', 'utf-16le.strings']
+  for f in strings_files:
+    strings = test.built_file_path(
+        os.path.join('Test App Gyp.app/Contents/Resources/English.lproj', f),
+        chdir='app-bundle')
+    test.must_exist(strings)
+    # Xcodes writes UTF-16LE with BOM.
+    contents = open(strings, 'rb').read()
+    if not contents.startswith('\xff\xfe' + '/* Localized'.encode('utf-16le')):
+      test.fail_test()
+
+  test.built_file_must_exist(
+      'Test App Gyp.app/Contents/Resources/English.lproj/MainMenu.nib',
+      chdir='app-bundle')
+
+  # Packaging
+  test.built_file_must_exist('Test App Gyp.app/Contents/PkgInfo',
+                             chdir='app-bundle')
+  test.built_file_must_match('Test App Gyp.app/Contents/PkgInfo', 'APPLause',
+                             chdir='app-bundle')
+
+  # Check that no other files get added to the bundle.
+  if set(ls(test.built_file_path('Test App Gyp.app', chdir='app-bundle'))) != \
+     set(['Contents/MacOS/Test App Gyp',
+          'Contents/Info.plist',
+          'Contents/Resources/English.lproj/MainMenu.nib',
+          'Contents/PkgInfo',
+          ] +
+         [os.path.join('Contents/Resources/English.lproj', f)
+             for f in strings_files]):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-archs.py b/gyp/test/mac/gyptest-archs.py
new file mode 100644 (file)
index 0000000..ff632d7
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests things related to ARCHS.
+"""
+
+import TestGyp
+import TestMac
+
+import re
+import subprocess
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('test-no-archs.gyp', chdir='archs')
+  test.build('test-no-archs.gyp', test.ALL, chdir='archs')
+  result_file = test.built_file_path('Test', chdir='archs')
+  test.must_exist(result_file)
+
+  if TestMac.Xcode.Version() >= '0500':
+    expected_type = ['x86_64']
+  else:
+    expected_type = ['i386']
+  TestMac.CheckFileType(test, result_file, expected_type)
+
+  test.run_gyp('test-valid-archs.gyp', chdir='archs')
+  test.build('test-valid-archs.gyp', test.ALL, chdir='archs')
+  result_file = test.built_file_path('Test', chdir='archs')
+  test.must_exist(result_file)
+  TestMac.CheckFileType(test, result_file, ['x86_64'])
+
+  test.run_gyp('test-archs-x86_64.gyp', chdir='archs')
+  test.build('test-archs-x86_64.gyp', test.ALL, chdir='archs')
+  result_file = test.built_file_path('Test64', chdir='archs')
+  test.must_exist(result_file)
+  TestMac.CheckFileType(test, result_file, ['x86_64'])
+
+  if test.format != 'make':
+    # Build all targets except 'exe_32_64_no_sources' that does build
+    # but should not cause error when generating ninja files
+    targets = [
+        'static_32_64', 'shared_32_64', 'shared_32_64_bundle',
+        'module_32_64', 'module_32_64_bundle',
+        'exe_32_64', 'exe_32_64_bundle', 'precompiled_prefix_header_mm_32_64',
+    ]
+
+    test.run_gyp('test-archs-multiarch.gyp', chdir='archs')
+    for target in targets:
+      test.build('test-archs-multiarch.gyp', target=target, chdir='archs')
+
+    result_file = test.built_file_path(
+        'static_32_64', chdir='archs', type=test.STATIC_LIB)
+    test.must_exist(result_file)
+    TestMac.CheckFileType(test, result_file, ['i386', 'x86_64'])
+
+    result_file = test.built_file_path(
+        'shared_32_64', chdir='archs', type=test.SHARED_LIB)
+    test.must_exist(result_file)
+    TestMac.CheckFileType(test, result_file, ['i386', 'x86_64'])
+
+    result_file = test.built_file_path('My Framework.framework/My Framework',
+                                       chdir='archs')
+    test.must_exist(result_file)
+    TestMac.CheckFileType(test, result_file, ['i386', 'x86_64'])
+    # Check that symbol "_x" made it into both versions of the binary:
+    if not all(['D _x' in subprocess.check_output(
+        ['nm', '-arch', arch, result_file]) for arch in ['i386', 'x86_64']]):
+      # This can only flakily fail, due to process ordering issues. If this
+      # does fail flakily, then something's broken, it's not the test at fault.
+      test.fail_test()
+
+    result_file = test.built_file_path(
+        'exe_32_64', chdir='archs', type=test.EXECUTABLE)
+    test.must_exist(result_file)
+    TestMac.CheckFileType(test, result_file, ['i386', 'x86_64'])
+
+    result_file = test.built_file_path('Test App.app/Contents/MacOS/Test App',
+                                       chdir='archs')
+    test.must_exist(result_file)
+    TestMac.CheckFileType(test, result_file, ['i386', 'x86_64'])
diff --git a/gyp/test/mac/gyptest-bundle-resources.py b/gyp/test/mac/gyptest-bundle-resources.py
new file mode 100644 (file)
index 0000000..824b17f
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies things related to bundle resources.
+"""
+
+import TestGyp
+
+import os
+import stat
+import sys
+
+
+def check_attribs(path, expected_exec_bit):
+  out_path = test.built_file_path(
+      os.path.join('resource.app/Contents/Resources', path), chdir=CHDIR)
+
+  in_stat = os.stat(os.path.join(CHDIR, path))
+  out_stat = os.stat(out_path)
+  if in_stat.st_mtime == out_stat.st_mtime:
+    test.fail_test()
+  if out_stat.st_mode & stat.S_IXUSR != expected_exec_bit:
+    test.fail_test()
+
+
+if sys.platform == 'darwin':
+  # set |match| to ignore build stderr output.
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'bundle-resources'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+  test.built_file_must_match('resource.app/Contents/Resources/secret.txt',
+                             'abc\n', chdir=CHDIR)
+  test.built_file_must_match('source_rule.app/Contents/Resources/secret.txt',
+                             'ABC\n', chdir=CHDIR)
+
+  test.built_file_must_match(
+      'resource.app/Contents/Resources/executable-file.sh',
+      '#!/bin/bash\n'
+      '\n'
+      'echo echo echo echo cho ho o o\n', chdir=CHDIR)
+
+  check_attribs('executable-file.sh', expected_exec_bit=stat.S_IXUSR)
+  check_attribs('secret.txt', expected_exec_bit=0)
+
+  # TODO(thakis): This currently fails with make.
+  if test.format != 'make':
+    test.built_file_must_match(
+        'resource_rule.app/Contents/Resources/secret.txt', 'ABC\n', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-cflags.py b/gyp/test/mac/gyptest-cflags.py
new file mode 100644 (file)
index 0000000..7d24863
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that compile-time flags work.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+  CHDIR = 'cflags'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-clang-cxx-language-standard.py b/gyp/test/mac/gyptest-clang-cxx-language-standard.py
new file mode 100644 (file)
index 0000000..75c6c74
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that CLANG_CXX_LANGUAGE_STANDARD works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode'])
+
+  test.run_gyp('clang-cxx-language-standard.gyp',
+               chdir='clang-cxx-language-standard')
+
+  test.build('clang-cxx-language-standard.gyp', test.ALL,
+             chdir='clang-cxx-language-standard')
+
+  test.pass_test()
+
diff --git a/gyp/test/mac/gyptest-clang-cxx-library.py b/gyp/test/mac/gyptest-clang-cxx-library.py
new file mode 100644 (file)
index 0000000..39a11c7
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that CLANG_CXX_LIBRARY works.
+"""
+
+import TestGyp
+import TestMac
+
+import os
+import sys
+
+if sys.platform == 'darwin':
+  # Xcode 4.2 on OS X 10.6 doesn't install the libc++ headers, don't run this
+  # test there.
+  if TestMac.Xcode.Version() <= '0420':
+    sys.exit(0)
+
+  test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode'])
+  test.run_gyp('clang-cxx-library.gyp', chdir='clang-cxx-library')
+  test.build('clang-cxx-library.gyp', test.ALL, chdir='clang-cxx-library')
+
+  test.pass_test()
+
diff --git a/gyp/test/mac/gyptest-copies.py b/gyp/test/mac/gyptest-copies.py
new file mode 100755 (executable)
index 0000000..c88065e
--- /dev/null
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that 'copies' with app bundles are handled correctly.
+"""
+
+import TestGyp
+
+import os
+import sys
+import time
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('framework.gyp', chdir='framework')
+
+  test.build('framework.gyp', 'copy_target', chdir='framework')
+
+  # Check that the copy succeeded.
+  test.built_file_must_exist(
+      'Test Framework.framework/foo/Dependency Bundle.framework',
+      chdir='framework')
+  test.built_file_must_exist(
+      'Test Framework.framework/foo/Dependency Bundle.framework/Versions/A',
+      chdir='framework')
+  test.built_file_must_exist(
+      'Test Framework.framework/Versions/A/Libraries/empty.c',
+      chdir='framework')
+
+
+  # Check that rebuilding the target a few times works.
+  dep_bundle = test.built_file_path('Dependency Bundle.framework',
+                                    chdir='framework')
+  mtime = os.path.getmtime(dep_bundle)
+  atime = os.path.getatime(dep_bundle)
+  for i in range(3):
+    os.utime(dep_bundle, (atime + i * 1000, mtime + i * 1000))
+    test.build('framework.gyp', 'copy_target', chdir='framework')
+
+
+  # Check that actions ran.
+  test.built_file_must_exist('action_file', chdir='framework')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-copy-dylib.py b/gyp/test/mac/gyptest-copy-dylib.py
new file mode 100644 (file)
index 0000000..253623d
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that dylibs can be copied into app bundles.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('test.gyp', chdir='copy-dylib')
+
+  test.build('test.gyp', 'test_app', chdir='copy-dylib')
+
+  test.built_file_must_exist(
+      'Test App.app/Contents/Resources/libmy_dylib.dylib', chdir='copy-dylib')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-debuginfo.py b/gyp/test/mac/gyptest-debuginfo.py
new file mode 100755 (executable)
index 0000000..a0e9438
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests things related to debug information generation.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('test.gyp', chdir='debuginfo')
+
+  test.build('test.gyp', test.ALL, chdir='debuginfo')
+
+  test.built_file_must_exist('libnonbundle_shared_library.dylib.dSYM',
+                             chdir='debuginfo')
+  test.built_file_must_exist('nonbundle_loadable_module.so.dSYM',
+                             chdir='debuginfo')
+  test.built_file_must_exist('nonbundle_executable.dSYM',
+                             chdir='debuginfo')
+
+  test.built_file_must_exist('bundle_shared_library.framework.dSYM',
+                             chdir='debuginfo')
+  test.built_file_must_exist('bundle_loadable_module.bundle.dSYM',
+                             chdir='debuginfo')
+  test.built_file_must_exist('My App.app.dSYM',
+                             chdir='debuginfo')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-depend-on-bundle.py b/gyp/test/mac/gyptest-depend-on-bundle.py
new file mode 100644 (file)
index 0000000..5cccb03
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a dependency on a bundle causes the whole bundle to be built.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('test.gyp', chdir='depend-on-bundle')
+
+  test.build('test.gyp', 'dependent_on_bundle', chdir='depend-on-bundle')
+
+  # Binary itself.
+  test.built_file_must_exist('dependent_on_bundle', chdir='depend-on-bundle')
+
+  # Bundle dependency.
+  test.built_file_must_exist(
+      'my_bundle.framework/Versions/A/my_bundle',
+      chdir='depend-on-bundle')
+  test.built_file_must_exist(  # package_framework
+      'my_bundle.framework/my_bundle',
+      chdir='depend-on-bundle')
+  test.built_file_must_exist(  # plist
+      'my_bundle.framework/Versions/A/Resources/Info.plist',
+      chdir='depend-on-bundle')
+  test.built_file_must_exist(
+      'my_bundle.framework/Versions/A/Resources/English.lproj/'  # Resources
+      'InfoPlist.strings',
+      chdir='depend-on-bundle')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-deployment-target.py b/gyp/test/mac/gyptest-deployment-target.py
new file mode 100644 (file)
index 0000000..afa6c77
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that MACOSX_DEPLOYMENT_TARGET works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode'])
+
+  test.run_gyp('deployment-target.gyp', chdir='deployment-target')
+
+  test.build('deployment-target.gyp', test.ALL, chdir='deployment-target')
+
+  test.pass_test()
+
diff --git a/gyp/test/mac/gyptest-framework-dirs.py b/gyp/test/mac/gyptest-framework-dirs.py
new file mode 100644 (file)
index 0000000..a1ae54c
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that it is possible to build an object that depends on a
+PrivateFramework.
+"""
+
+import os
+import sys
+import TestGyp
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'framework-dirs'
+  test.run_gyp('framework-dirs.gyp', chdir=CHDIR)
+  test.build('framework-dirs.gyp', 'calculate', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-framework-headers.py b/gyp/test/mac/gyptest-framework-headers.py
new file mode 100644 (file)
index 0000000..aa13a74
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that mac_framework_headers works properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  # TODO(thakis): Make this work with ninja, make. http://crbug.com/129013
+  test = TestGyp.TestGyp(formats=['xcode'])
+
+  CHDIR = 'framework-headers'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+
+  # Test that headers are installed for frameworks
+  test.build('test.gyp', 'test_framework_headers_framework', chdir=CHDIR)
+
+  test.built_file_must_exist(
+    'TestFramework.framework/Versions/A/TestFramework', chdir=CHDIR)
+
+  test.built_file_must_exist(
+    'TestFramework.framework/Versions/A/Headers/myframework.h', chdir=CHDIR)
+
+  # Test that headers are installed for static libraries.
+  test.build('test.gyp', 'test_framework_headers_static', chdir=CHDIR)
+
+  test.built_file_must_exist('libTestLibrary.a', chdir=CHDIR)
+
+  test.built_file_must_exist('include/myframework.h', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-framework.py b/gyp/test/mac/gyptest-framework.py
new file mode 100755 (executable)
index 0000000..401bd98
--- /dev/null
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that app bundles are built correctly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+
+def ls(path):
+  '''Returns a list of all files in a directory, relative to the directory.'''
+  result = []
+  for dirpath, _, files in os.walk(path):
+    for f in files:
+      result.append(os.path.join(dirpath, f)[len(path) + 1:])
+  return result
+
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('framework.gyp', chdir='framework')
+
+  test.build('framework.gyp', 'test_framework', chdir='framework')
+
+  # Binary
+  test.built_file_must_exist(
+      'Test Framework.framework/Versions/A/Test Framework',
+      chdir='framework')
+
+  # Info.plist
+  info_plist = test.built_file_path(
+      'Test Framework.framework/Versions/A/Resources/Info.plist',
+      chdir='framework')
+  test.must_exist(info_plist)
+  test.must_contain(info_plist, 'com.yourcompany.Test_Framework')
+
+  # Resources
+  test.built_file_must_exist(
+      'Test Framework.framework/Versions/A/Resources/English.lproj/'
+      'InfoPlist.strings',
+      chdir='framework')
+
+  # Symlinks created by packaging process
+  test.built_file_must_exist('Test Framework.framework/Versions/Current',
+                             chdir='framework')
+  test.built_file_must_exist('Test Framework.framework/Resources',
+                             chdir='framework')
+  test.built_file_must_exist('Test Framework.framework/Test Framework',
+                             chdir='framework')
+  # PkgInfo.
+  test.built_file_must_not_exist(
+      'Test Framework.framework/Versions/A/Resources/PkgInfo',
+      chdir='framework')
+
+  # Check that no other files get added to the bundle.
+  if set(ls(test.built_file_path('Test Framework.framework',
+                                 chdir='framework'))) != \
+     set(['Versions/A/Test Framework',
+          'Versions/A/Resources/Info.plist',
+          'Versions/A/Resources/English.lproj/InfoPlist.strings',
+          'Test Framework',
+          'Versions/A/Libraries/empty.c',  # Written by a gyp action.
+          ]):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-global-settings.py b/gyp/test/mac/gyptest-global-settings.py
new file mode 100644 (file)
index 0000000..648d32c
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that the global xcode_settings processing doesn't throw.
+Regression test for http://crbug.com/109163
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+  test.run_gyp('src/dir2/dir2.gyp', chdir='global-settings', depth='src')
+  # run_gyp shouldn't throw.
+
+  # Check that BUILT_PRODUCTS_DIR was set correctly, too.
+  test.build('dir2/dir2.gyp', 'dir2_target', chdir='global-settings/src',
+             SYMROOT='../build')
+  test.built_file_must_exist('file.txt', chdir='global-settings/src')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-infoplist-process.py b/gyp/test/mac/gyptest-infoplist-process.py
new file mode 100755 (executable)
index 0000000..20874a3
--- /dev/null
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies the Info.plist preprocessor functionality.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'infoplist-process'
+  INFO_PLIST_PATH = 'Test.app/Contents/Info.plist'
+
+  # First process both keys.
+  test.set_configuration('One')
+  test.run_gyp('test1.gyp', chdir=CHDIR)
+  test.build('test1.gyp', test.ALL, chdir=CHDIR)
+  info_plist = test.built_file_path(INFO_PLIST_PATH, chdir=CHDIR)
+  test.must_exist(info_plist)
+  test.must_contain(info_plist, 'Foo')
+  test.must_contain(info_plist, 'Bar')
+
+  # Then process a single key.
+  test.set_configuration('Two')
+  test.run_gyp('test2.gyp', chdir=CHDIR)
+  test.build('test2.gyp', chdir=CHDIR)
+  info_plist = test.built_file_path(INFO_PLIST_PATH, chdir=CHDIR)
+  test.must_exist(info_plist)
+  test.must_contain(info_plist, 'com.google.Test')  # Normal expansion works.
+  test.must_contain(info_plist, 'Foo (Bar)')
+  test.must_contain(info_plist, 'PROCESSED_KEY2')
+
+  # Then turn off the processor.
+  test.set_configuration('Three')
+  test.run_gyp('test3.gyp', chdir=CHDIR)
+  test.build('test3.gyp', chdir=CHDIR)
+  info_plist = test.built_file_path('Test App.app/Contents/Info.plist',
+                                    chdir=CHDIR)
+  test.must_exist(info_plist)
+  test.must_contain(info_plist, 'com.google.Test')  # Normal expansion works.
+  test.must_contain(info_plist, 'PROCESSED_KEY1')
+  test.must_contain(info_plist, 'PROCESSED_KEY2')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-installname.py b/gyp/test/mac/gyptest-installname.py
new file mode 100644 (file)
index 0000000..c300820
--- /dev/null
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that LD_DYLIB_INSTALL_NAME and DYLIB_INSTALL_NAME_BASE are handled
+correctly.
+"""
+
+import TestGyp
+
+import re
+import subprocess
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'installname'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+  def GetInstallname(p):
+    p = test.built_file_path(p, chdir=CHDIR)
+    r = re.compile(r'cmd LC_ID_DYLIB.*?name (.*?) \(offset \d+\)', re.DOTALL)
+    proc = subprocess.Popen(['otool', '-l', p], stdout=subprocess.PIPE)
+    o = proc.communicate()[0]
+    assert not proc.returncode
+    m = r.search(o)
+    assert m
+    return m.group(1)
+
+  if (GetInstallname('libdefault_installname.dylib') !=
+      '/usr/local/lib/libdefault_installname.dylib'):
+    test.fail_test()
+
+  if (GetInstallname('My Framework.framework/My Framework') !=
+      '/Library/Frameworks/My Framework.framework/'
+      'Versions/A/My Framework'):
+    test.fail_test()
+
+  if (GetInstallname('libexplicit_installname.dylib') !=
+      'Trapped in a dynamiclib factory'):
+    test.fail_test()
+
+  if (GetInstallname('libexplicit_installname_base.dylib') !=
+      '@executable_path/../../../libexplicit_installname_base.dylib'):
+    test.fail_test()
+
+  if (GetInstallname('My Other Framework.framework/My Other Framework') !=
+      '@executable_path/../../../My Other Framework.framework/'
+      'Versions/A/My Other Framework'):
+    test.fail_test()
+
+  if (GetInstallname('libexplicit_installname_with_base.dylib') !=
+      '/usr/local/lib/libexplicit_installname_with_base.dylib'):
+    test.fail_test()
+
+  if (GetInstallname('libexplicit_installname_with_explicit_base.dylib') !=
+      '@executable_path/../libexplicit_installname_with_explicit_base.dylib'):
+    test.fail_test()
+
+  if (GetInstallname('libboth_base_and_installname.dylib') !=
+      'Still trapped in a dynamiclib factory'):
+    test.fail_test()
+
+  if (GetInstallname('install_name_with_info_plist.framework/'
+                     'install_name_with_info_plist') !=
+      '/Library/Frameworks/install_name_with_info_plist.framework/'
+      'Versions/A/install_name_with_info_plist'):
+    test.fail_test()
+
+  if ('DYLIB_INSTALL_NAME_BASE:standardizepath: command not found' in
+          test.stdout()):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-ldflags-passed-to-libtool.py b/gyp/test/mac/gyptest-ldflags-passed-to-libtool.py
new file mode 100644 (file)
index 0000000..fb0fd95
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that OTHER_LDFLAGS is passed to libtool.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'],
+                         match = lambda a, b: True)
+
+  build_error_code = {
+    'xcode': [1, 65],  # 1 for xcode 3, 65 for xcode 4 (see `man sysexits`)
+    'make': 2,
+    'ninja': 1,
+  }[test.format]
+
+  CHDIR = 'ldflags-libtool'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+
+  test.build('test.gyp', 'ldflags_passed_to_libtool', chdir=CHDIR,
+             status=build_error_code)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-ldflags.py b/gyp/test/mac/gyptest-ldflags.py
new file mode 100644 (file)
index 0000000..4da4049
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that filenames passed to various linker flags are converted into
+build-directory relative paths correctly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'ldflags'
+  test.run_gyp('subdirectory/test.gyp', chdir=CHDIR)
+
+  test.build('subdirectory/test.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
+
+
+# These flags from `man ld` couldl show up in OTHER_LDFLAGS and need path
+# translation.
+#
+# Done:
+#      -exported_symbols_list filename
+#      -unexported_symbols_list file
+#      -reexported_symbols_list file
+#      -sectcreate segname sectname file
+#
+# Will be done on demand:
+#      -weak_library path_to_library
+#      -reexport_library path_to_library
+#      -lazy_library path_to_library
+#      -upward_library path_to_library
+#      -syslibroot rootdir
+#      -framework name[,suffix]
+#      -weak_framework name[,suffix]
+#      -reexport_framework name[,suffix]
+#      -lazy_framework name[,suffix]
+#      -upward_framework name[,suffix]
+#      -force_load path_to_archive
+#      -filelist file[,dirname]
+#      -dtrace file
+#      -order_file file                     # should use ORDER_FILE
+#      -exported_symbols_order file
+#      -bundle_loader executable            # should use BUNDLE_LOADER
+#      -alias_list filename
+#      -seg_addr_table filename
+#      -dylib_file install_name:file_name
+#      -interposable_list filename
+#      -object_path_lto filename
+#
+#
+# obsolete:
+#      -sectorder segname sectname orderfile
+#      -seg_addr_table_filename path
+#
+#
+# ??:
+#      -map map_file_path
+#      -sub_library library_name
+#      -sub_umbrella framework_name
diff --git a/gyp/test/mac/gyptest-libraries.py b/gyp/test/mac/gyptest-libraries.py
new file mode 100755 (executable)
index 0000000..46814d6
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies libraries (in link_settings) are properly found.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('subdir/test.gyp', chdir='libraries')
+
+  test.build('subdir/test.gyp', test.ALL, chdir='libraries')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-loadable-module-bundle-product-extension.py b/gyp/test/mac/gyptest-loadable-module-bundle-product-extension.py
new file mode 100644 (file)
index 0000000..90c2083
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests that loadable_modules don't collide when using the same name with
+different file extensions.
+"""
+
+import TestGyp
+
+import os
+import struct
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'loadable-module-bundle-product-extension'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+  test.must_exist(test.built_file_path('Collide.foo', chdir=CHDIR))
+  test.must_exist(test.built_file_path('Collide.bar', chdir=CHDIR))
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-loadable-module.py b/gyp/test/mac/gyptest-loadable-module.py
new file mode 100755 (executable)
index 0000000..3564aac
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests that a loadable_module target is built correctly.
+"""
+
+import TestGyp
+
+import os
+import struct
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'loadable-module'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+  # Binary.
+  binary = test.built_file_path(
+      'test_loadable_module.plugin/Contents/MacOS/test_loadable_module',
+      chdir=CHDIR)
+  test.must_exist(binary)
+  MH_BUNDLE = 8
+  if struct.unpack('4I', open(binary, 'rb').read(16))[3] != MH_BUNDLE:
+    test.fail_test()
+
+  # Info.plist.
+  info_plist = test.built_file_path(
+      'test_loadable_module.plugin/Contents/Info.plist', chdir=CHDIR)
+  test.must_exist(info_plist)
+  test.must_contain(info_plist, """
+       <key>CFBundleExecutable</key>
+       <string>test_loadable_module</string>
+""")
+
+  # PkgInfo.
+  test.built_file_must_not_exist(
+      'test_loadable_module.plugin/Contents/PkgInfo', chdir=CHDIR)
+  test.built_file_must_not_exist(
+      'test_loadable_module.plugin/Contents/Resources', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-missing-cfbundlesignature.py b/gyp/test/mac/gyptest-missing-cfbundlesignature.py
new file mode 100644 (file)
index 0000000..ef7a8d1
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that an Info.plist with CFBundleSignature works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('test.gyp', chdir='missing-cfbundlesignature')
+  test.build('test.gyp', test.ALL, chdir='missing-cfbundlesignature')
+
+  test.built_file_must_match('mytarget.app/Contents/PkgInfo', 'APPL????',
+                             chdir='missing-cfbundlesignature')
+
+  test.built_file_must_match('myothertarget.app/Contents/PkgInfo', 'APPL????',
+                             chdir='missing-cfbundlesignature')
+
+  test.built_file_must_match('thirdtarget.app/Contents/PkgInfo', 'APPL????',
+                             chdir='missing-cfbundlesignature')
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-non-strs-flattened-to-env.py b/gyp/test/mac/gyptest-non-strs-flattened-to-env.py
new file mode 100644 (file)
index 0000000..504dcd5
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that list xcode_settings are flattened before being exported to the
+environment.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'non-strs-flattened-to-env'
+  INFO_PLIST_PATH = 'Test.app/Contents/Info.plist'
+
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+  info_plist = test.built_file_path(INFO_PLIST_PATH, chdir=CHDIR)
+  test.must_exist(info_plist)
+  test.must_contain(info_plist, '''\
+\t<key>My Variable</key>
+\t<string>some expansion</string>''')
+  test.must_contain(info_plist, '''\
+\t<key>CFlags</key>
+\t<string>-fstack-protector-all -fno-strict-aliasing -DS="A Space"</string>''')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-objc-arc.py b/gyp/test/mac/gyptest-objc-arc.py
new file mode 100755 (executable)
index 0000000..b3192a1
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that ARC objc settings are handled correctly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  # set |match| to ignore build stderr output.
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'],
+                         match = lambda a, b: True)
+
+  CHDIR = 'objc-arc'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+
+  test.build('test.gyp', 'arc_enabled', chdir=CHDIR)
+  test.build('test.gyp', 'arc_disabled', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-objc-gc.py b/gyp/test/mac/gyptest-objc-gc.py
new file mode 100644 (file)
index 0000000..0cec458
--- /dev/null
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that GC objc settings are handled correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import sys
+
+if sys.platform == 'darwin':
+  # set |match| to ignore build stderr output.
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'],
+                         match = lambda a, b: True)
+
+  # Xcode 5.1 removed support for garbage-collection:
+  #   error: garbage collection is no longer supported
+  if TestMac.Xcode.Version() < '0510':
+
+    CHDIR = 'objc-gc'
+    test.run_gyp('test.gyp', chdir=CHDIR)
+
+    build_error_code = {
+      'xcode': [1, 65],  # 1 for xcode 3, 65 for xcode 4 (see `man sysexits`)
+      'make': 2,
+      'ninja': 1,
+    }[test.format]
+
+    test.build('test.gyp', 'gc_exe_fails', chdir=CHDIR, status=build_error_code)
+    test.build(
+        'test.gyp', 'gc_off_exe_req_lib', chdir=CHDIR, status=build_error_code)
+
+    test.build('test.gyp', 'gc_req_exe', chdir=CHDIR)
+    test.run_built_executable('gc_req_exe', chdir=CHDIR, stdout="gc on: 1\n")
+
+    test.build('test.gyp', 'gc_exe_req_lib', chdir=CHDIR)
+    test.run_built_executable(
+        'gc_exe_req_lib', chdir=CHDIR, stdout="gc on: 1\n")
+
+    test.build('test.gyp', 'gc_exe', chdir=CHDIR)
+    test.run_built_executable('gc_exe', chdir=CHDIR, stdout="gc on: 1\n")
+
+    test.build('test.gyp', 'gc_off_exe', chdir=CHDIR)
+    test.run_built_executable('gc_off_exe', chdir=CHDIR, stdout="gc on: 0\n")
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-postbuild-copy-bundle.py b/gyp/test/mac/gyptest-postbuild-copy-bundle.py
new file mode 100644 (file)
index 0000000..dc2c85f
--- /dev/null
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a postbuild copying a dependend framework into an app bundle is
+rerun if the resources in the framework change.
+"""
+
+import TestGyp
+
+import os.path
+import sys
+
+if sys.platform == 'darwin':
+  # TODO(thakis): Make this pass with the make generator, http://crbug.com/95529
+  test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+  CHDIR = 'postbuild-copy-bundle'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+
+  app_bundle_dir = test.built_file_path('Test app.app', chdir=CHDIR)
+  bundled_framework_dir = os.path.join(
+      app_bundle_dir, 'Contents', 'My Framework.framework', 'Resources')
+  final_plist_path = os.path.join(bundled_framework_dir, 'Info.plist')
+  final_resource_path = os.path.join(bundled_framework_dir, 'resource_file.sb')
+  final_copies_path = os.path.join(
+      app_bundle_dir, 'Contents', 'My Framework.framework', 'Versions', 'A',
+      'Libraries', 'copied.txt')
+
+  # Check that the dependency was built and copied into the app bundle:
+  test.build('test.gyp', 'test_app', chdir=CHDIR)
+  test.must_exist(final_resource_path)
+  test.must_match(final_resource_path,
+                  'This is included in the framework bundle.\n')
+
+  test.must_exist(final_plist_path)
+  test.must_contain(final_plist_path, '''\
+\t<key>RandomKey</key>
+\t<string>RandomValue</string>''')
+
+  # Touch the dependency's bundle resource, and check that the modification
+  # makes it all the way into the app bundle:
+  test.sleep()
+  test.write('postbuild-copy-bundle/resource_file.sb', 'New text\n')
+  test.build('test.gyp', 'test_app', chdir=CHDIR)
+
+  test.must_exist(final_resource_path)
+  test.must_match(final_resource_path, 'New text\n')
+
+  # Check the same for the plist file.
+  test.sleep()
+  contents = test.read('postbuild-copy-bundle/Framework-Info.plist')
+  contents = contents.replace('RandomValue', 'NewRandomValue')
+  test.write('postbuild-copy-bundle/Framework-Info.plist', contents)
+  test.build('test.gyp', 'test_app', chdir=CHDIR)
+
+  test.must_exist(final_plist_path)
+  test.must_contain(final_plist_path, '''\
+\t<key>RandomKey</key>
+\t<string>NewRandomValue</string>''')
+
+  # Check the same for the copies section, test for http://crbug.com/157077
+  test.sleep()
+  contents = test.read('postbuild-copy-bundle/copied.txt')
+  contents = contents.replace('old', 'new')
+  test.write('postbuild-copy-bundle/copied.txt', contents)
+  test.build('test.gyp', 'test_app', chdir=CHDIR)
+
+  test.must_exist(final_copies_path)
+  test.must_contain(final_copies_path, 'new copied file')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-postbuild-defaults.py b/gyp/test/mac/gyptest-postbuild-defaults.py
new file mode 100644 (file)
index 0000000..0560904
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a postbuild invoking |defaults| works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'postbuild-defaults'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+  result_file = test.built_file_path('result', chdir=CHDIR)
+  test.must_exist(result_file)
+  test.must_contain(result_file, '''\
+Test
+${PRODUCT_NAME}
+''')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-postbuild-fail.py b/gyp/test/mac/gyptest-postbuild-fail.py
new file mode 100755 (executable)
index 0000000..f3dee4a
--- /dev/null
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a failing postbuild step lets the build fail.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  # set |match| to ignore build stderr output.
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'],
+                         match = lambda a, b: True)
+
+  test.run_gyp('test.gyp', chdir='postbuild-fail')
+
+  build_error_code = {
+    'xcode': [1, 65],  # 1 for xcode 3, 65 for xcode 4 (see `man sysexits`)
+    'make': 2,
+    'ninja': 1,
+  }[test.format]
+
+
+  # If a postbuild fails, all postbuilds should be re-run on the next build.
+  # In Xcode 3, even if the first postbuild fails the other postbuilds were
+  # still executed. In Xcode 4, postbuilds are stopped after the first
+  # failing postbuild. This test checks for the Xcode 4 behavior.
+
+  # Ignore this test on Xcode 3.
+  import subprocess
+  job = subprocess.Popen(['xcodebuild', '-version'],
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.STDOUT)
+  out, err = job.communicate()
+  if job.returncode != 0:
+    print out
+    raise Exception('Error %d running xcodebuild' % job.returncode)
+  if out.startswith('Xcode 3.'):
+    test.pass_test()
+
+  # Non-bundles
+  test.build('test.gyp', 'nonbundle', chdir='postbuild-fail',
+             status=build_error_code)
+  test.built_file_must_not_exist('static_touch',
+                                 chdir='postbuild-fail')
+  # Check for non-up-to-date-ness by checking if building again produces an
+  # error.
+  test.build('test.gyp', 'nonbundle', chdir='postbuild-fail',
+             status=build_error_code)
+
+
+  # Bundles
+  test.build('test.gyp', 'bundle', chdir='postbuild-fail',
+             status=build_error_code)
+  test.built_file_must_not_exist('dynamic_touch',
+                                 chdir='postbuild-fail')
+  # Check for non-up-to-date-ness by checking if building again produces an
+  # error.
+  test.build('test.gyp', 'bundle', chdir='postbuild-fail',
+             status=build_error_code)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-postbuild-multiple-configurations.py b/gyp/test/mac/gyptest-postbuild-multiple-configurations.py
new file mode 100644 (file)
index 0000000..84694f3
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a postbuild work in projects with multiple configurations.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'postbuild-multiple-configurations'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+
+  for configuration in ['Debug', 'Release']:
+    test.set_configuration(configuration)
+    test.build('test.gyp', test.ALL, chdir=CHDIR)
+    test.built_file_must_exist('postbuild-file', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-postbuild-static-library.py b/gyp/test/mac/gyptest-postbuild-static-library.py
new file mode 100644 (file)
index 0000000..8f9a6eb
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a postbuilds on static libraries work, and that sourceless
+libraries don't cause failures at gyp time.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['make', 'xcode'])
+
+  CHDIR = 'postbuild-static-library'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', 'my_lib', chdir=CHDIR)
+  # Building my_sourceless_lib doesn't work with make. gyp should probably
+  # forbid sourceless static libraries, since they're pretty pointless.
+  # But they shouldn't cause gyp time exceptions.
+
+  test.built_file_must_exist('postbuild-file', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-postbuild.py b/gyp/test/mac/gyptest-postbuild.py
new file mode 100755 (executable)
index 0000000..684e7b8
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that postbuild steps work.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('test.gyp', chdir='postbuilds')
+
+  test.build('test.gyp', test.ALL, chdir='postbuilds')
+
+  # See comment in test/subdirectory/gyptest-subdir-default.py
+  if test.format == 'xcode':
+    chdir = 'postbuilds/subdirectory'
+  else:
+    chdir = 'postbuilds'
+
+  # Created by the postbuild scripts
+  test.built_file_must_exist('el.a_touch',
+                             type=test.STATIC_LIB,
+                             chdir='postbuilds')
+  test.built_file_must_exist('el.a_gyp_touch',
+                             type=test.STATIC_LIB,
+                             chdir='postbuilds')
+  test.built_file_must_exist('nest_el.a_touch',
+                             type=test.STATIC_LIB,
+                             chdir=chdir)
+  test.built_file_must_exist(
+      'dyna.framework/Versions/A/dyna_touch',
+      chdir='postbuilds')
+  test.built_file_must_exist(
+      'dyna.framework/Versions/A/dyna_gyp_touch',
+      chdir='postbuilds')
+  test.built_file_must_exist(
+      'nest_dyna.framework/Versions/A/nest_dyna_touch',
+      chdir=chdir)
+  test.built_file_must_exist('dyna_standalone.dylib_gyp_touch',
+                             type=test.SHARED_LIB,
+                             chdir='postbuilds')
+  test.built_file_must_exist('copied_file.txt', chdir='postbuilds')
+  test.built_file_must_exist('copied_file_2.txt', chdir=chdir)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-prefixheader.py b/gyp/test/mac/gyptest-prefixheader.py
new file mode 100755 (executable)
index 0000000..768551f
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that GCC_PREFIX_HEADER works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+  test.run_gyp('test.gyp', chdir='prefixheader')
+  test.build('test.gyp', test.ALL, chdir='prefixheader')
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-rebuild.py b/gyp/test/mac/gyptest-rebuild.py
new file mode 100755 (executable)
index 0000000..0f26e96
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that app bundles are rebuilt correctly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'rebuild'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+
+  test.build('test.gyp', 'test_app', chdir=CHDIR)
+
+  # Touch a source file, rebuild, and check that the app target is up-to-date.
+  test.touch('rebuild/main.c')
+  test.build('test.gyp', 'test_app', chdir=CHDIR)
+
+  test.up_to_date('test.gyp', 'test_app', chdir=CHDIR)
+
+  # Xcode runs postbuilds on every build, so targets with postbuilds are
+  # never marked as up_to_date.
+  if test.format != 'xcode':
+    # Same for a framework bundle.
+    test.build('test.gyp', 'test_framework_postbuilds', chdir=CHDIR)
+    test.up_to_date('test.gyp', 'test_framework_postbuilds', chdir=CHDIR)
+
+    # Test that an app bundle with a postbuild that touches the app binary needs
+    # to be built only once.
+    test.build('test.gyp', 'test_app_postbuilds', chdir=CHDIR)
+    test.up_to_date('test.gyp', 'test_app_postbuilds', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-rpath.py b/gyp/test/mac/gyptest-rpath.py
new file mode 100644 (file)
index 0000000..2440d54
--- /dev/null
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that LD_DYLIB_INSTALL_NAME and DYLIB_INSTALL_NAME_BASE are handled
+correctly.
+"""
+
+import TestGyp
+
+import re
+import subprocess
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'rpath'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+  def GetRpaths(p):
+    p = test.built_file_path(p, chdir=CHDIR)
+    r = re.compile(r'cmd LC_RPATH.*?path (.*?) \(offset \d+\)', re.DOTALL)
+    proc = subprocess.Popen(['otool', '-l', p], stdout=subprocess.PIPE)
+    o = proc.communicate()[0]
+    assert not proc.returncode
+    return r.findall(o)
+
+  if (GetRpaths('libdefault_rpath.dylib') != []):
+    test.fail_test()
+
+  if (GetRpaths('libexplicit_rpath.dylib') != ['@executable_path/.']):
+    test.fail_test()
+
+  if (GetRpaths('libexplicit_rpaths_escaped.dylib') !=
+      ['First rpath', 'Second rpath']):
+    test.fail_test()
+
+  if (GetRpaths('My Framework.framework/My Framework') != ['@loader_path/.']):
+    test.fail_test()
+
+  if (GetRpaths('executable') != ['@executable_path/.']):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-sdkroot.py b/gyp/test/mac/gyptest-sdkroot.py
new file mode 100644 (file)
index 0000000..711726e
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that setting SDKROOT works.
+"""
+
+import TestGyp
+
+import os
+import subprocess
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  def GetSDKPath(sdk):
+    """Return SDKROOT if the SDK version |sdk| is installed or empty string."""
+    DEVNULL = open(os.devnull, 'wb')
+    try:
+      proc = subprocess.Popen(
+          ['xcodebuild', '-version', '-sdk', 'macosx' + sdk, 'Path'],
+          stdout=subprocess.PIPE, stderr=DEVNULL)
+      return proc.communicate()[0].rstrip('\n')
+    finally:
+      DEVNULL.close()
+
+  def SelectSDK():
+    """Select the oldest SDK installed (greater than 10.6)."""
+    for sdk in ['10.6', '10.7', '10.8', '10.9']:
+      path = GetSDKPath(sdk)
+      if path:
+        return True, sdk, path
+    return False, '', ''
+
+  # Make sure this works on the bots, which only have the 10.6 sdk, and on
+  # dev machines which usually don't have the 10.6 sdk.
+  sdk_found, sdk, sdk_path = SelectSDK()
+  if not sdk_found:
+    test.fail_test()
+
+  test.write('sdkroot/test.gyp', test.read('sdkroot/test.gyp') % sdk)
+
+  test.run_gyp('test.gyp', '-D', 'sdk_path=%s' % sdk_path,
+               chdir='sdkroot')
+  test.build('test.gyp', test.ALL, chdir='sdkroot')
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-sourceless-module.py b/gyp/test/mac/gyptest-sourceless-module.py
new file mode 100644 (file)
index 0000000..b56b75e
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that bundles that have no 'sources' (pure resource containers) work.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('test.gyp', chdir='sourceless-module')
+
+  # Just needs to build without errors.
+  test.build('test.gyp', 'empty_bundle', chdir='sourceless-module')
+  test.built_file_must_not_exist(
+      'empty_bundle.bundle', chdir='sourceless-module')
+
+  # Needs to build, and contain a resource.
+  test.build('test.gyp', 'resource_bundle', chdir='sourceless-module')
+
+  test.built_file_must_exist(
+      'resource_bundle.bundle/Contents/Resources/foo.manifest',
+      chdir='sourceless-module')
+  test.built_file_must_not_exist(
+      'resource_bundle.bundle/Contents/MacOS/resource_bundle',
+      chdir='sourceless-module')
+
+  # Build an app containing an actionless bundle.
+  test.build(
+      'test.gyp',
+      'bundle_dependent_on_resource_bundle_no_actions',
+      chdir='sourceless-module')
+
+  test.built_file_must_exist(
+      'bundle_dependent_on_resource_bundle_no_actions.app/Contents/Resources/'
+          'mac_resource_bundle_no_actions.bundle/Contents/Resources/empty.txt',
+      chdir='sourceless-module')
+
+  # Needs to build and cause the bundle to be built.
+  test.build(
+      'test.gyp', 'dependent_on_resource_bundle', chdir='sourceless-module')
+
+  test.built_file_must_exist(
+      'resource_bundle.bundle/Contents/Resources/foo.manifest',
+      chdir='sourceless-module')
+  test.built_file_must_not_exist(
+      'resource_bundle.bundle/Contents/MacOS/resource_bundle',
+      chdir='sourceless-module')
+
+  # TODO(thakis): shared_libraries that have no sources but depend on static
+  # libraries currently only work with the ninja generator.  This is used by
+  # chrome/mac's components build.
+  if test.format == 'ninja':
+    # Check that an executable depending on a resource framework links fine too.
+    test.build(
+       'test.gyp', 'dependent_on_resource_framework', chdir='sourceless-module')
+
+    test.built_file_must_exist(
+        'resource_framework.framework/Resources/foo.manifest',
+        chdir='sourceless-module')
+    test.built_file_must_exist(
+        'resource_framework.framework/resource_framework',
+        chdir='sourceless-module')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-strip-default.py b/gyp/test/mac/gyptest-strip-default.py
new file mode 100644 (file)
index 0000000..f73fa11
--- /dev/null
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that the default STRIP_STYLEs match between different generators.
+"""
+
+import TestGyp
+
+import re
+import subprocess
+import sys
+import time
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR='strip'
+  test.run_gyp('test-defaults.gyp', chdir=CHDIR)
+
+  test.build('test-defaults.gyp', test.ALL, chdir=CHDIR)
+
+  # Lightweight check if stripping was done.
+  def OutPath(s):
+    return test.built_file_path(s, chdir=CHDIR)
+
+  def CheckNsyms(p, o_expected):
+    proc = subprocess.Popen(['nm', '-aU', p], stdout=subprocess.PIPE)
+    o = proc.communicate()[0]
+
+    # Filter out mysterious "00 0000   OPT radr://5614542" symbol which
+    # is apparently only printed on the bots (older toolchain?).
+    # Yes, "radr", not "rdar".
+    o = ''.join(filter(lambda s: 'radr://5614542' not in s, o.splitlines(True)))
+
+    o = o.replace('A', 'T')
+    o = re.sub(r'^[a-fA-F0-9]+', 'XXXXXXXX', o, flags=re.MULTILINE)
+    assert not proc.returncode
+    if o != o_expected:
+      print 'Stripping: Expected symbols """\n%s""", got """\n%s"""' % (
+          o_expected, o)
+      test.fail_test()
+
+  CheckNsyms(OutPath('libsingle_dylib.dylib'),
+"""\
+XXXXXXXX S _ci
+XXXXXXXX S _i
+XXXXXXXX T _the_function
+XXXXXXXX t _the_hidden_function
+XXXXXXXX T _the_used_function
+XXXXXXXX T _the_visible_function
+""")
+  CheckNsyms(OutPath('single_so.so'),
+"""\
+XXXXXXXX S _ci
+XXXXXXXX S _i
+XXXXXXXX T _the_function
+XXXXXXXX t _the_hidden_function
+XXXXXXXX T _the_used_function
+XXXXXXXX T _the_visible_function
+""")
+  CheckNsyms(OutPath('single_exe'),
+"""\
+XXXXXXXX T __mh_execute_header
+""")
+
+  CheckNsyms(test.built_file_path(
+      'bundle_dylib.framework/Versions/A/bundle_dylib', chdir=CHDIR),
+"""\
+XXXXXXXX S _ci
+XXXXXXXX S _i
+XXXXXXXX T _the_function
+XXXXXXXX t _the_hidden_function
+XXXXXXXX T _the_used_function
+XXXXXXXX T _the_visible_function
+""")
+  CheckNsyms(test.built_file_path(
+      'bundle_so.bundle/Contents/MacOS/bundle_so', chdir=CHDIR),
+"""\
+XXXXXXXX S _ci
+XXXXXXXX S _i
+XXXXXXXX T _the_function
+XXXXXXXX T _the_used_function
+XXXXXXXX T _the_visible_function
+""")
+  CheckNsyms(test.built_file_path(
+      'bundle_exe.app/Contents/MacOS/bundle_exe', chdir=CHDIR),
+"""\
+XXXXXXXX T __mh_execute_header
+""")
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-strip.py b/gyp/test/mac/gyptest-strip.py
new file mode 100755 (executable)
index 0000000..e2c06c1
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that stripping works.
+"""
+
+import TestGyp
+import TestMac
+
+import re
+import subprocess
+import sys
+import time
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('test.gyp', chdir='strip')
+
+  test.build('test.gyp', test.ALL, chdir='strip')
+
+  # Lightweight check if stripping was done.
+  def OutPath(s):
+    return test.built_file_path(s, type=test.SHARED_LIB, chdir='strip')
+
+  def CheckNsyms(p, n_expected):
+    r = re.compile(r'nsyms\s+(\d+)')
+    o = subprocess.check_output(['otool', '-l', p])
+    m = r.search(o)
+    n = int(m.group(1))
+    if n != n_expected:
+      print 'Stripping: Expected %d symbols, got %d' % (n_expected, n)
+      test.fail_test()
+
+  # Starting with Xcode 5.0, clang adds an additional symbols to the compiled
+  # file when using a relative path to the input file. So when using ninja
+  # with Xcode 5.0 or higher, take this additional symbol into consideration
+  # for unstripped builds (it is stripped by all strip commands).
+  expected_extra_symbol_count = 0
+  if test.format == 'ninja' and TestMac.Xcode.Version() >= '0500':
+    expected_extra_symbol_count = 1
+
+  # The actual numbers here are not interesting, they just need to be the same
+  # in both the xcode and the make build.
+  CheckNsyms(OutPath('no_postprocess'), 29 + expected_extra_symbol_count)
+  CheckNsyms(OutPath('no_strip'), 29 + expected_extra_symbol_count)
+  CheckNsyms(OutPath('strip_all'), 0)
+  CheckNsyms(OutPath('strip_nonglobal'), 6)
+  CheckNsyms(OutPath('strip_debugging'), 7)
+  CheckNsyms(OutPath('strip_all_custom_flags'), 0)
+  CheckNsyms(test.built_file_path(
+      'strip_all_bundle.framework/Versions/A/strip_all_bundle', chdir='strip'),
+      0)
+  CheckNsyms(OutPath('strip_save'), 7)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-type-envvars.py b/gyp/test/mac/gyptest-type-envvars.py
new file mode 100755 (executable)
index 0000000..61596ba
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test that MACH_O_TYPE etc are set correctly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  test.run_gyp('test.gyp', chdir='type_envvars')
+
+  test.build('test.gyp', test.ALL, chdir='type_envvars')
+
+  # The actual test is done by postbuild scripts during |test.build()|.
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-unicode-settings.py b/gyp/test/mac/gyptest-unicode-settings.py
new file mode 100644 (file)
index 0000000..a71b3bd
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that unicode strings in 'xcode_settings' work.
+Also checks that ASCII control characters are escaped properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['xcode'])
+  test.run_gyp('test.gyp', chdir='unicode-settings')
+  test.build('test.gyp', test.ALL, chdir='unicode-settings')
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-xcode-env-order.py b/gyp/test/mac/gyptest-xcode-env-order.py
new file mode 100755 (executable)
index 0000000..e70cf13
--- /dev/null
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that dependent Xcode settings are processed correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import subprocess
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'xcode-env-order'
+  INFO_PLIST_PATH = 'Test.app/Contents/Info.plist'
+
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+  # Env vars in 'copies' filenames.
+  test.built_file_must_exist('Test-copy-brace/main.c', chdir=CHDIR)
+  test.built_file_must_exist('Test-copy-paren/main.c', chdir=CHDIR)
+  test.built_file_must_exist('Test-copy-bare/main.c', chdir=CHDIR)
+
+  # Env vars in 'actions' filenames and inline actions
+  test.built_file_must_exist('action-copy-brace.txt', chdir=CHDIR)
+  test.built_file_must_exist('action-copy-paren.txt', chdir=CHDIR)
+  test.built_file_must_exist('action-copy-bare.txt', chdir=CHDIR)
+
+  # Env vars in 'rules' filenames and inline actions
+  test.built_file_must_exist('rule-copy-brace.txt', chdir=CHDIR)
+  test.built_file_must_exist('rule-copy-paren.txt', chdir=CHDIR)
+  # TODO: see comment in test.gyp for this file.
+  #test.built_file_must_exist('rule-copy-bare.txt', chdir=CHDIR)
+
+  # Env vars in Info.plist.
+  info_plist = test.built_file_path(INFO_PLIST_PATH, chdir=CHDIR)
+  test.must_exist(info_plist)
+
+  test.must_contain(info_plist, '''\
+\t<key>BraceProcessedKey1</key>
+\t<string>D:/Source/Project/Test</string>''')
+  test.must_contain(info_plist, '''\
+\t<key>BraceProcessedKey2</key>
+\t<string>/Source/Project/Test</string>''')
+  test.must_contain(info_plist, '''\
+\t<key>BraceProcessedKey3</key>
+\t<string>com.apple.product-type.application:D:/Source/Project/Test</string>''')
+
+  test.must_contain(info_plist, '''\
+\t<key>ParenProcessedKey1</key>
+\t<string>D:/Source/Project/Test</string>''')
+  test.must_contain(info_plist, '''\
+\t<key>ParenProcessedKey2</key>
+\t<string>/Source/Project/Test</string>''')
+  test.must_contain(info_plist, '''\
+\t<key>ParenProcessedKey3</key>
+\t<string>com.apple.product-type.application:D:/Source/Project/Test</string>''')
+
+  test.must_contain(info_plist, '''\
+\t<key>BareProcessedKey1</key>
+\t<string>D:/Source/Project/Test</string>''')
+  test.must_contain(info_plist, '''\
+\t<key>BareProcessedKey2</key>
+\t<string>/Source/Project/Test</string>''')
+  # NOTE: For bare variables, $PRODUCT_TYPE is not replaced! It _is_ replaced
+  # if it's not right at the start of the string (e.g. ':$PRODUCT_TYPE'), so
+  # this looks like an Xcode bug. This bug isn't emulated (yet?), so check this
+  # only for Xcode.
+  if test.format == 'xcode' and TestMac.Xcode.Version() < '0500':
+    test.must_contain(info_plist, '''\
+\t<key>BareProcessedKey3</key>
+\t<string>$PRODUCT_TYPE:D:/Source/Project/Test</string>''')
+  else:
+    # The bug has been fixed by Xcode version 5.0.0.
+    test.must_contain(info_plist, '''\
+\t<key>BareProcessedKey3</key>
+\t<string>com.apple.product-type.application:D:/Source/Project/Test</string>''')
+
+  test.must_contain(info_plist, '''\
+\t<key>MixedProcessedKey</key>
+\t<string>/Source/Project:Test:mh_execute</string>''')
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-xcode-gcc-clang.py b/gyp/test/mac/gyptest-xcode-gcc-clang.py
new file mode 100644 (file)
index 0000000..981c3fc
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that xcode-style GCC_... settings that require clang are handled
+properly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'xcode-gcc'
+  test.run_gyp('test-clang.gyp', chdir=CHDIR)
+
+  test.build('test-clang.gyp', 'aliasing_yes', chdir=CHDIR)
+  test.run_built_executable('aliasing_yes', chdir=CHDIR, stdout="1\n")
+  test.build('test-clang.gyp', 'aliasing_no', chdir=CHDIR)
+  test.run_built_executable('aliasing_no', chdir=CHDIR, stdout="0\n")
+
+  # The default behavior changed: strict aliasing used to be off, now it's on
+  # by default. The important part is that this is identical for all generators
+  # (which it is). TODO(thakis): Enable this once the bots have a newer Xcode.
+  #test.build('test-clang.gyp', 'aliasing_default', chdir=CHDIR)
+  #test.run_built_executable('aliasing_default', chdir=CHDIR, stdout="1\n")
+  # For now, just check the generated ninja file:
+  if test.format == 'ninja':
+    contents = open(test.built_file_path('obj/aliasing_default.ninja',
+                                         chdir=CHDIR)).read()
+    if 'strict-aliasing' in contents:
+      test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-xcode-gcc.py b/gyp/test/mac/gyptest-xcode-gcc.py
new file mode 100644 (file)
index 0000000..e45d0b5
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that xcode-style GCC_... settings are handled properly.
+"""
+
+import TestGyp
+
+import os
+import subprocess
+import sys
+
+def IgnoreOutput(string, expected_string):
+  return True
+
+def CompilerVersion(compiler):
+  stdout = subprocess.check_output([compiler, '-v'], stderr=subprocess.STDOUT)
+  return stdout.rstrip('\n')
+
+def CompilerSupportsWarnAboutInvalidOffsetOfMacro(test):
+  # "clang" does not support the "-Winvalid-offsetof" flag, and silently
+  # ignore it. Starting with Xcode 5.0.0, "gcc" is just a "clang" binary with
+  # some hard-coded include path hack, so use the output of "-v" to detect if
+  # the compiler supports the flag or not.
+  return 'clang' not in CompilerVersion('/usr/bin/cc')
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+  CHDIR = 'xcode-gcc'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+
+  # List of targets that'll pass. It expects targets of the same name with
+  # '-fail' appended that'll fail to build.
+  targets = [
+    'warn_about_missing_newline',
+  ]
+
+  # clang doesn't warn on invalid offsetofs, it silently ignores
+  # -Wno-invalid-offsetof.
+  if CompilerSupportsWarnAboutInvalidOffsetOfMacro(test):
+    targets.append('warn_about_invalid_offsetof_macro')
+
+  for target in targets:
+    test.build('test.gyp', target, chdir=CHDIR)
+    test.built_file_must_exist(target, chdir=CHDIR)
+    fail_target = target + '-fail'
+    test.build('test.gyp', fail_target, chdir=CHDIR, status=None,
+               stderr=None, match=IgnoreOutput)
+    test.built_file_must_not_exist(fail_target, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-xcode-support-actions.py b/gyp/test/mac/gyptest-xcode-support-actions.py
new file mode 100755 (executable)
index 0000000..ecc1402
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that support actions are properly created.
+"""
+
+import TestGyp
+
+import os
+import subprocess
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['xcode'])
+
+  CHDIR = 'xcode-support-actions'
+
+  test.run_gyp('test.gyp', '-Gsupport_target_suffix=_customsuffix', chdir=CHDIR)
+  test.build('test.gyp', target='target_customsuffix', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/mac/gyptest-xctest.py b/gyp/test/mac/gyptest-xctest.py
new file mode 100644 (file)
index 0000000..a46a5fb
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that xctest targets are correctly configured.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['xcode'])
+
+  # Ignore this test if Xcode 5 is not installed
+  import subprocess
+  job = subprocess.Popen(['xcodebuild', '-version'],
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.STDOUT)
+  out, err = job.communicate()
+  if job.returncode != 0:
+    raise Exception('Error %d running xcodebuild' % job.returncode)
+  xcode_version, build_number = out.splitlines()
+  # Convert the version string from 'Xcode 5.0' to ['5','0'].
+  xcode_version = xcode_version.split()[-1].split('.')
+  if xcode_version < ['5']:
+    test.pass_test()
+
+  CHDIR = 'xctest'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', chdir=CHDIR, arguments=['-scheme', 'classes', 'test'])
+
+  test.built_file_must_match('tests.xctest/Contents/Resources/resource.txt',
+                             'foo\n', chdir=CHDIR)
+  test.pass_test()
diff --git a/gyp/test/mac/infoplist-process/Info.plist b/gyp/test/mac/infoplist-process/Info.plist
new file mode 100644 (file)
index 0000000..cb65721
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.google.${PRODUCT_NAME}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+       <key>NSMainNibFile</key>
+       <string>MainMenu</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+       <key>ProcessedKey1</key>
+        <string>PROCESSED_KEY1</string>
+       <key>ProcessedKey2</key>
+        <string>PROCESSED_KEY2</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/infoplist-process/main.c b/gyp/test/mac/infoplist-process/main.c
new file mode 100644 (file)
index 0000000..1bf4b2a
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/mac/infoplist-process/test1.gyp b/gyp/test/mac/infoplist-process/test1.gyp
new file mode 100644 (file)
index 0000000..bc625a9
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'main.c',
+      ],
+      'configurations': {
+        'One': {
+        },
+      },
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+        'INFOPLIST_PREPROCESS': 'YES',
+        'INFOPLIST_PREPROCESSOR_DEFINITIONS': 'PROCESSED_KEY1=Foo PROCESSED_KEY2=Bar',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/infoplist-process/test2.gyp b/gyp/test/mac/infoplist-process/test2.gyp
new file mode 100644 (file)
index 0000000..ecfbc9f
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'main.c',
+      ],
+      'configurations': {
+        'Two': {
+        },
+      },
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+        'INFOPLIST_PREPROCESS': 'YES',
+        'INFOPLIST_PREPROCESSOR_DEFINITIONS': 'PROCESSED_KEY1="Foo (Bar)"',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/infoplist-process/test3.gyp b/gyp/test/mac/infoplist-process/test3.gyp
new file mode 100644 (file)
index 0000000..be8fe75
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test App',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'main.c',
+      ],
+      'configurations': {
+        'Three': {
+        },
+      },
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+        'INFOPLIST_PREPROCESS': 'NO',
+        'INFOPLIST_PREPROCESSOR_DEFINITIONS': 'PROCESSED_KEY1=Foo',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/installname/Info.plist b/gyp/test/mac/installname/Info.plist
new file mode 100644 (file)
index 0000000..5e05a51
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.yourcompany.${PRODUCT_NAME}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>NSPrincipalClass</key>
+       <string></string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/installname/file.c b/gyp/test/mac/installname/file.c
new file mode 100644 (file)
index 0000000..a39fce0
--- /dev/null
@@ -0,0 +1 @@
+int f() { return 0; }
diff --git a/gyp/test/mac/installname/main.c b/gyp/test/mac/installname/main.c
new file mode 100644 (file)
index 0000000..237c8ce
--- /dev/null
@@ -0,0 +1 @@
+int main() {}
diff --git a/gyp/test/mac/installname/test.gyp b/gyp/test/mac/installname/test.gyp
new file mode 100644 (file)
index 0000000..60c867f
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'default_installname',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+    },
+    {
+      'target_name': 'default_bundle_installname',
+      'product_name': 'My Framework',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.c' ],
+    },
+    {
+      'target_name': 'explicit_installname',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+      'xcode_settings': {
+        'LD_DYLIB_INSTALL_NAME': 'Trapped in a dynamiclib factory',
+      },
+    },
+    {
+      'target_name': 'explicit_installname_base',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+      'xcode_settings': {
+        'DYLIB_INSTALL_NAME_BASE': '@executable_path/../../..',
+
+      },
+    },
+    {
+      'target_name': 'explicit_installname_base_bundle',
+      'product_name': 'My Other Framework',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.c' ],
+      'xcode_settings': {
+        'DYLIB_INSTALL_NAME_BASE': '@executable_path/../../..',
+
+      },
+    },
+    {
+      'target_name': 'both_base_and_installname',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+      'xcode_settings': {
+        # LD_DYLIB_INSTALL_NAME wins.
+        'LD_DYLIB_INSTALL_NAME': 'Still trapped in a dynamiclib factory',
+        'DYLIB_INSTALL_NAME_BASE': '@executable_path/../../..',
+      },
+    },
+    {
+      'target_name': 'explicit_installname_with_base',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+      'xcode_settings': {
+        'LD_DYLIB_INSTALL_NAME': '$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)',
+      },
+    },
+    {
+      'target_name': 'explicit_installname_with_explicit_base',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+      'xcode_settings': {
+        'DYLIB_INSTALL_NAME_BASE': '@executable_path/..',
+        'LD_DYLIB_INSTALL_NAME': '$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)',
+      },
+    },
+    {
+      'target_name': 'executable',
+      'type': 'executable',
+      'sources': [ 'main.c' ],
+      'xcode_settings': {
+        'LD_DYLIB_INSTALL_NAME': 'Should be ignored for not shared_lib',
+      },
+    },
+    # Regression test for http://crbug.com/113918
+    {
+      'target_name': 'install_name_with_info_plist',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.c' ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+        'LD_DYLIB_INSTALL_NAME': '$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/ldflags-libtool/file.c b/gyp/test/mac/ldflags-libtool/file.c
new file mode 100644 (file)
index 0000000..56757a7
--- /dev/null
@@ -0,0 +1 @@
+void f() {}
diff --git a/gyp/test/mac/ldflags-libtool/test.gyp b/gyp/test/mac/ldflags-libtool/test.gyp
new file mode 100644 (file)
index 0000000..4e7aa07
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'ldflags_passed_to_libtool',
+      'type': 'static_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'OTHER_LDFLAGS': [
+          '-fblorfen-horf-does-not-exist',
+        ],
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/ldflags/subdirectory/Info.plist b/gyp/test/mac/ldflags/subdirectory/Info.plist
new file mode 100644 (file)
index 0000000..5f5e9ab
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/ldflags/subdirectory/file.c b/gyp/test/mac/ldflags/subdirectory/file.c
new file mode 100644 (file)
index 0000000..90c4554
--- /dev/null
@@ -0,0 +1,2 @@
+void f() {}
+void g() {}
diff --git a/gyp/test/mac/ldflags/subdirectory/symbol_list.def b/gyp/test/mac/ldflags/subdirectory/symbol_list.def
new file mode 100644 (file)
index 0000000..0ab7543
--- /dev/null
@@ -0,0 +1 @@
+_f
diff --git a/gyp/test/mac/ldflags/subdirectory/test.gyp b/gyp/test/mac/ldflags/subdirectory/test.gyp
new file mode 100644 (file)
index 0000000..db00c74
--- /dev/null
@@ -0,0 +1,66 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'raw',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'OTHER_LDFLAGS': [
+          '-exported_symbols_list symbol_list.def',
+          '-sectcreate __TEXT __info_plist Info.plist',
+        ],
+      },
+    },
+    # TODO(thakis): This form should ideally be supported, too. (But
+    # -Wlfoo,bar,baz is cleaner so people should use that anyway.)
+    #{
+    #  'target_name': 'raw_sep',
+    #  'type': 'shared_library',
+    #  'sources': [ 'file.c', ],
+    #  'xcode_settings': {
+    #    'OTHER_LDFLAGS': [
+    #      '-exported_symbols_list', 'symbol_list.def',
+    #      '-sectcreate', '__TEXT', '__info_plist', 'Info.plist',
+    #    ],
+    #  },
+    #},
+    {
+      'target_name': 'wl_space',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'OTHER_LDFLAGS': [
+          # Works because clang passes unknown files on to the linker.
+          '-Wl,-exported_symbols_list symbol_list.def',
+        ],
+      },
+    },
+    # TODO(thakis): This form should ideally be supported, too. (But
+    # -Wlfoo,bar,baz is cleaner so people should use that anyway.)
+    #{
+    #  'target_name': 'wl_space_sep',
+    #  'type': 'shared_library',
+    #  'sources': [ 'file.c', ],
+    #  'xcode_settings': {
+    #    'OTHER_LDFLAGS': [
+    #      # Works because clang passes unknown files on to the linker.
+    #      '-Wl,-exported_symbols_list', 'symbol_list.def',
+    #    ],
+    #  },
+    #},
+    {
+      'target_name': 'wl_comma',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'OTHER_LDFLAGS': [
+          '-Wl,-exported_symbols_list,symbol_list.def',
+          '-Wl,-sectcreate,__TEXT,__info_plist,Info.plist',
+        ],
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/libraries/subdir/README.txt b/gyp/test/mac/libraries/subdir/README.txt
new file mode 100644 (file)
index 0000000..4031ded
--- /dev/null
@@ -0,0 +1 @@
+Make things live in a subdirectory, to make sure that DEPTH works correctly.
diff --git a/gyp/test/mac/libraries/subdir/hello.cc b/gyp/test/mac/libraries/subdir/hello.cc
new file mode 100644 (file)
index 0000000..a43554c
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iostream>
+
+int main() {
+  std::cout << "Hello, world!" << std::endl;
+  return 0;
+}
diff --git a/gyp/test/mac/libraries/subdir/mylib.c b/gyp/test/mac/libraries/subdir/mylib.c
new file mode 100644 (file)
index 0000000..e771991
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int my_foo(int x) {
+  return x + 1;
+}
diff --git a/gyp/test/mac/libraries/subdir/test.gyp b/gyp/test/mac/libraries/subdir/test.gyp
new file mode 100644 (file)
index 0000000..59fef51
--- /dev/null
@@ -0,0 +1,65 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libraries-test',
+      'type': 'executable',
+      'sources': [
+        'hello.cc',
+      ],
+      'link_settings': {
+        'libraries': [
+          'libcrypto.dylib',
+        ],
+      },
+    },
+    {
+      # This creates a static library and puts it in a nonstandard location for
+      # libraries-search-path-test.
+      'target_name': 'mylib',
+      'type': 'static_library',
+      'sources': [
+        'mylib.c',
+      ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Make a secret location',
+          'action': [
+            'mkdir',
+            '-p',
+            '${SRCROOT}/../secret_location',
+          ],
+        },
+        {
+          'postbuild_name': 'Copy to secret location, with secret name',
+          'action': [
+            'cp',
+            '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}',
+            '${SRCROOT}/../secret_location/libmysecretlib.a',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'libraries-search-path-test',
+      'type': 'executable',
+      'dependencies': [ 'mylib' ],
+      'sources': [
+        'hello.cc',
+      ],
+      'xcode_settings': {
+        'LIBRARY_SEARCH_PATHS': [
+          '<(DEPTH)/secret_location',
+        ],
+      },
+      'link_settings': {
+        'libraries': [
+          'libmysecretlib.a',
+        ],
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/loadable-module-bundle-product-extension/src.cc b/gyp/test/mac/loadable-module-bundle-product-extension/src.cc
new file mode 100644 (file)
index 0000000..3d878e9
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int test() {
+  return 1337;
+}
diff --git a/gyp/test/mac/loadable-module-bundle-product-extension/test.gyp b/gyp/test/mac/loadable-module-bundle-product-extension/test.gyp
new file mode 100644 (file)
index 0000000..684a2c0
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [{
+    'target_name': 'test',
+    'type': 'none',
+    'dependencies': ['child_one', 'child_two'],
+  }, {
+    'target_name': 'child_one',
+    'product_name': 'Collide',
+    'product_extension': 'bar',
+    'sources': ['src.cc'],
+    'type': 'loadable_module',
+    'mac_bundle': 1,
+  }, {
+    'target_name': 'child_two',
+    'product_name': 'Collide',
+    'product_extension': 'foo',
+    'sources': ['src.cc'],
+    'type': 'loadable_module',
+    'mac_bundle': 1,
+  }],
+}
diff --git a/gyp/test/mac/loadable-module/Info.plist b/gyp/test/mac/loadable-module/Info.plist
new file mode 100644 (file)
index 0000000..f6607ae
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.google.test_loadable_module</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>BRPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0</string>
+       <key>CFPlugInDynamicRegisterFunction</key>
+       <string></string>
+       <key>CFPlugInDynamicRegistration</key>
+       <string>NO</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/loadable-module/module.c b/gyp/test/mac/loadable-module/module.c
new file mode 100644 (file)
index 0000000..9584538
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int SuperFly() {
+  return 42;
+}
+
+const char* SuperFoo() {
+  return "Hello World";
+}
diff --git a/gyp/test/mac/loadable-module/test.gyp b/gyp/test/mac/loadable-module/test.gyp
new file mode 100644 (file)
index 0000000..3c8a530
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'test_loadable_module',
+      'type': 'loadable_module',
+      'mac_bundle': 1,
+      'sources': [ 'module.c' ],
+      'product_extension': 'plugin',
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/missing-cfbundlesignature/Info.plist b/gyp/test/mac/missing-cfbundlesignature/Info.plist
new file mode 100644 (file)
index 0000000..0c31674
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/missing-cfbundlesignature/Other-Info.plist b/gyp/test/mac/missing-cfbundlesignature/Other-Info.plist
new file mode 100644 (file)
index 0000000..4709528
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+        <key>CFBundleSignature</key>
+        <string>F</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/missing-cfbundlesignature/Third-Info.plist b/gyp/test/mac/missing-cfbundlesignature/Third-Info.plist
new file mode 100644 (file)
index 0000000..5b61fe2
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+        <key>CFBundleSignature</key>
+        <string>some really long string</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/missing-cfbundlesignature/file.c b/gyp/test/mac/missing-cfbundlesignature/file.c
new file mode 100644 (file)
index 0000000..237c8ce
--- /dev/null
@@ -0,0 +1 @@
+int main() {}
diff --git a/gyp/test/mac/missing-cfbundlesignature/test.gyp b/gyp/test/mac/missing-cfbundlesignature/test.gyp
new file mode 100644 (file)
index 0000000..b50cc27
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'mytarget',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+      },
+    },
+    {
+      'target_name': 'myothertarget',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Other-Info.plist',
+      },
+    },
+    {
+      'target_name': 'thirdtarget',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Third-Info.plist',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/non-strs-flattened-to-env/Info.plist b/gyp/test/mac/non-strs-flattened-to-env/Info.plist
new file mode 100644 (file)
index 0000000..11fc4b6
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+        <!-- Not a valid plist file since it's missing so much. That's fine. -->
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>My Variable</key>
+       <string>${MY_VAR}</string>
+       <key>CFlags</key>
+       <string>${OTHER_CFLAGS}</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/non-strs-flattened-to-env/main.c b/gyp/test/mac/non-strs-flattened-to-env/main.c
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/mac/non-strs-flattened-to-env/test.gyp b/gyp/test/mac/non-strs-flattened-to-env/test.gyp
new file mode 100644 (file)
index 0000000..aaf821c
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [ 'main.c', ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+        'MY_VAR': 'some expansion',
+        'OTHER_CFLAGS': [
+          # Just some (more than one) random flags.
+          '-fstack-protector-all',
+          '-fno-strict-aliasing',
+          '-DS="A Space"',  # Would normally be in 'defines'
+        ],
+      },
+      'include_dirs': [
+        '$(SDKROOT)/usr/include/libxml2',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/objc-arc/c-file.c b/gyp/test/mac/objc-arc/c-file.c
new file mode 100644 (file)
index 0000000..6536132
--- /dev/null
@@ -0,0 +1,6 @@
+#if __has_feature(objc_arc)
+#error "C files shouldn't be ARC'd!"
+#endif
+
+void c_fun() {}
+
diff --git a/gyp/test/mac/objc-arc/cc-file.cc b/gyp/test/mac/objc-arc/cc-file.cc
new file mode 100644 (file)
index 0000000..95e14ea
--- /dev/null
@@ -0,0 +1,5 @@
+#if __has_feature(objc_arc)
+#error "C++ files shouldn't be ARC'd!"
+#endif
+
+void cc_fun() {}
diff --git a/gyp/test/mac/objc-arc/m-file-no-arc.m b/gyp/test/mac/objc-arc/m-file-no-arc.m
new file mode 100644 (file)
index 0000000..8ffaabf
--- /dev/null
@@ -0,0 +1,5 @@
+#if __has_feature(objc_arc)
+#error "ObjC files without CLANG_ENABLE_OBJC_ARC should not be ARC'd!"
+#endif
+
+void m_fun() {}
diff --git a/gyp/test/mac/objc-arc/m-file.m b/gyp/test/mac/objc-arc/m-file.m
new file mode 100644 (file)
index 0000000..9689b1f
--- /dev/null
@@ -0,0 +1,5 @@
+#if !__has_feature(objc_arc)
+#error "ObjC files with CLANG_ENABLE_OBJC_ARC should be ARC'd!"
+#endif
+
+void m_fun() {}
diff --git a/gyp/test/mac/objc-arc/mm-file-no-arc.mm b/gyp/test/mac/objc-arc/mm-file-no-arc.mm
new file mode 100644 (file)
index 0000000..0dac539
--- /dev/null
@@ -0,0 +1,5 @@
+#if __has_feature(objc_arc)
+#error "ObjC++ files without CLANG_ENABLE_OBJC_ARC should not be ARC'd!"
+#endif
+
+void mm_fun() {}
diff --git a/gyp/test/mac/objc-arc/mm-file.mm b/gyp/test/mac/objc-arc/mm-file.mm
new file mode 100644 (file)
index 0000000..9467e96
--- /dev/null
@@ -0,0 +1,5 @@
+#if !__has_feature(objc_arc)
+#error "ObjC++ files with CLANG_ENABLE_OBJC_ARC should be ARC'd!"
+#endif
+
+void mm_fun() {}
diff --git a/gyp/test/mac/objc-arc/test.gyp b/gyp/test/mac/objc-arc/test.gyp
new file mode 100644 (file)
index 0000000..59cf0e2
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+    ['CXX', '/usr/bin/clang++'],
+  ],
+
+  'targets': [
+    {
+      'target_name': 'arc_enabled',
+      'type': 'static_library',
+      'sources': [
+        'c-file.c',
+        'cc-file.cc',
+        'm-file.m',
+        'mm-file.mm',
+      ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'MACOSX_DEPLOYMENT_TARGET': '10.6',
+        'ARCHS': [ 'x86_64' ],  # For the non-fragile objc ABI.
+        'CLANG_ENABLE_OBJC_ARC': 'YES',
+      },
+    },
+
+    {
+      'target_name': 'arc_disabled',
+      'type': 'static_library',
+      'sources': [
+        'c-file.c',
+        'cc-file.cc',
+        'm-file-no-arc.m',
+        'mm-file-no-arc.mm',
+      ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'MACOSX_DEPLOYMENT_TARGET': '10.6',
+        'ARCHS': [ 'x86_64' ],  # For the non-fragile objc ABI.
+      },
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/objc-gc/c-file.c b/gyp/test/mac/objc-gc/c-file.c
new file mode 100644 (file)
index 0000000..2855a00
--- /dev/null
@@ -0,0 +1 @@
+void c_fun() {}
diff --git a/gyp/test/mac/objc-gc/cc-file.cc b/gyp/test/mac/objc-gc/cc-file.cc
new file mode 100644 (file)
index 0000000..71e47a0
--- /dev/null
@@ -0,0 +1 @@
+void cc_fun() {}
diff --git a/gyp/test/mac/objc-gc/main.m b/gyp/test/mac/objc-gc/main.m
new file mode 100644 (file)
index 0000000..1a87f8e
--- /dev/null
@@ -0,0 +1,6 @@
+#import <Foundation/Foundation.h>
+
+int main() {
+  printf("gc on: %d\n", [NSGarbageCollector defaultCollector] != NULL);
+  return 0;
+}
diff --git a/gyp/test/mac/objc-gc/needs-gc-mm.mm b/gyp/test/mac/objc-gc/needs-gc-mm.mm
new file mode 100644 (file)
index 0000000..fc3fee9
--- /dev/null
@@ -0,0 +1 @@
+void objcpp_fun() { }
diff --git a/gyp/test/mac/objc-gc/needs-gc.m b/gyp/test/mac/objc-gc/needs-gc.m
new file mode 100644 (file)
index 0000000..ca77976
--- /dev/null
@@ -0,0 +1 @@
+void objc_fun() { }
diff --git a/gyp/test/mac/objc-gc/test.gyp b/gyp/test/mac/objc-gc/test.gyp
new file mode 100644 (file)
index 0000000..4d827c1
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    # For some reason, static_library targets that are built with gc=required
+    # and then linked to executables that don't use gc, the linker doesn't
+    # complain. For shared_libraries it does, so use that.
+    {
+      'target_name': 'no_gc_lib',
+      'type': 'shared_library',
+      'sources': [
+        'c-file.c',
+        'cc-file.cc',
+        'needs-gc-mm.mm',
+        'needs-gc.m',
+      ],
+    },
+    {
+      'target_name': 'gc_lib',
+      'type': 'shared_library',
+      'sources': [
+        'c-file.c',
+        'cc-file.cc',
+        'needs-gc-mm.mm',
+        'needs-gc.m',
+      ],
+      'xcode_settings': {
+        'GCC_ENABLE_OBJC_GC': 'supported',
+      },
+    },
+    {
+      'target_name': 'gc_req_lib',
+      'type': 'shared_library',
+      'sources': [
+        'c-file.c',
+        'cc-file.cc',
+        'needs-gc-mm.mm',
+        'needs-gc.m',
+      ],
+      'xcode_settings': {
+        'GCC_ENABLE_OBJC_GC': 'required',
+      },
+    },
+
+    {
+      'target_name': 'gc_exe_fails',
+      'type': 'executable',
+      'sources': [ 'main.m' ],
+      'dependencies': [ 'no_gc_lib' ],
+      'xcode_settings': {
+        'GCC_ENABLE_OBJC_GC': 'required',
+      },
+      'libraries': [ 'Foundation.framework' ],
+    },
+    {
+      'target_name': 'gc_req_exe',
+      'type': 'executable',
+      'sources': [ 'main.m' ],
+      'dependencies': [ 'gc_lib' ],
+      'xcode_settings': {
+        'GCC_ENABLE_OBJC_GC': 'required',
+      },
+      'libraries': [ 'Foundation.framework' ],
+    },
+    {
+      'target_name': 'gc_exe_req_lib',
+      'type': 'executable',
+      'sources': [ 'main.m' ],
+      'dependencies': [ 'gc_req_lib' ],
+      'xcode_settings': {
+        'GCC_ENABLE_OBJC_GC': 'supported',
+      },
+      'libraries': [ 'Foundation.framework' ],
+    },
+    {
+      'target_name': 'gc_exe',
+      'type': 'executable',
+      'sources': [ 'main.m' ],
+      'dependencies': [ 'gc_lib' ],
+      'xcode_settings': {
+        'GCC_ENABLE_OBJC_GC': 'supported',
+      },
+      'libraries': [ 'Foundation.framework' ],
+    },
+    {
+      'target_name': 'gc_off_exe_req_lib',
+      'type': 'executable',
+      'sources': [ 'main.m' ],
+      'dependencies': [ 'gc_req_lib' ],
+      'libraries': [ 'Foundation.framework' ],
+    },
+    {
+      'target_name': 'gc_off_exe',
+      'type': 'executable',
+      'sources': [ 'main.m' ],
+      'dependencies': [ 'gc_lib' ],
+      'libraries': [ 'Foundation.framework' ],
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/postbuild-copy-bundle/Framework-Info.plist b/gyp/test/mac/postbuild-copy-bundle/Framework-Info.plist
new file mode 100644 (file)
index 0000000..ec36829
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.yourcompany.${PRODUCT_NAME}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>NSPrincipalClass</key>
+       <string></string>
+       <key>RandomKey</key>
+       <string>RandomValue</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/postbuild-copy-bundle/TestApp-Info.plist b/gyp/test/mac/postbuild-copy-bundle/TestApp-Info.plist
new file mode 100644 (file)
index 0000000..98fd515
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.google.${PRODUCT_NAME}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+       <key>NSMainNibFile</key>
+       <string>MainMenu</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/postbuild-copy-bundle/copied.txt b/gyp/test/mac/postbuild-copy-bundle/copied.txt
new file mode 100644 (file)
index 0000000..1784138
--- /dev/null
@@ -0,0 +1 @@
+old copied file
diff --git a/gyp/test/mac/postbuild-copy-bundle/empty.c b/gyp/test/mac/postbuild-copy-bundle/empty.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/mac/postbuild-copy-bundle/main.c b/gyp/test/mac/postbuild-copy-bundle/main.c
new file mode 100644 (file)
index 0000000..21c1963
--- /dev/null
@@ -0,0 +1,4 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+int main() {}
diff --git a/gyp/test/mac/postbuild-copy-bundle/postbuild-copy-framework.sh b/gyp/test/mac/postbuild-copy-bundle/postbuild-copy-framework.sh
new file mode 100755 (executable)
index 0000000..930fec6
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+rsync -acC --delete "$1" "$2"
diff --git a/gyp/test/mac/postbuild-copy-bundle/resource_file.sb b/gyp/test/mac/postbuild-copy-bundle/resource_file.sb
new file mode 100644 (file)
index 0000000..42057fa
--- /dev/null
@@ -0,0 +1 @@
+This is included in the framework bundle.
diff --git a/gyp/test/mac/postbuild-copy-bundle/test.gyp b/gyp/test/mac/postbuild-copy-bundle/test.gyp
new file mode 100644 (file)
index 0000000..a03e643
--- /dev/null
@@ -0,0 +1,49 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'test_bundle',
+      'product_name': 'My Framework',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'empty.c', ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Framework-Info.plist',
+      },
+      'mac_bundle_resources': [
+        'resource_file.sb',
+      ],
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Libraries',
+          'files': [ 'copied.txt' ],
+        },
+      ],
+    },
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test App',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'dependencies': [
+        'test_bundle',
+      ],
+      'sources': [ 'main.c', ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'TestApp-Info.plist',
+      },
+      'postbuilds': [
+        {
+          'postbuild_name': 'Copy dependent framework into app',
+          'action': [
+            './postbuild-copy-framework.sh',
+            '${BUILT_PRODUCTS_DIR}/My Framework.framework',
+            '${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/postbuild-defaults/Info.plist b/gyp/test/mac/postbuild-defaults/Info.plist
new file mode 100644 (file)
index 0000000..d3f54d7
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+        <!-- Not a valid plist file since it's missing so much. That's fine. -->
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleName</key>
+        <string>${PRODUCT_NAME}</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/postbuild-defaults/main.c b/gyp/test/mac/postbuild-defaults/main.c
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/mac/postbuild-defaults/postbuild-defaults.sh b/gyp/test/mac/postbuild-defaults/postbuild-defaults.sh
new file mode 100755 (executable)
index 0000000..56af2a8
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+# This is the built Info.plist in the output directory.
+PLIST="${BUILT_PRODUCTS_DIR}"/Test.app/Contents/Info  # No trailing .plist
+echo $(defaults read "${PLIST}" "CFBundleName") > "${BUILT_PRODUCTS_DIR}/result"
+
+# This is the source Info.plist next to this script file.
+PLIST="${SRCROOT}"/Info  # No trailing .plist
+echo $(defaults read "${PLIST}" "CFBundleName") \
+    >> "${BUILT_PRODUCTS_DIR}/result"
diff --git a/gyp/test/mac/postbuild-defaults/test.gyp b/gyp/test/mac/postbuild-defaults/test.gyp
new file mode 100644 (file)
index 0000000..be0a075
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [ 'main.c', ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+      },
+      'postbuilds': [
+        {
+          'postbuild_name': 'Postbuild that calls defaults',
+          'action': [
+            './postbuild-defaults.sh',
+            '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/postbuild-fail/file.c b/gyp/test/mac/postbuild-fail/file.c
new file mode 100644 (file)
index 0000000..91695b1
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// That's right, this is copyrighted.
+void f() {}
diff --git a/gyp/test/mac/postbuild-fail/postbuild-fail.sh b/gyp/test/mac/postbuild-fail/postbuild-fail.sh
new file mode 100755 (executable)
index 0000000..dc1a60d
--- /dev/null
@@ -0,0 +1,6 @@
+#!/usr/bin/bash
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+exit 1
diff --git a/gyp/test/mac/postbuild-fail/test.gyp b/gyp/test/mac/postbuild-fail/test.gyp
new file mode 100644 (file)
index 0000000..e63283d
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'nonbundle',
+      'type': 'static_library',
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Postbuild Fail',
+          'action': [ './postbuild-fail.sh', ],
+        },
+        {
+          'postbuild_name': 'Runs after failing postbuild',
+          'action': [ './touch-static.sh', ],
+        },
+      ],
+    },
+    {
+      'target_name': 'bundle',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Postbuild Fail',
+          'action': [ './postbuild-fail.sh', ],
+        },
+        {
+          'postbuild_name': 'Runs after failing postbuild',
+          'action': [ './touch-dynamic.sh', ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/postbuild-fail/touch-dynamic.sh b/gyp/test/mac/postbuild-fail/touch-dynamic.sh
new file mode 100755 (executable)
index 0000000..a388a64
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+touch "${BUILT_PRODUCTS_DIR}/dynamic_touch"
diff --git a/gyp/test/mac/postbuild-fail/touch-static.sh b/gyp/test/mac/postbuild-fail/touch-static.sh
new file mode 100755 (executable)
index 0000000..97ecaa6
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+touch "${BUILT_PRODUCTS_DIR}/static_touch"
diff --git a/gyp/test/mac/postbuild-multiple-configurations/main.c b/gyp/test/mac/postbuild-multiple-configurations/main.c
new file mode 100644 (file)
index 0000000..21c1963
--- /dev/null
@@ -0,0 +1,4 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+int main() {}
diff --git a/gyp/test/mac/postbuild-multiple-configurations/postbuild-touch-file.sh b/gyp/test/mac/postbuild-multiple-configurations/postbuild-touch-file.sh
new file mode 100755 (executable)
index 0000000..b6170cf
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+touch "${BUILT_PRODUCTS_DIR}/postbuild-file"
diff --git a/gyp/test/mac/postbuild-multiple-configurations/test.gyp b/gyp/test/mac/postbuild-multiple-configurations/test.gyp
new file mode 100644 (file)
index 0000000..c350b20
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'target_defaults': {
+    'configurations': {
+       'Debug': {},
+       'Release': {},
+    },
+  },
+  'targets': [
+    {
+      'target_name': 'random_target',
+      'type': 'executable',
+      'sources': [ 'main.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Touch a file.',
+          'action': [
+            './postbuild-touch-file.sh',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/postbuild-static-library/empty.c b/gyp/test/mac/postbuild-static-library/empty.c
new file mode 100644 (file)
index 0000000..9554336
--- /dev/null
@@ -0,0 +1,4 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+void f() {}
diff --git a/gyp/test/mac/postbuild-static-library/postbuild-touch-file.sh b/gyp/test/mac/postbuild-static-library/postbuild-touch-file.sh
new file mode 100755 (executable)
index 0000000..37de4de
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+touch "${BUILT_PRODUCTS_DIR}/$1"
diff --git a/gyp/test/mac/postbuild-static-library/test.gyp b/gyp/test/mac/postbuild-static-library/test.gyp
new file mode 100644 (file)
index 0000000..9ef55a0
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'my_lib',
+      'type': 'static_library',
+      'sources': [ 'empty.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Postbuild that touches a file',
+          'action': [
+            './postbuild-touch-file.sh', 'postbuild-file'
+          ],
+        },
+      ],
+    },
+
+    {
+      'target_name': 'my_sourceless_lib',
+      'type': 'static_library',
+      'dependencies': [ 'my_lib' ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Postbuild that touches a file',
+          'action': [
+            './postbuild-touch-file.sh', 'postbuild-file-sourceless'
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/postbuilds/copy.sh b/gyp/test/mac/postbuilds/copy.sh
new file mode 100755 (executable)
index 0000000..ecad038
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+cp "$@"
diff --git a/gyp/test/mac/postbuilds/file.c b/gyp/test/mac/postbuilds/file.c
new file mode 100644 (file)
index 0000000..653e71f
--- /dev/null
@@ -0,0 +1,4 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+void f() {}
diff --git a/gyp/test/mac/postbuilds/file_g.c b/gyp/test/mac/postbuilds/file_g.c
new file mode 100644 (file)
index 0000000..0f7849d
--- /dev/null
@@ -0,0 +1,4 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+void g() {}
diff --git a/gyp/test/mac/postbuilds/file_h.c b/gyp/test/mac/postbuilds/file_h.c
new file mode 100644 (file)
index 0000000..521d1f4
--- /dev/null
@@ -0,0 +1,4 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+void h() {}
diff --git a/gyp/test/mac/postbuilds/script/shared_library_postbuild.sh b/gyp/test/mac/postbuilds/script/shared_library_postbuild.sh
new file mode 100755 (executable)
index 0000000..c623c8b
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/bash
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+lib="${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
+nm ${lib} > /dev/null  # Just make sure this works.
+
+pattern="${1}"
+
+if [ $pattern != "a|b" ]; then
+  echo "Parameter quoting is broken"
+  exit 1
+fi
+
+if [ "${2}" != "arg with spaces" ]; then
+  echo "Parameter space escaping is broken"
+  exit 1
+fi
+
+touch "${lib}"_touch
diff --git a/gyp/test/mac/postbuilds/script/static_library_postbuild.sh b/gyp/test/mac/postbuilds/script/static_library_postbuild.sh
new file mode 100755 (executable)
index 0000000..2bf09b3
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/bash
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+lib="${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}"
+nm ${lib} > /dev/null  # Just make sure this works.
+
+pattern="${1}"
+
+if [ $pattern != "a|b" ]; then
+  echo "Parameter quote escaping is broken"
+  exit 1
+fi
+
+if [ "${2}" != "arg with spaces" ]; then
+  echo "Parameter space escaping is broken"
+  exit 1
+fi
+
+touch "${lib}"_touch.a
diff --git a/gyp/test/mac/postbuilds/subdirectory/copied_file.txt b/gyp/test/mac/postbuilds/subdirectory/copied_file.txt
new file mode 100644 (file)
index 0000000..a634f85
--- /dev/null
@@ -0,0 +1 @@
+This file should be copied to the products dir.
diff --git a/gyp/test/mac/postbuilds/subdirectory/nested_target.gyp b/gyp/test/mac/postbuilds/subdirectory/nested_target.gyp
new file mode 100644 (file)
index 0000000..6d4f239
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'nest_el',
+      'type': 'static_library',
+      'sources': [ '../file_g.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Static library postbuild',
+          'variables': {
+            'some_regex': 'a|b',
+          },
+          'action': [
+            '../script/static_library_postbuild.sh',
+            '<(some_regex)',
+            'arg with spaces',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'nest_dyna',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ '../file_h.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Dynamic library postbuild',
+          'variables': {
+            'some_regex': 'a|b',
+          },
+          'action': [
+            '../script/shared_library_postbuild.sh',
+            '<(some_regex)',
+            'arg with spaces',
+          ],
+        },
+        {
+          'postbuild_name': 'Test paths relative to gyp file',
+          'action': [
+            '../copy.sh',
+            './copied_file.txt',
+            '${BUILT_PRODUCTS_DIR}/copied_file_2.txt',
+          ],
+        },
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/postbuilds/test.gyp b/gyp/test/mac/postbuilds/test.gyp
new file mode 100644 (file)
index 0000000..7c0b523
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'el',
+      'type': 'static_library',
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Static library postbuild',
+          'variables': {
+            'some_regex': 'a|b',
+          },
+          'action': [
+            'script/static_library_postbuild.sh',
+            '<(some_regex)',
+            'arg with spaces',
+          ],
+        },
+        {
+          'postbuild_name': 'Test variable in gyp file',
+          'action': [
+            'cp',
+            '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}',
+            '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}_gyp_touch.a',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'dyna',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'dependencies': [
+        'subdirectory/nested_target.gyp:nest_dyna',
+        'subdirectory/nested_target.gyp:nest_el',
+      ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Dynamic library postbuild',
+          'variables': {
+            'some_regex': 'a|b',
+          },
+          'action': [
+            'script/shared_library_postbuild.sh',
+            '<(some_regex)',
+            'arg with spaces',
+          ],
+        },
+        {
+          'postbuild_name': 'Test variable in gyp file',
+          'action': [
+            'cp',
+            '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}',
+            '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}_gyp_touch',
+          ],
+        },
+        {
+          'postbuild_name': 'Test paths relative to gyp file',
+          'action': [
+            './copy.sh',
+            'subdirectory/copied_file.txt',
+            '${BUILT_PRODUCTS_DIR}',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'dyna_standalone',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Test variable in gyp file',
+          'action': [
+            'cp',
+            '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}',
+            '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}_gyp_touch.dylib',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'EmptyBundle',
+      'product_extension': 'bundle',
+      'type': 'executable',
+      'mac_bundle': 1,
+    },
+  ],
+}
diff --git a/gyp/test/mac/prefixheader/file.c b/gyp/test/mac/prefixheader/file.c
new file mode 100644 (file)
index 0000000..d0b39d1
--- /dev/null
@@ -0,0 +1 @@
+MyInt f() { return 0; }
diff --git a/gyp/test/mac/prefixheader/file.cc b/gyp/test/mac/prefixheader/file.cc
new file mode 100644 (file)
index 0000000..d0b39d1
--- /dev/null
@@ -0,0 +1 @@
+MyInt f() { return 0; }
diff --git a/gyp/test/mac/prefixheader/file.m b/gyp/test/mac/prefixheader/file.m
new file mode 100644 (file)
index 0000000..d0b39d1
--- /dev/null
@@ -0,0 +1 @@
+MyInt f() { return 0; }
diff --git a/gyp/test/mac/prefixheader/file.mm b/gyp/test/mac/prefixheader/file.mm
new file mode 100644 (file)
index 0000000..d0b39d1
--- /dev/null
@@ -0,0 +1 @@
+MyInt f() { return 0; }
diff --git a/gyp/test/mac/prefixheader/header.h b/gyp/test/mac/prefixheader/header.h
new file mode 100644 (file)
index 0000000..0716e50
--- /dev/null
@@ -0,0 +1 @@
+typedef int MyInt;
diff --git a/gyp/test/mac/prefixheader/test.gyp b/gyp/test/mac/prefixheader/test.gyp
new file mode 100644 (file)
index 0000000..7e6b1af
--- /dev/null
@@ -0,0 +1,82 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'prefix_header_c',
+      'type': 'static_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'GCC_PREFIX_HEADER': 'header.h',
+      },
+    },
+    {
+      'target_name': 'precompiled_prefix_header_c',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'GCC_PREFIX_HEADER': 'header.h',
+        'GCC_PRECOMPILE_PREFIX_HEADER': 'YES',
+      },
+    },
+
+    {
+      'target_name': 'prefix_header_cc',
+      'type': 'static_library',
+      'sources': [ 'file.cc', ],
+      'xcode_settings': {
+        'GCC_PREFIX_HEADER': 'header.h',
+      },
+    },
+    {
+      'target_name': 'precompiled_prefix_header_cc',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.cc', ],
+      'xcode_settings': {
+        'GCC_PREFIX_HEADER': 'header.h',
+        'GCC_PRECOMPILE_PREFIX_HEADER': 'YES',
+      },
+    },
+
+    {
+      'target_name': 'prefix_header_m',
+      'type': 'static_library',
+      'sources': [ 'file.m', ],
+      'xcode_settings': {
+        'GCC_PREFIX_HEADER': 'header.h',
+      },
+    },
+    {
+      'target_name': 'precompiled_prefix_header_m',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.m', ],
+      'xcode_settings': {
+        'GCC_PREFIX_HEADER': 'header.h',
+        'GCC_PRECOMPILE_PREFIX_HEADER': 'YES',
+      },
+    },
+
+    {
+      'target_name': 'prefix_header_mm',
+      'type': 'static_library',
+      'sources': [ 'file.mm', ],
+      'xcode_settings': {
+        'GCC_PREFIX_HEADER': 'header.h',
+      },
+    },
+    {
+      'target_name': 'precompiled_prefix_header_mm',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.mm', ],
+      'xcode_settings': {
+        'GCC_PREFIX_HEADER': 'header.h',
+        'GCC_PRECOMPILE_PREFIX_HEADER': 'YES',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/rebuild/TestApp-Info.plist b/gyp/test/mac/rebuild/TestApp-Info.plist
new file mode 100644 (file)
index 0000000..98fd515
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.google.${PRODUCT_NAME}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+       <key>NSMainNibFile</key>
+       <string>MainMenu</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/rebuild/delay-touch.sh b/gyp/test/mac/rebuild/delay-touch.sh
new file mode 100755 (executable)
index 0000000..7caf105
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+
+sleep 1  # mtime resolution is 1 sec on unix.
+touch "$1"
diff --git a/gyp/test/mac/rebuild/empty.c b/gyp/test/mac/rebuild/empty.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/mac/rebuild/main.c b/gyp/test/mac/rebuild/main.c
new file mode 100644 (file)
index 0000000..237c8ce
--- /dev/null
@@ -0,0 +1 @@
+int main() {}
diff --git a/gyp/test/mac/rebuild/test.gyp b/gyp/test/mac/rebuild/test.gyp
new file mode 100644 (file)
index 0000000..15b4e4e
--- /dev/null
@@ -0,0 +1,56 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test App',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'main.c',
+      ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'TestApp-Info.plist',
+      },
+    },
+    {
+      'target_name': 'test_app_postbuilds',
+      'product_name': 'Test App 2',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'main.c',
+      ],
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'TestApp-Info.plist',
+      },
+      'postbuilds': [
+        {
+          'postbuild_name': 'Postbuild that touches the app binary',
+          'action': [
+            './delay-touch.sh', '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'test_framework_postbuilds',
+      'product_name': 'Test Framework',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [
+        'empty.c',
+      ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'Postbuild that touches the framework binary',
+          'action': [
+            './delay-touch.sh', '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/rpath/file.c b/gyp/test/mac/rpath/file.c
new file mode 100644 (file)
index 0000000..56757a7
--- /dev/null
@@ -0,0 +1 @@
+void f() {}
diff --git a/gyp/test/mac/rpath/main.c b/gyp/test/mac/rpath/main.c
new file mode 100644 (file)
index 0000000..237c8ce
--- /dev/null
@@ -0,0 +1 @@
+int main() {}
diff --git a/gyp/test/mac/rpath/test.gyp b/gyp/test/mac/rpath/test.gyp
new file mode 100644 (file)
index 0000000..7255cb7
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'default_rpath',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+    },
+    {
+      'target_name': 'explicit_rpath',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+      'xcode_settings': {
+        'LD_RUNPATH_SEARCH_PATHS': ['@executable_path/.'],
+      },
+    },
+    {
+      'target_name': 'explicit_rpaths_escaped',
+      'type': 'shared_library',
+      'sources': [ 'file.c' ],
+      'xcode_settings': {
+        # Xcode requires spaces to be escaped, else it ends up adding two
+        # independent rpaths.
+        'LD_RUNPATH_SEARCH_PATHS': ['First\\ rpath', 'Second\\ rpath'],
+      },
+    },
+    {
+      'target_name': 'explicit_rpaths_bundle',
+      'product_name': 'My Framework',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.c' ],
+      'xcode_settings': {
+        'LD_RUNPATH_SEARCH_PATHS': ['@loader_path/.'],
+      },
+    },
+    {
+      'target_name': 'executable',
+      'type': 'executable',
+      'sources': [ 'main.c' ],
+      'xcode_settings': {
+        'LD_RUNPATH_SEARCH_PATHS': ['@executable_path/.'],
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/sdkroot/file.cc b/gyp/test/mac/sdkroot/file.cc
new file mode 100644 (file)
index 0000000..13ae971
--- /dev/null
@@ -0,0 +1,5 @@
+#include <map>
+using std::map;
+
+int main() {
+}
diff --git a/gyp/test/mac/sdkroot/test.gyp b/gyp/test/mac/sdkroot/test.gyp
new file mode 100644 (file)
index 0000000..2fc11a0
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'mytarget',
+      'type': 'executable',
+      'sources': [ 'file.cc', ],
+      'xcode_settings': {
+        'SDKROOT': 'macosx%s',
+      },
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_shorthand.sh', ],
+        },
+      ],
+    },
+    {
+      'target_name': 'absolute',
+      'type': 'executable',
+      'sources': [ 'file.cc', ],
+      'xcode_settings': {
+        'SDKROOT': '<(sdk_path)',
+      },
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_shorthand.sh', ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/sdkroot/test_shorthand.sh b/gyp/test/mac/sdkroot/test_shorthand.sh
new file mode 100755 (executable)
index 0000000..ac4ac22
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+found=false
+for sdk in 10.6 10.7 10.8 10.9 ; do
+  if expected=$(xcodebuild -version -sdk macosx$sdk Path 2>/dev/null) ; then
+    found=true
+    break
+  fi
+done
+if ! $found ; then
+  echo >&2 "cannot find installed SDK"
+  exit 1
+fi
+
+test $SDKROOT = $expected
diff --git a/gyp/test/mac/sourceless-module/empty.c b/gyp/test/mac/sourceless-module/empty.c
new file mode 100644 (file)
index 0000000..237c8ce
--- /dev/null
@@ -0,0 +1 @@
+int main() {}
diff --git a/gyp/test/mac/sourceless-module/empty.txt b/gyp/test/mac/sourceless-module/empty.txt
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/gyp/test/mac/sourceless-module/fun.c b/gyp/test/mac/sourceless-module/fun.c
new file mode 100644 (file)
index 0000000..d64ff8c
--- /dev/null
@@ -0,0 +1 @@
+int f() { return 42; }
diff --git a/gyp/test/mac/sourceless-module/test.gyp b/gyp/test/mac/sourceless-module/test.gyp
new file mode 100644 (file)
index 0000000..cbbe63d
--- /dev/null
@@ -0,0 +1,96 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'empty_bundle',
+      'type': 'loadable_module',
+      'mac_bundle': 1,
+    },
+    {
+      'target_name': 'resource_bundle',
+      'type': 'loadable_module',
+      'mac_bundle': 1,
+      'actions': [
+        {
+          'action_name': 'Add Resource',
+          'inputs': [],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/app_manifest/foo.manifest',
+          ],
+          'action': [
+            'touch', '<(INTERMEDIATE_DIR)/app_manifest/foo.manifest',
+          ],
+          'process_outputs_as_mac_bundle_resources': 1,
+        },
+      ],
+    },
+    {
+      'target_name': 'dependent_on_resource_bundle',
+      'type': 'executable',
+      'sources': [ 'empty.c' ],
+      'dependencies': [
+        'resource_bundle',
+      ],
+    },
+
+    {
+      'target_name': 'alib',
+      'type': 'static_library',
+      'sources': [ 'fun.c' ]
+    },
+    { # No sources, but depends on a static_library so must be linked.
+      'target_name': 'resource_framework',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'dependencies': [
+        'alib',
+      ],
+      'actions': [
+        {
+          'action_name': 'Add Resource',
+          'inputs': [],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/app_manifest/foo.manifest',
+          ],
+          'action': [
+            'touch', '<(INTERMEDIATE_DIR)/app_manifest/foo.manifest',
+          ],
+          'process_outputs_as_mac_bundle_resources': 1,
+        },
+      ],
+    },
+    {
+      'target_name': 'dependent_on_resource_framework',
+      'type': 'executable',
+      'sources': [ 'empty.c' ],
+      'dependencies': [
+        'resource_framework',
+      ],
+    },
+
+    { # No actions, but still have resources.
+      'target_name': 'mac_resource_bundle_no_actions',
+      'product_extension': 'bundle',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'mac_bundle_resources': [
+        'empty.txt',
+      ],
+    },
+    {
+      'target_name': 'bundle_dependent_on_resource_bundle_no_actions',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [ 'empty.c' ],
+      'dependencies': [
+        'mac_resource_bundle_no_actions',
+      ],
+      'mac_bundle_resources': [
+        '<(PRODUCT_DIR)/mac_resource_bundle_no_actions.bundle',
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/strip/file.c b/gyp/test/mac/strip/file.c
new file mode 100644 (file)
index 0000000..a4c504d
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+static void the_static_function() {}
+__attribute__((used)) void the_used_function() {}
+
+__attribute__((visibility("hidden"))) __attribute__((used))
+    void the_hidden_function() {}
+__attribute__((visibility("default"))) __attribute__((used))
+    void the_visible_function() {}
+
+extern const int eci;
+__attribute__((used)) int i;
+__attribute__((used)) const int ci = 34623;
+
+void the_function() {
+  the_static_function();
+  the_used_function();
+  the_hidden_function();
+  the_visible_function();
+}
diff --git a/gyp/test/mac/strip/main.c b/gyp/test/mac/strip/main.c
new file mode 100644 (file)
index 0000000..b2291a6
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+static void the_static_function() {}
+__attribute__((used)) void the_used_function() {}
+
+__attribute__((visibility("hidden"))) __attribute__((used))
+void the_hidden_function() {}
+__attribute__((visibility("default"))) __attribute__((used))
+void the_visible_function() {}
+
+void the_function() {}
+
+extern const int eci;
+__attribute__((used)) int i;
+__attribute__((used)) const int ci = 34623;
+
+int main() {
+  the_function();
+  the_static_function();
+  the_used_function();
+  the_hidden_function();
+  the_visible_function();
+}
diff --git a/gyp/test/mac/strip/strip.saves b/gyp/test/mac/strip/strip.saves
new file mode 100644 (file)
index 0000000..b60ca62
--- /dev/null
@@ -0,0 +1,5 @@
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file would list symbols that should not be stripped.
diff --git a/gyp/test/mac/strip/subdirectory/nested_file.c b/gyp/test/mac/strip/subdirectory/nested_file.c
new file mode 100644 (file)
index 0000000..50daa6c
--- /dev/null
@@ -0,0 +1 @@
+void nested_f() {}
diff --git a/gyp/test/mac/strip/subdirectory/nested_strip.saves b/gyp/test/mac/strip/subdirectory/nested_strip.saves
new file mode 100644 (file)
index 0000000..d434c0e
--- /dev/null
@@ -0,0 +1,5 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file would list symbols that should not be stripped.
diff --git a/gyp/test/mac/strip/subdirectory/subdirectory.gyp b/gyp/test/mac/strip/subdirectory/subdirectory.gyp
new file mode 100644 (file)
index 0000000..5d0d190
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'nested_strip_save',
+      'type': 'shared_library',
+      'sources': [ 'nested_file.c', ],
+      'xcode_settings': {
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+        'STRIPFLAGS': '-s $(CHROMIUM_STRIP_SAVE_FILE)',
+        'CHROMIUM_STRIP_SAVE_FILE': 'nested_strip.saves',
+      },
+    },
+    {
+      'target_name': 'nested_strip_save_postbuild',
+      'type': 'shared_library',
+      'sources': [ 'nested_file.c', ],
+      'xcode_settings': {
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+        'STRIPFLAGS': '-s $(CHROMIUM_STRIP_SAVE_FILE)',
+        'CHROMIUM_STRIP_SAVE_FILE': 'nested_strip.saves',
+      },
+      'postbuilds': [
+        {
+          'postbuild_name': 'Action that reads CHROMIUM_STRIP_SAVE_FILE',
+          'action': [
+            './test_reading_save_file_from_postbuild.sh',
+          ],
+        },
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/strip/subdirectory/test_reading_save_file_from_postbuild.sh b/gyp/test/mac/strip/subdirectory/test_reading_save_file_from_postbuild.sh
new file mode 100755 (executable)
index 0000000..9769436
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+set -e
+
+test -f ${CHROMIUM_STRIP_SAVE_FILE}
diff --git a/gyp/test/mac/strip/test-defaults.gyp b/gyp/test/mac/strip/test-defaults.gyp
new file mode 100644 (file)
index 0000000..e688b95
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+  ],
+  'target_defaults': {
+    'xcode_settings': {
+      'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+      'DEPLOYMENT_POSTPROCESSING': 'YES',
+      'STRIP_INSTALLED_PRODUCT': 'YES',
+    },
+  },
+  'targets': [
+    {
+      'target_name': 'single_dylib',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+    },
+    {
+      'target_name': 'single_so',
+      'type': 'loadable_module',
+      'sources': [ 'file.c', ],
+    },
+    {
+      'target_name': 'single_exe',
+      'type': 'executable',
+      'sources': [ 'main.c', ],
+    },
+
+    {
+      'target_name': 'bundle_dylib',
+      'type': 'shared_library',
+      'mac_bundle': '1',
+      'sources': [ 'file.c', ],
+    },
+    {
+      'target_name': 'bundle_so',
+      'type': 'loadable_module',
+      'mac_bundle': '1',
+      'sources': [ 'file.c', ],
+    },
+    {
+      'target_name': 'bundle_exe',
+      'type': 'executable',
+      'mac_bundle': '1',
+      'sources': [ 'main.c', ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/strip/test.gyp b/gyp/test/mac/strip/test.gyp
new file mode 100644 (file)
index 0000000..2558aa9
--- /dev/null
@@ -0,0 +1,119 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# These xcode_settings affect stripping:
+# "Deployment postprocessing involves stripping the binary, and setting
+# its file mode, owner, and group."
+#'DEPLOYMENT_POSTPROCESSING': 'YES',
+
+# "Specifies whether to strip symbol information from the binary.
+# Prerequisite: $DEPLOYMENT_POSTPROCESSING = YES" "Default Value: 'NO'"
+#'STRIP_INSTALLED_PRODUCT': 'YES',
+
+# "Values:
+# * all: Strips the binary completely, removing the symbol table and
+#        relocation information
+# * non-global: Strips nonglobal symbols but saves external symbols.
+# * debugging: Strips debugging symbols but saves local and global
+#              symbols."
+# (maps to no flag, -x, -S in that order)
+#'STRIP_STYLE': 'non-global',
+
+# "Additional strip flags"
+#'STRIPFLAGS': '-c',
+
+# "YES: Copied binaries are stripped of debugging symbols. This does
+# not cause the binary produced by the linker to be stripped. Use
+# 'STRIP_INSTALLED_PRODUCT (Strip Linked Product)' to have the linker
+# strip the binary."
+#'COPY_PHASE_STRIP': 'NO',
+{
+  'targets': [
+    {
+      'target_name': 'no_postprocess',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEPLOYMENT_POSTPROCESSING': 'NO',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+      },
+    },
+    {
+      'target_name': 'no_strip',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'NO',
+      },
+    },
+    {
+      'target_name': 'strip_all',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+        'STRIP_STYLE': 'all',
+      },
+    },
+    {
+      'target_name': 'strip_nonglobal',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+        'STRIP_STYLE': 'non-global',
+      },
+    },
+    {
+      'target_name': 'strip_debugging',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+        'STRIP_STYLE': 'debugging',
+      },
+    },
+    {
+      'target_name': 'strip_all_custom_flags',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+        'STRIP_STYLE': 'all',
+        'STRIPFLAGS': '-c',
+      },
+    },
+    {
+      'target_name': 'strip_all_bundle',
+      'type': 'shared_library',
+      'mac_bundle': '1',
+      'sources': [ 'file.c', ],
+      'xcode_settings': {
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+        'STRIP_STYLE': 'all',
+      },
+    },
+    {
+      'target_name': 'strip_save',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'dependencies': [
+        'subdirectory/subdirectory.gyp:nested_strip_save',
+        'subdirectory/subdirectory.gyp:nested_strip_save_postbuild',
+      ],
+      'xcode_settings': {
+        'DEPLOYMENT_POSTPROCESSING': 'YES',
+        'STRIP_INSTALLED_PRODUCT': 'YES',
+        'STRIPFLAGS': '-s $(CHROMIUM_STRIP_SAVE_FILE)',
+        'CHROMIUM_STRIP_SAVE_FILE': 'strip.saves',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/type_envvars/file.c b/gyp/test/mac/type_envvars/file.c
new file mode 100644 (file)
index 0000000..9cddaf1
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+void f() {}
+int main() {}
diff --git a/gyp/test/mac/type_envvars/test.gyp b/gyp/test/mac/type_envvars/test.gyp
new file mode 100644 (file)
index 0000000..4656700
--- /dev/null
@@ -0,0 +1,100 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'my_app',
+      'product_name': 'My App',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_bundle_executable.sh', ],
+        },
+      ],
+    },
+    {
+      'target_name': 'bundle_loadable_module',
+      'type': 'loadable_module',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_bundle_loadable_module.sh', ],
+        },
+      ],
+    },
+    {
+      'target_name': 'bundle_shared_library',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_bundle_shared_library.sh', ],
+        },
+      ],
+    },
+    # Types 'static_library' and 'none' can't exist as bundles.
+
+    {
+      'target_name': 'nonbundle_executable',
+      'type': 'executable',
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_nonbundle_executable.sh', ],
+        },
+      ],
+    },
+    {
+      'target_name': 'nonbundle_loadable_module',
+      'type': 'loadable_module',
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_nonbundle_loadable_module.sh', ],
+        },
+      ],
+    },
+    {
+      'target_name': 'nonbundle_shared_library',
+      'type': 'shared_library',
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_nonbundle_shared_library.sh', ],
+        },
+      ],
+    },
+    {
+      'target_name': 'nonbundle_static_library',
+      'type': 'static_library',
+      'sources': [ 'file.c', ],
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_nonbundle_static_library.sh', ],
+        },
+      ],
+    },
+    {
+      'target_name': 'nonbundle_none',
+      'type': 'none',
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_nonbundle_none.sh', ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/type_envvars/test_bundle_executable.sh b/gyp/test/mac/type_envvars/test_bundle_executable.sh
new file mode 100755 (executable)
index 0000000..5cd740c
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+test $MACH_O_TYPE = mh_execute
+test $PRODUCT_TYPE = com.apple.product-type.application
+test "${PRODUCT_NAME}" = "My App"
+test "${FULL_PRODUCT_NAME}" = "My App.app"
+
+test "${EXECUTABLE_NAME}" = "My App"
+test "${EXECUTABLE_PATH}" = "My App.app/Contents/MacOS/My App"
+test "${WRAPPER_NAME}" = "My App.app"
+
+[[ ! $DYLIB_INSTALL_NAME_BASE && ${DYLIB_INSTALL_NAME_BASE-_} ]]
+[[ ! $LD_DYLIB_INSTALL_NAME && ${LD_DYLIB_INSTALL_NAME-_} ]]
+
+"$(dirname "$0")/test_check_sdkroot.sh"
diff --git a/gyp/test/mac/type_envvars/test_bundle_loadable_module.sh b/gyp/test/mac/type_envvars/test_bundle_loadable_module.sh
new file mode 100755 (executable)
index 0000000..ea985f5
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+test $MACH_O_TYPE = mh_bundle
+test $PRODUCT_TYPE = com.apple.product-type.bundle
+test $PRODUCT_NAME = bundle_loadable_module
+test $FULL_PRODUCT_NAME = bundle_loadable_module.bundle
+
+test $EXECUTABLE_NAME = bundle_loadable_module
+test $EXECUTABLE_PATH = \
+    "bundle_loadable_module.bundle/Contents/MacOS/bundle_loadable_module"
+test $WRAPPER_NAME = bundle_loadable_module.bundle
+
+[[ ! $DYLIB_INSTALL_NAME_BASE && ${DYLIB_INSTALL_NAME_BASE-_} ]]
+[[ ! $LD_DYLIB_INSTALL_NAME && ${LD_DYLIB_INSTALL_NAME-_} ]]
+
+"$(dirname "$0")/test_check_sdkroot.sh"
diff --git a/gyp/test/mac/type_envvars/test_bundle_shared_library.sh b/gyp/test/mac/type_envvars/test_bundle_shared_library.sh
new file mode 100755 (executable)
index 0000000..bf49d45
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+test $MACH_O_TYPE = mh_dylib
+test $PRODUCT_TYPE = com.apple.product-type.framework
+test $PRODUCT_NAME = bundle_shared_library
+test $FULL_PRODUCT_NAME = bundle_shared_library.framework
+
+test $EXECUTABLE_NAME = bundle_shared_library
+test $EXECUTABLE_PATH = \
+    "bundle_shared_library.framework/Versions/A/bundle_shared_library"
+test $WRAPPER_NAME = bundle_shared_library.framework
+
+test $DYLIB_INSTALL_NAME_BASE = "/Library/Frameworks"
+test $LD_DYLIB_INSTALL_NAME = \
+    "/Library/Frameworks/bundle_shared_library.framework/Versions/A/bundle_shared_library"
+
+"$(dirname "$0")/test_check_sdkroot.sh"
diff --git a/gyp/test/mac/type_envvars/test_check_sdkroot.sh b/gyp/test/mac/type_envvars/test_check_sdkroot.sh
new file mode 100755 (executable)
index 0000000..1297dbe
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+# `xcodebuild -version` output looks like
+#    Xcode 4.6.3
+#    Build version 4H1503
+# or like
+#    Xcode 4.2
+#    Build version 4C199
+# or like
+#    Xcode 3.2.6
+#    Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0
+#    BuildVersion: 10M2518
+# Convert that to '0463', '0420' and '0326' respectively.
+function xcodeversion() {
+  xcodebuild -version | awk '/Xcode ([0-9]+\.[0-9]+(\.[0-9]+)?)/ {
+    version = $2
+    gsub(/\./, "", version)
+    if (length(version) < 3) {
+      version = version "0"
+    }
+    if (length(version) < 4) {
+      version = "0" version
+    }
+  }
+  END { print version }'
+}
+
+# Returns true if |string1| is smaller than |string2|.
+# This function assumes that both strings represent Xcode version numbers
+# as returned by |xcodeversion|.
+function smaller() {
+  local min="$(echo -ne "${1}\n${2}\n" | sort -n | head -n1)"
+  test "${min}" != "${2}"
+}
+
+if [[ "$(xcodeversion)" < "0500" ]]; then
+  # Xcode version is older than 5.0, check that SDKROOT is set but empty.
+  [[ -z "${SDKROOT}" && -z "${SDKROOT-_}" ]]
+else
+  # Xcode version is newer than 5.0, check that SDKROOT is set.
+  [[ "${SDKROOT}" == "$(xcodebuild -version -sdk '' Path)" ]]
+fi
diff --git a/gyp/test/mac/type_envvars/test_nonbundle_executable.sh b/gyp/test/mac/type_envvars/test_nonbundle_executable.sh
new file mode 100755 (executable)
index 0000000..25afcbe
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+# For some reason, Xcode doesn't set MACH_O_TYPE for non-bundle executables.
+# Check for "not set", not just "empty":
+[[ ! $MACH_O_TYPE && ${MACH_O_TYPE-_} ]]
+test $PRODUCT_TYPE = com.apple.product-type.tool
+test $PRODUCT_NAME = nonbundle_executable
+test $FULL_PRODUCT_NAME = nonbundle_executable
+
+test $EXECUTABLE_NAME = nonbundle_executable
+test $EXECUTABLE_PATH = nonbundle_executable
+[[ ! $WRAPPER_NAME && ${WRAPPER_NAME-_} ]]
+
+[[ ! $DYLIB_INSTALL_NAME_BASE && ${DYLIB_INSTALL_NAME_BASE-_} ]]
+[[ ! $LD_DYLIB_INSTALL_NAME && ${LD_DYLIB_INSTALL_NAME-_} ]]
+
+"$(dirname "$0")/test_check_sdkroot.sh"
diff --git a/gyp/test/mac/type_envvars/test_nonbundle_loadable_module.sh b/gyp/test/mac/type_envvars/test_nonbundle_loadable_module.sh
new file mode 100755 (executable)
index 0000000..9b58426
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+test $MACH_O_TYPE = mh_bundle
+test $PRODUCT_TYPE = com.apple.product-type.library.dynamic
+test $PRODUCT_NAME = nonbundle_loadable_module
+test $FULL_PRODUCT_NAME = nonbundle_loadable_module.so
+
+test $EXECUTABLE_NAME = nonbundle_loadable_module.so
+test $EXECUTABLE_PATH = nonbundle_loadable_module.so
+[[ ! $WRAPPER_NAME && ${WRAPPER_NAME-_} ]]
+
+test $DYLIB_INSTALL_NAME_BASE = "/usr/local/lib"
+test $LD_DYLIB_INSTALL_NAME = "/usr/local/lib/nonbundle_loadable_module.so"
+
+"$(dirname "$0")/test_check_sdkroot.sh"
diff --git a/gyp/test/mac/type_envvars/test_nonbundle_none.sh b/gyp/test/mac/type_envvars/test_nonbundle_none.sh
new file mode 100755 (executable)
index 0000000..871af1b
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+# Check for "not set", not just "empty":
+[[ ! $MACH_O_TYPE && ${MACH_O_TYPE-_} ]]
+[[ ! $PRODUCT_TYPE && ${PRODUCT_TYPE-_} ]]
+test $PRODUCT_NAME = nonbundle_none
+[[ ! $FULL_PRODUCT_NAME && ${FULL_PRODUCT_NAME-_} ]]
+
+[[ ! $EXECUTABLE_NAME && ${EXECUTABLE_NAME-_} ]]
+[[ ! $EXECUTABLE_PATH && ${EXECUTABLE_PATH-_} ]]
+[[ ! $WRAPPER_NAME && ${WRAPPER_NAME-_} ]]
+
+[[ ! $DYLIB_INSTALL_NAME_BASE && ${DYLIB_INSTALL_NAME_BASE-_} ]]
+[[ ! $LD_DYLIB_INSTALL_NAME && ${LD_DYLIB_INSTALL_NAME-_} ]]
+
+"$(dirname "$0")/test_check_sdkroot.sh"
diff --git a/gyp/test/mac/type_envvars/test_nonbundle_shared_library.sh b/gyp/test/mac/type_envvars/test_nonbundle_shared_library.sh
new file mode 100755 (executable)
index 0000000..cbb118b
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+test $MACH_O_TYPE = mh_dylib
+test $PRODUCT_TYPE = com.apple.product-type.library.dynamic
+test $PRODUCT_NAME = nonbundle_shared_library
+test $FULL_PRODUCT_NAME = libnonbundle_shared_library.dylib
+
+test $EXECUTABLE_NAME = libnonbundle_shared_library.dylib
+test $EXECUTABLE_PATH = libnonbundle_shared_library.dylib
+[[ ! $WRAPPER_NAME && ${WRAPPER_NAME-_} ]]
+
+test $DYLIB_INSTALL_NAME_BASE = "/usr/local/lib"
+test $LD_DYLIB_INSTALL_NAME = "/usr/local/lib/libnonbundle_shared_library.dylib"
+
+"$(dirname "$0")/test_check_sdkroot.sh"
diff --git a/gyp/test/mac/type_envvars/test_nonbundle_static_library.sh b/gyp/test/mac/type_envvars/test_nonbundle_static_library.sh
new file mode 100755 (executable)
index 0000000..86c04a9
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+test $MACH_O_TYPE = staticlib
+test $PRODUCT_TYPE = com.apple.product-type.library.static
+test $PRODUCT_NAME = nonbundle_static_library
+test $FULL_PRODUCT_NAME = libnonbundle_static_library.a
+
+test $EXECUTABLE_NAME = libnonbundle_static_library.a
+test $EXECUTABLE_PATH = libnonbundle_static_library.a
+[[ ! $WRAPPER_NAME && ${WRAPPER_NAME-_} ]]
+
+[[ ! $DYLIB_INSTALL_NAME_BASE && ${DYLIB_INSTALL_NAME_BASE-_} ]]
+[[ ! $LD_DYLIB_INSTALL_NAME && ${LD_DYLIB_INSTALL_NAME-_} ]]
+
+"$(dirname "$0")/test_check_sdkroot.sh"
diff --git a/gyp/test/mac/unicode-settings/file.cc b/gyp/test/mac/unicode-settings/file.cc
new file mode 100644 (file)
index 0000000..b2f9976
--- /dev/null
@@ -0,0 +1,2 @@
+int main() {
+}
diff --git a/gyp/test/mac/unicode-settings/test.gyp b/gyp/test/mac/unicode-settings/test.gyp
new file mode 100644 (file)
index 0000000..b331ae4
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'myapp',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [ 'file.cc', ],
+      'xcode_settings': {
+        'BUNDLE_DISPLAY_NAME': 'α\011',
+      },
+      'postbuilds': [
+        {
+          'postbuild_name': 'envtest',
+          'action': [ './test_bundle_display_name.sh', ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/unicode-settings/test_bundle_display_name.sh b/gyp/test/mac/unicode-settings/test_bundle_display_name.sh
new file mode 100755 (executable)
index 0000000..95dd626
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Copyright 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+test "${BUNDLE_DISPLAY_NAME}" = 'α    '
diff --git a/gyp/test/mac/xcode-env-order/Info.plist b/gyp/test/mac/xcode-env-order/Info.plist
new file mode 100644 (file)
index 0000000..e11f21e
--- /dev/null
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.google.${PRODUCT_NAME}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+       <key>NSMainNibFile</key>
+       <string>MainMenu</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+
+       <key>BraceProcessedKey1</key>
+       <string>${BRACE_DEPENDENT_KEY1}</string>
+       <key>BraceProcessedKey2</key>
+       <string>${BRACE_DEPENDENT_KEY2}</string>
+       <key>BraceProcessedKey3</key>
+       <string>${BRACE_DEPENDENT_KEY3}</string>
+
+       <key>ParenProcessedKey1</key>
+       <string>${PAREN_DEPENDENT_KEY1}</string>
+       <key>ParenProcessedKey2</key>
+       <string>${PAREN_DEPENDENT_KEY2}</string>
+       <key>ParenProcessedKey3</key>
+       <string>${PAREN_DEPENDENT_KEY3}</string>
+
+       <key>BareProcessedKey1</key>
+       <string>${BARE_DEPENDENT_KEY1}</string>
+       <key>BareProcessedKey2</key>
+       <string>${BARE_DEPENDENT_KEY2}</string>
+       <key>BareProcessedKey3</key>
+       <string>${BARE_DEPENDENT_KEY3}</string>
+
+       <key>MixedProcessedKey</key>
+       <string>${MIXED_DEPENDENT_KEY}</string>
+</dict>
+</plist>
diff --git a/gyp/test/mac/xcode-env-order/file.ext1 b/gyp/test/mac/xcode-env-order/file.ext1
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/mac/xcode-env-order/file.ext2 b/gyp/test/mac/xcode-env-order/file.ext2
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/mac/xcode-env-order/file.ext3 b/gyp/test/mac/xcode-env-order/file.ext3
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/mac/xcode-env-order/main.c b/gyp/test/mac/xcode-env-order/main.c
new file mode 100644 (file)
index 0000000..1bf4b2a
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/mac/xcode-env-order/test.gyp b/gyp/test/mac/xcode-env-order/test.gyp
new file mode 100644 (file)
index 0000000..8f975f7
--- /dev/null
@@ -0,0 +1,121 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'main.c',
+        'file.ext1',
+        'file.ext2',
+        'file.ext3',
+      ],
+      # Env vars in copies.
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/${PRODUCT_NAME}-copy-brace',
+          'files': [ 'main.c', ],  # ${SOURCE_ROOT} doesn't work with xcode
+        },
+        {
+          'destination': '<(PRODUCT_DIR)/$(PRODUCT_NAME)-copy-paren',
+          'files': [ '$(SOURCE_ROOT)/main.c', ],
+        },
+        {
+          'destination': '<(PRODUCT_DIR)/$PRODUCT_NAME-copy-bare',
+          'files': [ 'main.c', ],  # $SOURCE_ROOT doesn't work with xcode
+        },
+      ],
+      # Env vars in actions. The $FOO's are here to test that env vars that
+      # aren't defined are handled in some way that doesn't break the build.
+      'actions': [
+        {
+          'action_name': 'Action copy braces ${PRODUCT_NAME} ${FOO}',
+          'description': 'Action copy braces ${PRODUCT_NAME} ${FOO}',
+          'inputs': [ '${SOURCE_ROOT}/main.c' ],
+          # Referencing ${PRODUCT_NAME} in action outputs doesn't work with
+          # the Xcode generator (PRODUCT_NAME expands to "Test Support").
+          'outputs': [ '<(PRODUCT_DIR)/action-copy-brace.txt' ],
+          'action': [ 'cp', '${SOURCE_ROOT}/main.c',
+                      '<(PRODUCT_DIR)/action-copy-brace.txt' ],
+        },
+        {
+          'action_name': 'Action copy parens $(PRODUCT_NAME) $(FOO)',
+          'description': 'Action copy parens $(PRODUCT_NAME) $(FOO)',
+          'inputs': [ '$(SOURCE_ROOT)/main.c' ],
+          # Referencing $(PRODUCT_NAME) in action outputs doesn't work with
+          # the Xcode generator (PRODUCT_NAME expands to "Test Support").
+          'outputs': [ '<(PRODUCT_DIR)/action-copy-paren.txt' ],
+          'action': [ 'cp', '$(SOURCE_ROOT)/main.c',
+                      '<(PRODUCT_DIR)/action-copy-paren.txt' ],
+        },
+        {
+          'action_name': 'Action copy bare $PRODUCT_NAME $FOO',
+          'description': 'Action copy bare $PRODUCT_NAME $FOO',
+          'inputs': [ '$SOURCE_ROOT/main.c' ],
+          # Referencing $PRODUCT_NAME in action outputs doesn't work with
+          # the Xcode generator (PRODUCT_NAME expands to "Test Support").
+          'outputs': [ '<(PRODUCT_DIR)/action-copy-bare.txt' ],
+          'action': [ 'cp', '$SOURCE_ROOT/main.c',
+                      '<(PRODUCT_DIR)/action-copy-bare.txt' ],
+        },
+      ],
+      # Env vars in xcode_settings.
+      'xcode_settings': {
+        'INFOPLIST_FILE': 'Info.plist',
+        'STRING_KEY': '/Source/Project',
+
+        'BRACE_DEPENDENT_KEY2': '${STRING_KEY}/${PRODUCT_NAME}',
+        'BRACE_DEPENDENT_KEY1': 'D:${BRACE_DEPENDENT_KEY2}',
+        'BRACE_DEPENDENT_KEY3': '${PRODUCT_TYPE}:${BRACE_DEPENDENT_KEY1}',
+
+        'PAREN_DEPENDENT_KEY2': '$(STRING_KEY)/$(PRODUCT_NAME)',
+        'PAREN_DEPENDENT_KEY1': 'D:$(PAREN_DEPENDENT_KEY2)',
+        'PAREN_DEPENDENT_KEY3': '$(PRODUCT_TYPE):$(PAREN_DEPENDENT_KEY1)',
+
+        'BARE_DEPENDENT_KEY2': '$STRING_KEY/$PRODUCT_NAME',
+        'BARE_DEPENDENT_KEY1': 'D:$BARE_DEPENDENT_KEY2',
+        'BARE_DEPENDENT_KEY3': '$PRODUCT_TYPE:$BARE_DEPENDENT_KEY1',
+
+        'MIXED_DEPENDENT_KEY': '${STRING_KEY}:$(PRODUCT_NAME):$MACH_O_TYPE',
+      },
+      # Env vars in rules. The $FOO's are here to test that env vars that
+      # aren't defined are handled in some way that doesn't break the build.
+      'rules': [
+        {
+          'rule_name': 'brace_rule',
+          'message': 'Rule braces ${PRODUCT_NAME} ${FOO} <(RULE_INPUT_NAME)',
+          'extension': 'ext1',
+          'inputs': [ '${SOURCE_ROOT}/main.c' ],
+          'outputs': [ '<(PRODUCT_DIR)/rule-copy-brace.txt' ],
+          'action': [ 'cp', '${SOURCE_ROOT}/main.c',
+                      '<(PRODUCT_DIR)/rule-copy-brace.txt' ],
+        },
+        {
+          'rule_name': 'paren_rule',
+          'message': 'Rule parens $(PRODUCT_NAME) $(FOO) <(RULE_INPUT_NAME)',
+          'extension': 'ext2',
+          'inputs': [ '$(SOURCE_ROOT)/main.c' ],
+          'outputs': [ '<(PRODUCT_DIR)/rule-copy-paren.txt' ],
+          'action': [ 'cp', '$(SOURCE_ROOT)/main.c',
+                      '<(PRODUCT_DIR)/rule-copy-paren.txt' ],
+        },
+        # TODO: Fails in xcode. Looks like a bug in the xcode generator though
+        #       (which uses makefiles for rules, and thinks $PRODUCT_NAME is
+        #       $(P)RODUCT_NAME).
+        #{
+        #  'rule_name': 'bare_rule',
+        #  'message': 'Rule copy bare $PRODUCT_NAME $FOO',
+        #  'extension': 'ext3',
+        #  'inputs': [ '$SOURCE_ROOT/main.c' ],
+        #  'outputs': [ '<(PRODUCT_DIR)/rule-copy-bare.txt' ],
+        #  'action': [ 'cp', '$SOURCE_ROOT/main.c',
+        #              '<(PRODUCT_DIR)/rule-copy-bare.txt' ],
+        #},
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/xcode-gcc/aliasing.cc b/gyp/test/mac/xcode-gcc/aliasing.cc
new file mode 100644 (file)
index 0000000..16a41ef
--- /dev/null
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+void check(int* h, long* k) {
+  *h = 1;
+  *k = 0;
+  printf("%d\n", *h);
+}
+
+int main(void) {
+  long k;
+  check((int*)&k, &k);
+  return 0;
+}
diff --git a/gyp/test/mac/xcode-gcc/test-clang.gyp b/gyp/test/mac/xcode-gcc/test-clang.gyp
new file mode 100644 (file)
index 0000000..9f4a98a
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+    ['CXX', '/usr/bin/clang++'],
+  ],
+
+  'targets': [
+    {
+      'target_name': 'aliasing_yes',
+      'type': 'executable',
+      'sources': [ 'aliasing.cc', ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'GCC_STRICT_ALIASING': 'YES',
+        'GCC_OPTIMIZATION_LEVEL': 2,
+      },
+    },
+    {
+      'target_name': 'aliasing_no',
+      'type': 'executable',
+      'sources': [ 'aliasing.cc', ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'GCC_STRICT_ALIASING': 'NO',
+        'GCC_OPTIMIZATION_LEVEL': 2,
+      },
+    },
+    {
+      'target_name': 'aliasing_default',
+      'type': 'executable',
+      'sources': [ 'aliasing.cc', ],
+      'xcode_settings': {
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'GCC_OPTIMIZATION_LEVEL': 2,
+      },
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/xcode-gcc/test.gyp b/gyp/test/mac/xcode-gcc/test.gyp
new file mode 100644 (file)
index 0000000..1ca8b21
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'target_defaults': {
+    'xcode_settings': {
+      'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES',
+    },
+  },
+
+  'variables': {
+    # Non-failing tests should check that these trivial files in every language
+    # still compile correctly.
+    'valid_sources': [
+      'valid_c.c',
+      'valid_cc.cc',
+      'valid_m.m',
+      'valid_mm.mm',
+    ],
+  },
+
+  # Targets come in pairs: 'foo' and 'foo-fail', with the former building with
+  # no warnings and the latter not.
+  'targets': [
+    # GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO (default: YES):
+    {
+      'target_name': 'warn_about_invalid_offsetof_macro',
+      'type': 'executable',
+      'sources': [
+        'warn_about_invalid_offsetof_macro.cc',
+        '<@(valid_sources)',
+      ],
+      'xcode_settings': {
+        'GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO': 'NO',
+      },
+    },
+    {
+      'target_name': 'warn_about_invalid_offsetof_macro-fail',
+      'type': 'executable',
+      'sources': [ 'warn_about_invalid_offsetof_macro.cc', ],
+    },
+    # GCC_WARN_ABOUT_MISSING_NEWLINE (default: NO):
+    {
+      'target_name': 'warn_about_missing_newline',
+      'type': 'executable',
+      'sources': [
+        'warn_about_missing_newline.c',
+        '<@(valid_sources)',
+      ],
+    },
+    {
+      'target_name': 'warn_about_missing_newline-fail',
+      'type': 'executable',
+      'sources': [ 'warn_about_missing_newline.c', ],
+      'xcode_settings': {
+        'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/mac/xcode-gcc/valid_c.c b/gyp/test/mac/xcode-gcc/valid_c.c
new file mode 100644 (file)
index 0000000..2b10ac3
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file exists to test that valid C files compile correctly.
+
+void FunctionInCFile(void) {
+}
diff --git a/gyp/test/mac/xcode-gcc/valid_cc.cc b/gyp/test/mac/xcode-gcc/valid_cc.cc
new file mode 100644 (file)
index 0000000..31cddc3
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file exists to test that valid C++ files compile correctly.
+
+void FunctionInCCFile() {
+}
diff --git a/gyp/test/mac/xcode-gcc/valid_m.m b/gyp/test/mac/xcode-gcc/valid_m.m
new file mode 100644 (file)
index 0000000..95bddb2
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file exists to test that valid Objective-C files compile correctly.
+
+void FunctionInMFile(void) {
+}
diff --git a/gyp/test/mac/xcode-gcc/valid_mm.mm b/gyp/test/mac/xcode-gcc/valid_mm.mm
new file mode 100644 (file)
index 0000000..a7db7e3
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file exists to test that valid Objective-C++ files compile correctly.
+
+void FunctionInMMFile() {
+}
diff --git a/gyp/test/mac/xcode-gcc/warn_about_invalid_offsetof_macro.cc b/gyp/test/mac/xcode-gcc/warn_about_invalid_offsetof_macro.cc
new file mode 100644 (file)
index 0000000..4a4612b
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define offsetof(st, m) ((unsigned)((char*)&((st*)0)->m - (char*)0))
+
+struct MyStruct {
+  virtual void MyFunc() = 0;
+  int my_member;
+};
+
+int main() {
+  unsigned x = offsetof(MyStruct, my_member);
+  return x ? 0 : 1;
+}
diff --git a/gyp/test/mac/xcode-gcc/warn_about_missing_newline.c b/gyp/test/mac/xcode-gcc/warn_about_missing_newline.c
new file mode 100644 (file)
index 0000000..6faf089
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Important: Don't terminate this file with a newline.
+int main() {
+  return 0;
+}
\ No newline at end of file
diff --git a/gyp/test/mac/xcode-support-actions/source.c b/gyp/test/mac/xcode-support-actions/source.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/mac/xcode-support-actions/test.gyp b/gyp/test/mac/xcode-support-actions/test.gyp
new file mode 100644 (file)
index 0000000..ad81b8c
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'target',
+      'product_name': 'Product',
+      'type': 'shared_library',
+      'mac_bundle': 1,
+      'sources': [
+        '<(PRODUCT_DIR)/copy.c',
+      ],
+      'actions': [
+        {
+          'action_name': 'Helper',
+          'description': 'Helps',
+          'inputs': [ 'source.c' ],
+          'outputs': [ '<(PRODUCT_DIR)/copy.c' ],
+          'action': [ 'cp', '${SOURCE_ROOT}/source.c',
+                      '<(PRODUCT_DIR)/copy.c' ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/mac/xctest/MyClass.h b/gyp/test/mac/xctest/MyClass.h
new file mode 100644 (file)
index 0000000..dde13aa
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Foundation/Foundation.h>
+
+@interface MyClass : NSObject
+@end
diff --git a/gyp/test/mac/xctest/MyClass.m b/gyp/test/mac/xctest/MyClass.m
new file mode 100644 (file)
index 0000000..df11471
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "MyClass.h"
+
+@implementation MyClass
+@end
diff --git a/gyp/test/mac/xctest/TestCase.m b/gyp/test/mac/xctest/TestCase.m
new file mode 100644 (file)
index 0000000..36846a1
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <XCTest/XCTest.h>
+#import "MyClass.h"
+
+@interface TestCase : XCTestCase
+@end
+
+@implementation TestCase
+- (void)testFoo {
+  MyClass *foo = [[MyClass alloc] init];
+  XCTAssertNotNil(foo, @"expected non-nil object");
+}
+@end
diff --git a/gyp/test/mac/xctest/resource.txt b/gyp/test/mac/xctest/resource.txt
new file mode 100644 (file)
index 0000000..257cc56
--- /dev/null
@@ -0,0 +1 @@
+foo
diff --git a/gyp/test/mac/xctest/test.gyp b/gyp/test/mac/xctest/test.gyp
new file mode 100644 (file)
index 0000000..ac25656
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'classes',
+      'type': 'static_library',
+      'sources': [
+        'MyClass.h',
+        'MyClass.m',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+        ],
+      },
+    },
+    {
+      'target_name': 'tests',
+      'type': 'loadable_module',
+      'mac_xctest_bundle': 1,
+      'sources': [
+        'TestCase.m',
+      ],
+      'dependencies': [
+        'classes',
+      ],
+      'mac_bundle_resources': [
+        'resource.txt',
+      ],
+      'xcode_settings': {
+        'WRAPPER_EXTENSION': 'xctest',
+        'FRAMEWORK_SEARCH_PATHS': [
+          '$(inherited)',
+          '$(DEVELOPER_FRAMEWORKS_DIR)',
+        ],
+        'OTHER_LDFLAGS': [
+          '$(inherited)',
+          '-ObjC',
+        ],
+      },
+    },
+  ],
+}
+
diff --git a/gyp/test/mac/xctest/test.xcodeproj/xcshareddata/xcschemes/classes.xcscheme b/gyp/test/mac/xctest/test.xcodeproj/xcshareddata/xcschemes/classes.xcscheme
new file mode 100644 (file)
index 0000000..6bd1bb9
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0500"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "D3B79173B4570A3C70A902FF"
+               BuildableName = "libclasses.a"
+               BlueprintName = "classes"
+               ReferencedContainer = "container:test.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Default">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "2ACDAB234B9E5D65CACBCF9C"
+               BuildableName = "tests.xctest"
+               BlueprintName = "tests"
+               ReferencedContainer = "container:test.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Default"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Default"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Default">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Default"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/gyp/test/make/dependencies.gyp b/gyp/test/make/dependencies.gyp
new file mode 100644 (file)
index 0000000..e2bee24
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'main',
+      'type': 'executable',
+      'sources': [
+        'main.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/make/gyptest-dependencies.py b/gyp/test/make/gyptest-dependencies.py
new file mode 100755 (executable)
index 0000000..d215f76
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that .d files and all.deps are properly generated.
+"""
+
+import TestGyp
+
+# .d files are only used by the make build.
+test = TestGyp.TestGyp(formats=['make'])
+
+test.run_gyp('dependencies.gyp')
+
+test.build('dependencies.gyp', test.ALL)
+
+deps_file = test.built_file_path(".deps/out/Default/obj.target/main/main.o.d")
+test.must_contain(deps_file, "main.h")
+
+# Build a second time to make sure we generate all.deps.
+test.build('dependencies.gyp', test.ALL)
+
+test.pass_test()
diff --git a/gyp/test/make/gyptest-noload.py b/gyp/test/make/gyptest-noload.py
new file mode 100755 (executable)
index 0000000..1f51033
--- /dev/null
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests the use of the NO_LOAD flag which makes loading sub .mk files
+optional.
+"""
+
+# Python 2.5 needs this for the with statement.
+from __future__ import with_statement
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['make'])
+
+test.run_gyp('all.gyp', chdir='noload')
+
+test.relocate('noload', 'relocate/noload')
+
+test.build('build/all.gyp', test.ALL, chdir='relocate/noload')
+test.run_built_executable('exe', chdir='relocate/noload',
+                          stdout='Hello from shared.c.\n')
+
+# Just sanity test that NO_LOAD=lib doesn't break anything.
+test.build('build/all.gyp', test.ALL, chdir='relocate/noload',
+           arguments=['NO_LOAD=lib'])
+test.run_built_executable('exe', chdir='relocate/noload',
+                          stdout='Hello from shared.c.\n')
+test.build('build/all.gyp', test.ALL, chdir='relocate/noload',
+           arguments=['NO_LOAD=z'])
+test.run_built_executable('exe', chdir='relocate/noload',
+                          stdout='Hello from shared.c.\n')
+
+# Make sure we can rebuild without reloading the sub .mk file.
+with open('relocate/noload/main.c', 'a') as src_file:
+  src_file.write("\n")
+test.build('build/all.gyp', test.ALL, chdir='relocate/noload',
+           arguments=['NO_LOAD=lib'])
+test.run_built_executable('exe', chdir='relocate/noload',
+                          stdout='Hello from shared.c.\n')
+
+# Change shared.c, but verify that it doesn't get rebuild if we don't load it.
+with open('relocate/noload/lib/shared.c', 'w') as shared_file:
+  shared_file.write(
+      '#include "shared.h"\n'
+      'const char kSharedStr[] = "modified";\n'
+  )
+test.build('build/all.gyp', test.ALL, chdir='relocate/noload',
+           arguments=['NO_LOAD=lib'])
+test.run_built_executable('exe', chdir='relocate/noload',
+                          stdout='Hello from shared.c.\n')
+
+test.pass_test()
diff --git a/gyp/test/make/main.cc b/gyp/test/make/main.cc
new file mode 100644 (file)
index 0000000..3b9a705
--- /dev/null
@@ -0,0 +1,12 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+#include "main.h"
+
+int main(void) {
+  printf("hello world\n");
+  return 0;
+}
diff --git a/gyp/test/make/main.h b/gyp/test/make/main.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/make/noload/all.gyp b/gyp/test/make/noload/all.gyp
new file mode 100644 (file)
index 0000000..1617a9e
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'exe',
+      'type': 'executable',
+      'sources': [
+        'main.c',
+      ],
+      'dependencies': [
+        'lib/shared.gyp:shared',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/make/noload/lib/shared.c b/gyp/test/make/noload/lib/shared.c
new file mode 100644 (file)
index 0000000..51776c5
--- /dev/null
@@ -0,0 +1,3 @@
+#include "shared.h"
+
+const char kSharedStr[] = "shared.c";
diff --git a/gyp/test/make/noload/lib/shared.gyp b/gyp/test/make/noload/lib/shared.gyp
new file mode 100644 (file)
index 0000000..8a8841b
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'shared',
+      'type': 'shared_library',
+      'sources': [
+        'shared.c',
+        'shared.h',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/make/noload/lib/shared.h b/gyp/test/make/noload/lib/shared.h
new file mode 100644 (file)
index 0000000..a21da75
--- /dev/null
@@ -0,0 +1 @@
+extern const char kSharedStr[];
diff --git a/gyp/test/make/noload/main.c b/gyp/test/make/noload/main.c
new file mode 100644 (file)
index 0000000..26ec188
--- /dev/null
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#include "lib/shared.h"
+
+int main(void)
+{
+  printf("Hello from %s.\n", kSharedStr);
+  return 0;
+}
diff --git a/gyp/test/make_global_settings/ar/gyptest-make_global_settings_ar.py b/gyp/test/make_global_settings/ar/gyptest-make_global_settings_ar.py
new file mode 100644 (file)
index 0000000..f935e23
--- /dev/null
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies 'AR' in make_global_settings.
+"""
+
+import os
+import sys
+import TestGyp
+
+def resolve_path(test, path):
+  if path is None:
+    return None
+  elif test.format == 'make':
+    return '$(abspath %s)' % path
+  elif test.format == 'ninja':
+    return os.path.join('..', '..', path)
+  else:
+    test.fail_test()
+
+
+def verify_ar_target(test, ar=None, rel_path=False):
+  if rel_path:
+    ar_expected = resolve_path(test, ar)
+  else:
+    ar_expected = ar
+  # Resolve default values
+  if ar_expected is None:
+    if test.format == 'make':
+      # Make generator hasn't set the default value for AR.
+      # You can remove the following assertion as long as it doesn't
+      # break existing projects.
+      test.must_not_contain('Makefile', 'AR ?= ')
+      return
+    elif test.format == 'ninja':
+      if sys.platform == 'win32':
+        ar_expected = 'lib.exe'
+      else:
+        ar_expected = 'ar'
+  if test.format == 'make':
+    test.must_contain('Makefile', 'AR ?= %s' % ar_expected)
+  elif test.format == 'ninja':
+    test.must_contain('out/Default/build.ninja', 'ar = %s' % ar_expected)
+  else:
+    test.fail_test()
+
+
+def verify_ar_host(test, ar=None, rel_path=False):
+  if rel_path:
+    ar_expected = resolve_path(test, ar)
+  else:
+    ar_expected = ar
+  # Resolve default values
+  if ar_expected is None:
+    ar_expected = 'ar'
+  if test.format == 'make':
+    test.must_contain('Makefile', 'AR.host ?= %s' % ar_expected)
+  elif test.format == 'ninja':
+    test.must_contain('out/Default/build.ninja', 'ar_host = %s' % ar_expected)
+  else:
+    test.fail_test()
+
+
+test_format = ['ninja']
+if sys.platform in ('linux2', 'darwin'):
+  test_format += ['make']
+
+test = TestGyp.TestGyp(formats=test_format)
+
+# Check default values
+test.run_gyp('make_global_settings_ar.gyp')
+verify_ar_target(test)
+
+
+# Check default values with GYP_CROSSCOMPILE enabled.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+  test.run_gyp('make_global_settings_ar.gyp')
+verify_ar_target(test)
+verify_ar_host(test)
+
+
+# Test 'AR' in 'make_global_settings'.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+  test.run_gyp('make_global_settings_ar.gyp', '-Dcustom_ar_target=my_ar')
+verify_ar_target(test, ar='my_ar', rel_path=True)
+
+
+# Test 'AR'/'AR.host' in 'make_global_settings'.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+  test.run_gyp('make_global_settings_ar.gyp',
+               '-Dcustom_ar_target=my_ar_target1',
+               '-Dcustom_ar_host=my_ar_host1')
+verify_ar_target(test, ar='my_ar_target1', rel_path=True)
+verify_ar_host(test, ar='my_ar_host1', rel_path=True)
+
+
+# Test $AR and $AR_host environment variables.
+with TestGyp.LocalEnv({'AR': 'my_ar_target2',
+                       'AR_host': 'my_ar_host2'}):
+  test.run_gyp('make_global_settings_ar.gyp')
+# Ninja generator resolves $AR in gyp phase. Make generator doesn't.
+if test.format == 'ninja':
+  if sys.platform == 'win32':
+    # TODO(yukawa): Make sure if this is an expected result or not.
+    verify_ar_target(test, ar='lib.exe', rel_path=False)
+  else:
+    verify_ar_target(test, ar='my_ar_target2', rel_path=False)
+verify_ar_host(test, ar='my_ar_host2', rel_path=False)
+
+
+# Test 'AR' in 'make_global_settings' with $AR_host environment variable.
+with TestGyp.LocalEnv({'AR_host': 'my_ar_host3'}):
+  test.run_gyp('make_global_settings_ar.gyp',
+               '-Dcustom_ar_target=my_ar_target3')
+verify_ar_target(test, ar='my_ar_target3', rel_path=True)
+verify_ar_host(test, ar='my_ar_host3', rel_path=False)
+
+
+test.pass_test()
diff --git a/gyp/test/make_global_settings/ar/make_global_settings_ar.gyp b/gyp/test/make_global_settings/ar/make_global_settings_ar.gyp
new file mode 100644 (file)
index 0000000..3430d82
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style licence that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'custom_ar_target%': '',
+    'custom_ar_host%': '',
+  },
+  'conditions': [
+    ['"<(custom_ar_target)"!=""', {
+      'make_global_settings': [
+        ['AR', '<(custom_ar_target)'],
+      ],
+    }],
+    ['"<(custom_ar_host)"!=""', {
+      'make_global_settings': [
+        ['AR.host', '<(custom_ar_host)'],
+      ],
+    }],
+  ],
+  'targets': [
+    {
+      'target_name': 'make_global_settings_ar_test',
+      'type': 'static_library',
+      'sources': [ 'foo.c' ],
+    },
+  ],
+}
diff --git a/gyp/test/make_global_settings/basics/gyptest-make_global_settings.py b/gyp/test/make_global_settings/basics/gyptest-make_global_settings.py
new file mode 100644 (file)
index 0000000..1c1b1fb
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies make_global_settings.
+"""
+
+import os
+import sys
+import TestGyp
+
+test_format = ['ninja']
+if sys.platform in ('linux2', 'darwin'):
+  test_format += ['make']
+
+test = TestGyp.TestGyp(formats=test_format)
+
+test.run_gyp('make_global_settings.gyp')
+
+if test.format == 'make':
+  cc_expected = """ifneq (,$(filter $(origin CC), undefined default))
+  CC = $(abspath clang)
+endif
+"""
+  if sys.platform == 'linux2':
+    link_expected = """
+LINK ?= flock $(builddir)/linker.lock $(abspath clang)
+"""
+  elif sys.platform == 'darwin':
+    link_expected = """
+LINK ?= ./gyp-mac-tool flock $(builddir)/linker.lock $(abspath clang)
+"""
+  test.must_contain('Makefile', cc_expected)
+  test.must_contain('Makefile', link_expected)
+if test.format == 'ninja':
+  cc_expected = 'cc = ' + os.path.join('..', '..', 'clang')
+  ld_expected = 'ld = $cc'
+  if sys.platform == 'win32':
+    ld_expected = 'link.exe'
+  test.must_contain('out/Default/build.ninja', cc_expected)
+  test.must_contain('out/Default/build.ninja', ld_expected)
+
+test.pass_test()
diff --git a/gyp/test/make_global_settings/basics/make_global_settings.gyp b/gyp/test/make_global_settings/basics/make_global_settings.gyp
new file mode 100644 (file)
index 0000000..47dbc85
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style licence that can be
+# found in the LICENSE file.
+
+{
+  'make_global_settings': [
+    ['CC', 'clang'],
+    ['LINK', 'clang'],
+  ],
+  'targets': [
+    {
+      'target_name': 'test',
+      'type': 'static_library',
+      'sources': [ 'foo.c' ],
+    },
+  ],
+}
diff --git a/gyp/test/make_global_settings/env-wrapper/gyptest-wrapper.py b/gyp/test/make_global_settings/env-wrapper/gyptest-wrapper.py
new file mode 100644 (file)
index 0000000..70d6906
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies *_wrapper in environment.
+"""
+
+import os
+import sys
+import TestGyp
+
+test_format = ['ninja']
+
+os.environ['CC_wrapper'] = 'distcc'
+os.environ['LINK_wrapper'] = 'distlink'
+os.environ['CC.host_wrapper'] = 'ccache'
+
+test = TestGyp.TestGyp(formats=test_format)
+
+old_env = dict(os.environ)
+os.environ['GYP_CROSSCOMPILE'] = '1'
+test.run_gyp('wrapper.gyp')
+os.environ.clear()
+os.environ.update(old_env)
+
+if test.format == 'ninja':
+  cc_expected = ('cc = ' + os.path.join('..', '..', 'distcc') + ' ' +
+                 os.path.join('..', '..', 'clang'))
+  cc_host_expected = ('cc_host = ' + os.path.join('..', '..', 'ccache') + ' ' +
+                      os.path.join('..', '..', 'clang'))
+  ld_expected = 'ld = ../../distlink $cc'
+  if sys.platform != 'win32':
+    ldxx_expected = 'ldxx = ../../distlink $cxx'
+
+  if sys.platform == 'win32':
+     ld_expected = 'link.exe'
+  test.must_contain('out/Default/build.ninja', cc_expected)
+  test.must_contain('out/Default/build.ninja', cc_host_expected)
+  test.must_contain('out/Default/build.ninja', ld_expected)
+  if sys.platform != 'win32':
+    test.must_contain('out/Default/build.ninja', ldxx_expected)
+
+test.pass_test()
diff --git a/gyp/test/make_global_settings/env-wrapper/wrapper.gyp b/gyp/test/make_global_settings/env-wrapper/wrapper.gyp
new file mode 100644 (file)
index 0000000..1698d71
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'make_global_settings': [
+    ['CC', 'clang'],
+    ['CC.host', 'clang'],
+  ],
+  'targets': [
+    {
+      'target_name': 'test',
+      'type': 'static_library',
+      'sources': [ 'foo.c' ],
+    },
+  ],
+}
diff --git a/gyp/test/make_global_settings/ld/gyptest-make_global_settings_ld.py b/gyp/test/make_global_settings/ld/gyptest-make_global_settings_ld.py
new file mode 100644 (file)
index 0000000..c0b0a38
--- /dev/null
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies 'LD' in make_global_settings.
+"""
+
+import os
+import sys
+import TestGyp
+
+def resolve_path(test, path):
+  if path is None:
+    return None
+  elif test.format == 'make':
+    return '$(abspath %s)' % path
+  elif test.format == 'ninja':
+    return os.path.join('..', '..', path)
+  else:
+    test.fail_test()
+
+
+def verify_ld_target(test, ld=None, rel_path=False):
+  if rel_path:
+    ld_expected = resolve_path(test, ld)
+  else:
+    ld_expected = ld
+  # Resolve default values
+  if ld_expected is None:
+    if test.format == 'make':
+      # Make generator hasn't set the default value for LD.
+      # You can remove the following assertion as long as it doesn't
+      # break existing projects.
+      test.must_not_contain('Makefile', 'LD ?= ')
+      return
+    elif test.format == 'ninja':
+      if sys.platform == 'win32':
+        ld_expected = 'link.exe'
+      else:
+        ld_expected = '$cc'
+  if test.format == 'make':
+    test.must_contain('Makefile', 'LD ?= %s' % ld_expected)
+  elif test.format == 'ninja':
+    test.must_contain('out/Default/build.ninja', 'ld = %s' % ld_expected)
+  else:
+    test.fail_test()
+
+
+def verify_ld_host(test, ld=None, rel_path=False):
+  if rel_path:
+    ld_expected = resolve_path(test, ld)
+  else:
+    ld_expected = ld
+  # Resolve default values
+  if ld_expected is None:
+    if test.format == 'make':
+      # Make generator hasn't set the default value for LD.host.
+      # You can remove the following assertion as long as it doesn't
+      # break existing projects.
+      test.must_not_contain('Makefile', 'LD.host ?= ')
+      return
+    elif test.format == 'ninja':
+      if sys.platform == 'win32':
+        ld_expected = '$ld'
+      else:
+        ld_expected = '$cc_host'
+  if test.format == 'make':
+    test.must_contain('Makefile', 'LD.host ?= %s' % ld_expected)
+  elif test.format == 'ninja':
+    test.must_contain('out/Default/build.ninja', 'ld_host = %s' % ld_expected)
+  else:
+    test.fail_test()
+
+
+test_format = ['ninja']
+if sys.platform in ('linux2', 'darwin'):
+  test_format += ['make']
+
+test = TestGyp.TestGyp(formats=test_format)
+
+# Check default values
+test.run_gyp('make_global_settings_ld.gyp')
+verify_ld_target(test)
+
+
+# Check default values with GYP_CROSSCOMPILE enabled.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+  test.run_gyp('make_global_settings_ld.gyp')
+verify_ld_target(test)
+verify_ld_host(test)
+
+
+# Test 'LD' in 'make_global_settings'.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+  test.run_gyp('make_global_settings_ld.gyp', '-Dcustom_ld_target=my_ld')
+verify_ld_target(test, ld='my_ld', rel_path=True)
+
+
+# Test 'LD'/'LD.host' in 'make_global_settings'.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+  test.run_gyp('make_global_settings_ld.gyp',
+               '-Dcustom_ld_target=my_ld_target1',
+               '-Dcustom_ld_host=my_ld_host1')
+verify_ld_target(test, ld='my_ld_target1', rel_path=True)
+verify_ld_host(test, ld='my_ld_host1', rel_path=True)
+
+
+# Unlike other environment variables such as $AR/$AR_host, $CC/$CC_host,
+# and $CXX/$CXX_host, neither Make generator nor Ninja generator recognizes
+# $LD/$LD_host environment variables as of r1935. This may or may not be
+# intentional, but here we leave a test case to verify this behavior just for
+# the record.
+# If you want to support $LD/$LD_host, please revise the following test case as
+# well as the generator.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1',
+                       'LD': 'my_ld_target2',
+                       'LD_host': 'my_ld_host2'}):
+  test.run_gyp('make_global_settings_ld.gyp')
+if test.format == 'make':
+  test.must_not_contain('Makefile', 'my_ld_target2')
+  test.must_not_contain('Makefile', 'my_ld_host2')
+elif test.format == 'ninja':
+  test.must_not_contain('out/Default/build.ninja', 'my_ld_target2')
+  test.must_not_contain('out/Default/build.ninja', 'my_ld_host2')
+
+
+test.pass_test()
diff --git a/gyp/test/make_global_settings/ld/make_global_settings_ld.gyp b/gyp/test/make_global_settings/ld/make_global_settings_ld.gyp
new file mode 100644 (file)
index 0000000..6837c77
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style licence that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'custom_ld_target%': '',
+    'custom_ld_host%': '',
+  },
+  'conditions': [
+    ['"<(custom_ld_target)"!=""', {
+      'make_global_settings': [
+        ['LD', '<(custom_ld_target)'],
+      ],
+    }],
+    ['"<(custom_ld_host)"!=""', {
+      'make_global_settings': [
+        ['LD.host', '<(custom_ld_host)'],
+      ],
+    }],
+  ],
+  'targets': [
+    {
+      'target_name': 'make_global_settings_ld_test',
+      'type': 'static_library',
+      'sources': [ 'foo.c' ],
+    },
+  ],
+}
diff --git a/gyp/test/make_global_settings/wrapper/gyptest-wrapper.py b/gyp/test/make_global_settings/wrapper/gyptest-wrapper.py
new file mode 100644 (file)
index 0000000..eb1ebfd
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies *_wrapper in make_global_settings.
+"""
+
+import os
+import sys
+import TestGyp
+
+test_format = ['ninja']
+if sys.platform in ('linux2', 'darwin'):
+  test_format += ['make']
+
+test = TestGyp.TestGyp(formats=test_format)
+
+old_env = dict(os.environ)
+os.environ['GYP_CROSSCOMPILE'] = '1'
+test.run_gyp('wrapper.gyp')
+os.environ.clear()
+os.environ.update(old_env)
+
+if test.format == 'make':
+  cc_expected = """ifneq (,$(filter $(origin CC), undefined default))
+  CC = $(abspath distcc) $(abspath clang)
+endif
+"""
+  link_expected = 'LINK ?= $(abspath distlink) $(abspath clang++)'
+  test.must_contain('Makefile', cc_expected)
+  test.must_contain('Makefile', link_expected)
+if test.format == 'ninja':
+  cc_expected = ('cc = ' + os.path.join('..', '..', 'distcc') + ' ' +
+                 os.path.join('..', '..', 'clang'))
+  cc_host_expected = ('cc_host = ' + os.path.join('..', '..', 'ccache') + ' ' +
+                      os.path.join('..', '..', 'clang'))
+  ld_expected = 'ld = ../../distlink $cc'
+  if sys.platform == 'win32':
+     ld_expected = 'link.exe'
+  test.must_contain('out/Default/build.ninja', cc_expected)
+  test.must_contain('out/Default/build.ninja', cc_host_expected)
+  test.must_contain('out/Default/build.ninja', ld_expected)
+
+test.pass_test()
diff --git a/gyp/test/make_global_settings/wrapper/wrapper.gyp b/gyp/test/make_global_settings/wrapper/wrapper.gyp
new file mode 100644 (file)
index 0000000..3d4cd04
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'make_global_settings': [
+    ['CC', 'clang'],
+    ['CC_wrapper', 'distcc'],
+    ['LINK', 'clang++'],
+    ['LINK_wrapper', 'distlink'],
+    ['CC.host', 'clang'],
+    ['CC.host_wrapper', 'ccache'],
+  ],
+  'targets': [
+    {
+      'target_name': 'test',
+      'type': 'static_library',
+      'sources': [ 'foo.c' ],
+    },
+  ],
+}
diff --git a/gyp/test/many-actions/file0 b/gyp/test/many-actions/file0
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/many-actions/file1 b/gyp/test/many-actions/file1
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/many-actions/file2 b/gyp/test/many-actions/file2
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/many-actions/file3 b/gyp/test/many-actions/file3
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/many-actions/file4 b/gyp/test/many-actions/file4
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/many-actions/gyptest-many-actions-unsorted.py b/gyp/test/many-actions/gyptest-many-actions-unsorted.py
new file mode 100644 (file)
index 0000000..5cb0338
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure lots of actions in the same target don't cause exceeding command
+line length.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('many-actions-unsorted.gyp')
+test.build('many-actions-unsorted.gyp', test.ALL)
+for i in range(15):
+  test.built_file_must_exist('generated_%d.h' % i)
+
+# Make sure the optimized cygwin setup doesn't cause problems for incremental
+# builds.
+test.touch('file1')
+test.build('many-actions-unsorted.gyp', test.ALL)
+
+test.touch('file0')
+test.build('many-actions-unsorted.gyp', test.ALL)
+
+test.touch('file2')
+test.touch('file3')
+test.touch('file4')
+test.build('many-actions-unsorted.gyp', test.ALL)
+
+test.pass_test()
diff --git a/gyp/test/many-actions/gyptest-many-actions.py b/gyp/test/many-actions/gyptest-many-actions.py
new file mode 100644 (file)
index 0000000..9c71641
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure lots of actions in the same target don't cause exceeding command
+line length.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('many-actions.gyp')
+test.build('many-actions.gyp', test.ALL)
+for i in range(200):
+  test.built_file_must_exist('generated_%d.h' % i)
+test.pass_test()
diff --git a/gyp/test/many-actions/many-actions-unsorted.gyp b/gyp/test/many-actions/many-actions-unsorted.gyp
new file mode 100644 (file)
index 0000000..eec79fe
--- /dev/null
@@ -0,0 +1,154 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'msvs_cygwin_dirs': ['../../../../<(DEPTH)/third_party/cygwin'],
+  },
+  'targets': [
+    {
+      'target_name': 'a',
+      'type': 'none',
+      'actions': [
+        # Notice that the inputs go 0, 1, ..., 0, 1, .... This is to test
+        # a regression in the msvs generator in _AddActions.
+        {
+          'action_name': 'do_0',
+          'inputs': ['file0'],
+          'outputs': ['<(PRODUCT_DIR)/generated_0.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_0.h',
+          ],
+        },
+        {
+          'action_name': 'do_1',
+          'inputs': ['file1'],
+          'outputs': ['<(PRODUCT_DIR)/generated_1.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_1.h',
+          ],
+        },
+        {
+          'action_name': 'do_2',
+          'inputs': ['file2'],
+          'outputs': ['<(PRODUCT_DIR)/generated_2.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_2.h',
+          ],
+        },
+        {
+          'action_name': 'do_3',
+          'inputs': ['file3'],
+          'outputs': ['<(PRODUCT_DIR)/generated_3.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_3.h',
+          ],
+        },
+        {
+          'action_name': 'do_4',
+          'inputs': ['file4'],
+          'outputs': ['<(PRODUCT_DIR)/generated_4.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_4.h',
+          ],
+        },
+        {
+          'action_name': 'do_5',
+          'inputs': ['file0'],
+          'outputs': ['<(PRODUCT_DIR)/generated_5.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_5.h',
+          ],
+        },
+        {
+          'action_name': 'do_6',
+          'inputs': ['file1'],
+          'outputs': ['<(PRODUCT_DIR)/generated_6.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_6.h',
+          ],
+        },
+        {
+          'action_name': 'do_7',
+          'inputs': ['file2'],
+          'outputs': ['<(PRODUCT_DIR)/generated_7.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_7.h',
+          ],
+        },
+        {
+          'action_name': 'do_8',
+          'inputs': ['file3'],
+          'outputs': ['<(PRODUCT_DIR)/generated_8.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_8.h',
+          ],
+        },
+        {
+          'action_name': 'do_9',
+          'inputs': ['file4'],
+          'outputs': ['<(PRODUCT_DIR)/generated_9.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_9.h',
+          ],
+        },
+        {
+          'action_name': 'do_10',
+          'inputs': ['file0'],
+          'outputs': ['<(PRODUCT_DIR)/generated_10.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_10.h',
+          ],
+        },
+        {
+          'action_name': 'do_11',
+          'inputs': ['file1'],
+          'outputs': ['<(PRODUCT_DIR)/generated_11.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_11.h',
+          ],
+        },
+        {
+          'action_name': 'do_12',
+          'inputs': ['file2'],
+          'outputs': ['<(PRODUCT_DIR)/generated_12.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_12.h',
+          ],
+        },
+        {
+          'action_name': 'do_13',
+          'inputs': ['file3'],
+          'outputs': ['<(PRODUCT_DIR)/generated_13.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_13.h',
+          ],
+        },
+        {
+          'action_name': 'do_14',
+          'inputs': ['file4'],
+          'outputs': ['<(PRODUCT_DIR)/generated_14.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_14.h',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/many-actions/many-actions.gyp b/gyp/test/many-actions/many-actions.gyp
new file mode 100644 (file)
index 0000000..38545d2
--- /dev/null
@@ -0,0 +1,1817 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'msvs_cygwin_dirs': ['../../../../<(DEPTH)/third_party/cygwin'],
+  },
+  'targets': [
+    {
+      'target_name': 'a',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'do_0',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_0.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_0.h',
+          ],
+        },
+        {
+          'action_name': 'do_1',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_1.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_1.h',
+          ],
+        },
+        {
+          'action_name': 'do_2',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_2.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_2.h',
+          ],
+        },
+        {
+          'action_name': 'do_3',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_3.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_3.h',
+          ],
+        },
+        {
+          'action_name': 'do_4',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_4.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_4.h',
+          ],
+        },
+        {
+          'action_name': 'do_5',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_5.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_5.h',
+          ],
+        },
+        {
+          'action_name': 'do_6',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_6.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_6.h',
+          ],
+        },
+        {
+          'action_name': 'do_7',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_7.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_7.h',
+          ],
+        },
+        {
+          'action_name': 'do_8',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_8.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_8.h',
+          ],
+        },
+        {
+          'action_name': 'do_9',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_9.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_9.h',
+          ],
+        },
+        {
+          'action_name': 'do_10',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_10.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_10.h',
+          ],
+        },
+        {
+          'action_name': 'do_11',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_11.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_11.h',
+          ],
+        },
+        {
+          'action_name': 'do_12',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_12.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_12.h',
+          ],
+        },
+        {
+          'action_name': 'do_13',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_13.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_13.h',
+          ],
+        },
+        {
+          'action_name': 'do_14',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_14.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_14.h',
+          ],
+        },
+        {
+          'action_name': 'do_15',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_15.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_15.h',
+          ],
+        },
+        {
+          'action_name': 'do_16',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_16.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_16.h',
+          ],
+        },
+        {
+          'action_name': 'do_17',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_17.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_17.h',
+          ],
+        },
+        {
+          'action_name': 'do_18',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_18.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_18.h',
+          ],
+        },
+        {
+          'action_name': 'do_19',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_19.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_19.h',
+          ],
+        },
+        {
+          'action_name': 'do_20',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_20.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_20.h',
+          ],
+        },
+        {
+          'action_name': 'do_21',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_21.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_21.h',
+          ],
+        },
+        {
+          'action_name': 'do_22',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_22.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_22.h',
+          ],
+        },
+        {
+          'action_name': 'do_23',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_23.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_23.h',
+          ],
+        },
+        {
+          'action_name': 'do_24',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_24.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_24.h',
+          ],
+        },
+        {
+          'action_name': 'do_25',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_25.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_25.h',
+          ],
+        },
+        {
+          'action_name': 'do_26',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_26.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_26.h',
+          ],
+        },
+        {
+          'action_name': 'do_27',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_27.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_27.h',
+          ],
+        },
+        {
+          'action_name': 'do_28',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_28.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_28.h',
+          ],
+        },
+        {
+          'action_name': 'do_29',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_29.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_29.h',
+          ],
+        },
+        {
+          'action_name': 'do_30',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_30.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_30.h',
+          ],
+        },
+        {
+          'action_name': 'do_31',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_31.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_31.h',
+          ],
+        },
+        {
+          'action_name': 'do_32',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_32.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_32.h',
+          ],
+        },
+        {
+          'action_name': 'do_33',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_33.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_33.h',
+          ],
+        },
+        {
+          'action_name': 'do_34',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_34.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_34.h',
+          ],
+        },
+        {
+          'action_name': 'do_35',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_35.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_35.h',
+          ],
+        },
+        {
+          'action_name': 'do_36',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_36.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_36.h',
+          ],
+        },
+        {
+          'action_name': 'do_37',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_37.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_37.h',
+          ],
+        },
+        {
+          'action_name': 'do_38',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_38.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_38.h',
+          ],
+        },
+        {
+          'action_name': 'do_39',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_39.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_39.h',
+          ],
+        },
+        {
+          'action_name': 'do_40',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_40.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_40.h',
+          ],
+        },
+        {
+          'action_name': 'do_41',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_41.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_41.h',
+          ],
+        },
+        {
+          'action_name': 'do_42',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_42.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_42.h',
+          ],
+        },
+        {
+          'action_name': 'do_43',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_43.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_43.h',
+          ],
+        },
+        {
+          'action_name': 'do_44',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_44.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_44.h',
+          ],
+        },
+        {
+          'action_name': 'do_45',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_45.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_45.h',
+          ],
+        },
+        {
+          'action_name': 'do_46',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_46.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_46.h',
+          ],
+        },
+        {
+          'action_name': 'do_47',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_47.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_47.h',
+          ],
+        },
+        {
+          'action_name': 'do_48',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_48.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_48.h',
+          ],
+        },
+        {
+          'action_name': 'do_49',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_49.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_49.h',
+          ],
+        },
+        {
+          'action_name': 'do_50',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_50.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_50.h',
+          ],
+        },
+        {
+          'action_name': 'do_51',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_51.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_51.h',
+          ],
+        },
+        {
+          'action_name': 'do_52',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_52.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_52.h',
+          ],
+        },
+        {
+          'action_name': 'do_53',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_53.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_53.h',
+          ],
+        },
+        {
+          'action_name': 'do_54',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_54.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_54.h',
+          ],
+        },
+        {
+          'action_name': 'do_55',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_55.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_55.h',
+          ],
+        },
+        {
+          'action_name': 'do_56',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_56.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_56.h',
+          ],
+        },
+        {
+          'action_name': 'do_57',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_57.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_57.h',
+          ],
+        },
+        {
+          'action_name': 'do_58',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_58.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_58.h',
+          ],
+        },
+        {
+          'action_name': 'do_59',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_59.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_59.h',
+          ],
+        },
+        {
+          'action_name': 'do_60',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_60.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_60.h',
+          ],
+        },
+        {
+          'action_name': 'do_61',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_61.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_61.h',
+          ],
+        },
+        {
+          'action_name': 'do_62',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_62.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_62.h',
+          ],
+        },
+        {
+          'action_name': 'do_63',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_63.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_63.h',
+          ],
+        },
+        {
+          'action_name': 'do_64',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_64.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_64.h',
+          ],
+        },
+        {
+          'action_name': 'do_65',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_65.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_65.h',
+          ],
+        },
+        {
+          'action_name': 'do_66',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_66.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_66.h',
+          ],
+        },
+        {
+          'action_name': 'do_67',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_67.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_67.h',
+          ],
+        },
+        {
+          'action_name': 'do_68',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_68.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_68.h',
+          ],
+        },
+        {
+          'action_name': 'do_69',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_69.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_69.h',
+          ],
+        },
+        {
+          'action_name': 'do_70',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_70.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_70.h',
+          ],
+        },
+        {
+          'action_name': 'do_71',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_71.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_71.h',
+          ],
+        },
+        {
+          'action_name': 'do_72',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_72.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_72.h',
+          ],
+        },
+        {
+          'action_name': 'do_73',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_73.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_73.h',
+          ],
+        },
+        {
+          'action_name': 'do_74',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_74.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_74.h',
+          ],
+        },
+        {
+          'action_name': 'do_75',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_75.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_75.h',
+          ],
+        },
+        {
+          'action_name': 'do_76',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_76.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_76.h',
+          ],
+        },
+        {
+          'action_name': 'do_77',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_77.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_77.h',
+          ],
+        },
+        {
+          'action_name': 'do_78',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_78.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_78.h',
+          ],
+        },
+        {
+          'action_name': 'do_79',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_79.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_79.h',
+          ],
+        },
+        {
+          'action_name': 'do_80',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_80.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_80.h',
+          ],
+        },
+        {
+          'action_name': 'do_81',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_81.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_81.h',
+          ],
+        },
+        {
+          'action_name': 'do_82',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_82.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_82.h',
+          ],
+        },
+        {
+          'action_name': 'do_83',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_83.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_83.h',
+          ],
+        },
+        {
+          'action_name': 'do_84',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_84.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_84.h',
+          ],
+        },
+        {
+          'action_name': 'do_85',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_85.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_85.h',
+          ],
+        },
+        {
+          'action_name': 'do_86',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_86.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_86.h',
+          ],
+        },
+        {
+          'action_name': 'do_87',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_87.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_87.h',
+          ],
+        },
+        {
+          'action_name': 'do_88',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_88.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_88.h',
+          ],
+        },
+        {
+          'action_name': 'do_89',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_89.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_89.h',
+          ],
+        },
+        {
+          'action_name': 'do_90',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_90.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_90.h',
+          ],
+        },
+        {
+          'action_name': 'do_91',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_91.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_91.h',
+          ],
+        },
+        {
+          'action_name': 'do_92',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_92.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_92.h',
+          ],
+        },
+        {
+          'action_name': 'do_93',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_93.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_93.h',
+          ],
+        },
+        {
+          'action_name': 'do_94',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_94.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_94.h',
+          ],
+        },
+        {
+          'action_name': 'do_95',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_95.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_95.h',
+          ],
+        },
+        {
+          'action_name': 'do_96',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_96.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_96.h',
+          ],
+        },
+        {
+          'action_name': 'do_97',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_97.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_97.h',
+          ],
+        },
+        {
+          'action_name': 'do_98',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_98.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_98.h',
+          ],
+        },
+        {
+          'action_name': 'do_99',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_99.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_99.h',
+          ],
+        },
+        {
+          'action_name': 'do_100',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_100.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_100.h',
+          ],
+        },
+        {
+          'action_name': 'do_101',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_101.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_101.h',
+          ],
+        },
+        {
+          'action_name': 'do_102',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_102.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_102.h',
+          ],
+        },
+        {
+          'action_name': 'do_103',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_103.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_103.h',
+          ],
+        },
+        {
+          'action_name': 'do_104',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_104.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_104.h',
+          ],
+        },
+        {
+          'action_name': 'do_105',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_105.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_105.h',
+          ],
+        },
+        {
+          'action_name': 'do_106',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_106.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_106.h',
+          ],
+        },
+        {
+          'action_name': 'do_107',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_107.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_107.h',
+          ],
+        },
+        {
+          'action_name': 'do_108',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_108.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_108.h',
+          ],
+        },
+        {
+          'action_name': 'do_109',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_109.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_109.h',
+          ],
+        },
+        {
+          'action_name': 'do_110',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_110.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_110.h',
+          ],
+        },
+        {
+          'action_name': 'do_111',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_111.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_111.h',
+          ],
+        },
+        {
+          'action_name': 'do_112',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_112.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_112.h',
+          ],
+        },
+        {
+          'action_name': 'do_113',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_113.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_113.h',
+          ],
+        },
+        {
+          'action_name': 'do_114',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_114.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_114.h',
+          ],
+        },
+        {
+          'action_name': 'do_115',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_115.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_115.h',
+          ],
+        },
+        {
+          'action_name': 'do_116',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_116.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_116.h',
+          ],
+        },
+        {
+          'action_name': 'do_117',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_117.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_117.h',
+          ],
+        },
+        {
+          'action_name': 'do_118',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_118.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_118.h',
+          ],
+        },
+        {
+          'action_name': 'do_119',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_119.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_119.h',
+          ],
+        },
+        {
+          'action_name': 'do_120',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_120.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_120.h',
+          ],
+        },
+        {
+          'action_name': 'do_121',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_121.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_121.h',
+          ],
+        },
+        {
+          'action_name': 'do_122',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_122.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_122.h',
+          ],
+        },
+        {
+          'action_name': 'do_123',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_123.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_123.h',
+          ],
+        },
+        {
+          'action_name': 'do_124',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_124.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_124.h',
+          ],
+        },
+        {
+          'action_name': 'do_125',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_125.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_125.h',
+          ],
+        },
+        {
+          'action_name': 'do_126',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_126.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_126.h',
+          ],
+        },
+        {
+          'action_name': 'do_127',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_127.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_127.h',
+          ],
+        },
+        {
+          'action_name': 'do_128',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_128.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_128.h',
+          ],
+        },
+        {
+          'action_name': 'do_129',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_129.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_129.h',
+          ],
+        },
+        {
+          'action_name': 'do_130',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_130.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_130.h',
+          ],
+        },
+        {
+          'action_name': 'do_131',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_131.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_131.h',
+          ],
+        },
+        {
+          'action_name': 'do_132',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_132.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_132.h',
+          ],
+        },
+        {
+          'action_name': 'do_133',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_133.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_133.h',
+          ],
+        },
+        {
+          'action_name': 'do_134',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_134.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_134.h',
+          ],
+        },
+        {
+          'action_name': 'do_135',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_135.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_135.h',
+          ],
+        },
+        {
+          'action_name': 'do_136',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_136.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_136.h',
+          ],
+        },
+        {
+          'action_name': 'do_137',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_137.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_137.h',
+          ],
+        },
+        {
+          'action_name': 'do_138',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_138.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_138.h',
+          ],
+        },
+        {
+          'action_name': 'do_139',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_139.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_139.h',
+          ],
+        },
+        {
+          'action_name': 'do_140',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_140.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_140.h',
+          ],
+        },
+        {
+          'action_name': 'do_141',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_141.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_141.h',
+          ],
+        },
+        {
+          'action_name': 'do_142',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_142.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_142.h',
+          ],
+        },
+        {
+          'action_name': 'do_143',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_143.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_143.h',
+          ],
+        },
+        {
+          'action_name': 'do_144',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_144.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_144.h',
+          ],
+        },
+        {
+          'action_name': 'do_145',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_145.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_145.h',
+          ],
+        },
+        {
+          'action_name': 'do_146',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_146.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_146.h',
+          ],
+        },
+        {
+          'action_name': 'do_147',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_147.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_147.h',
+          ],
+        },
+        {
+          'action_name': 'do_148',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_148.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_148.h',
+          ],
+        },
+        {
+          'action_name': 'do_149',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_149.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_149.h',
+          ],
+        },
+        {
+          'action_name': 'do_150',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_150.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_150.h',
+          ],
+        },
+        {
+          'action_name': 'do_151',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_151.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_151.h',
+          ],
+        },
+        {
+          'action_name': 'do_152',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_152.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_152.h',
+          ],
+        },
+        {
+          'action_name': 'do_153',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_153.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_153.h',
+          ],
+        },
+        {
+          'action_name': 'do_154',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_154.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_154.h',
+          ],
+        },
+        {
+          'action_name': 'do_155',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_155.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_155.h',
+          ],
+        },
+        {
+          'action_name': 'do_156',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_156.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_156.h',
+          ],
+        },
+        {
+          'action_name': 'do_157',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_157.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_157.h',
+          ],
+        },
+        {
+          'action_name': 'do_158',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_158.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_158.h',
+          ],
+        },
+        {
+          'action_name': 'do_159',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_159.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_159.h',
+          ],
+        },
+        {
+          'action_name': 'do_160',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_160.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_160.h',
+          ],
+        },
+        {
+          'action_name': 'do_161',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_161.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_161.h',
+          ],
+        },
+        {
+          'action_name': 'do_162',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_162.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_162.h',
+          ],
+        },
+        {
+          'action_name': 'do_163',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_163.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_163.h',
+          ],
+        },
+        {
+          'action_name': 'do_164',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_164.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_164.h',
+          ],
+        },
+        {
+          'action_name': 'do_165',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_165.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_165.h',
+          ],
+        },
+        {
+          'action_name': 'do_166',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_166.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_166.h',
+          ],
+        },
+        {
+          'action_name': 'do_167',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_167.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_167.h',
+          ],
+        },
+        {
+          'action_name': 'do_168',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_168.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_168.h',
+          ],
+        },
+        {
+          'action_name': 'do_169',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_169.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_169.h',
+          ],
+        },
+        {
+          'action_name': 'do_170',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_170.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_170.h',
+          ],
+        },
+        {
+          'action_name': 'do_171',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_171.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_171.h',
+          ],
+        },
+        {
+          'action_name': 'do_172',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_172.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_172.h',
+          ],
+        },
+        {
+          'action_name': 'do_173',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_173.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_173.h',
+          ],
+        },
+        {
+          'action_name': 'do_174',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_174.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_174.h',
+          ],
+        },
+        {
+          'action_name': 'do_175',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_175.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_175.h',
+          ],
+        },
+        {
+          'action_name': 'do_176',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_176.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_176.h',
+          ],
+        },
+        {
+          'action_name': 'do_177',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_177.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_177.h',
+          ],
+        },
+        {
+          'action_name': 'do_178',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_178.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_178.h',
+          ],
+        },
+        {
+          'action_name': 'do_179',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_179.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_179.h',
+          ],
+        },
+        {
+          'action_name': 'do_180',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_180.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_180.h',
+          ],
+        },
+        {
+          'action_name': 'do_181',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_181.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_181.h',
+          ],
+        },
+        {
+          'action_name': 'do_182',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_182.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_182.h',
+          ],
+        },
+        {
+          'action_name': 'do_183',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_183.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_183.h',
+          ],
+        },
+        {
+          'action_name': 'do_184',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_184.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_184.h',
+          ],
+        },
+        {
+          'action_name': 'do_185',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_185.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_185.h',
+          ],
+        },
+        {
+          'action_name': 'do_186',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_186.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_186.h',
+          ],
+        },
+        {
+          'action_name': 'do_187',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_187.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_187.h',
+          ],
+        },
+        {
+          'action_name': 'do_188',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_188.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_188.h',
+          ],
+        },
+        {
+          'action_name': 'do_189',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_189.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_189.h',
+          ],
+        },
+        {
+          'action_name': 'do_190',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_190.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_190.h',
+          ],
+        },
+        {
+          'action_name': 'do_191',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_191.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_191.h',
+          ],
+        },
+        {
+          'action_name': 'do_192',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_192.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_192.h',
+          ],
+        },
+        {
+          'action_name': 'do_193',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_193.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_193.h',
+          ],
+        },
+        {
+          'action_name': 'do_194',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_194.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_194.h',
+          ],
+        },
+        {
+          'action_name': 'do_195',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_195.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_195.h',
+          ],
+        },
+        {
+          'action_name': 'do_196',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_196.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_196.h',
+          ],
+        },
+        {
+          'action_name': 'do_197',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_197.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_197.h',
+          ],
+        },
+        {
+          'action_name': 'do_198',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_198.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_198.h',
+          ],
+        },
+        {
+          'action_name': 'do_199',
+          'inputs': [],
+          'outputs': ['<(PRODUCT_DIR)/generated_199.h'],
+          'action': [
+            'touch',
+            '<(PRODUCT_DIR)/generated_199.h',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/module/gyptest-default.py b/gyp/test/module/gyptest-default.py
new file mode 100755 (executable)
index 0000000..7be5a72
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple build of a "Hello, world!" program with loadable modules. The
+default for all platforms should be to output the loadable modules to the same
+path as the executable.
+"""
+
+import TestGyp
+
+# Android doesn't support loadable modules
+test = TestGyp.TestGyp(formats=['!android'])
+
+test.run_gyp('module.gyp', chdir='src')
+
+test.build('module.gyp', test.ALL, chdir='src')
+
+expect = """\
+Hello from program.c
+Hello from lib1.c
+Hello from lib2.c
+"""
+test.run_built_executable('program', chdir='src', stdout=expect)
+
+test.pass_test()
diff --git a/gyp/test/module/src/lib1.c b/gyp/test/module/src/lib1.c
new file mode 100644 (file)
index 0000000..8de0e94
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void module_main(void)
+{
+  fprintf(stdout, "Hello from lib1.c\n");
+  fflush(stdout);
+}
diff --git a/gyp/test/module/src/lib2.c b/gyp/test/module/src/lib2.c
new file mode 100644 (file)
index 0000000..266396d
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void module_main(void)
+{
+  fprintf(stdout, "Hello from lib2.c\n");
+  fflush(stdout);
+}
diff --git a/gyp/test/module/src/module.gyp b/gyp/test/module/src/module.gyp
new file mode 100644 (file)
index 0000000..2bc398b
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'conditions': [
+      ['OS=="win"', {
+        'defines': ['PLATFORM_WIN'],
+      }],
+      ['OS=="mac" or OS=="ios"', {
+        'defines': ['PLATFORM_MAC'],
+      }],
+      ['OS=="linux"', {
+        'defines': ['PLATFORM_LINUX'],
+        # Support 64-bit shared libs (also works fine for 32-bit).
+        'cflags': ['-fPIC'],
+        'libraries': ['-ldl'],
+      }],
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'dependencies': [
+        'lib1',
+        'lib2',
+      ],
+      'sources': [
+        'program.c',
+      ],
+    },
+    {
+      'target_name': 'lib1',
+      'type': 'loadable_module',
+      'product_name': 'lib1',
+      'product_prefix': '',
+      'sources': [
+        'lib1.c',
+      ],
+    },
+    {
+      'target_name': 'lib2',
+      'product_name': 'lib2',
+      'product_prefix': '',
+      'type': 'loadable_module',
+      'sources': [
+        'lib2.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/module/src/program.c b/gyp/test/module/src/program.c
new file mode 100644 (file)
index 0000000..7cc3dd3
--- /dev/null
@@ -0,0 +1,111 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(PLATFORM_WIN)
+#include <windows.h>
+#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+#include <dlfcn.h>
+#include <libgen.h>
+#include <string.h>
+#include <sys/param.h>
+#define MAX_PATH PATH_MAX
+#endif
+
+#if defined(PLATFORM_WIN)
+#define MODULE_SUFFIX ".dll"
+#elif defined(PLATFORM_MAC)
+#define MODULE_SUFFIX ".so"
+#elif defined(PLATFORM_LINUX)
+#define MODULE_SUFFIX ".so"
+#endif
+
+typedef void (*module_symbol)(void);
+char bin_path[MAX_PATH + 1];
+
+
+void CallModule(const char* module) {
+  char module_path[MAX_PATH + 1];
+  const char* module_function = "module_main";
+  module_symbol funcptr;
+#if defined(PLATFORM_WIN)
+  HMODULE dl;
+  char drive[_MAX_DRIVE];
+  char dir[_MAX_DIR];
+
+  if (_splitpath_s(bin_path, drive, _MAX_DRIVE, dir, _MAX_DIR,
+                    NULL, 0, NULL, 0)) {
+    fprintf(stderr, "Failed to split executable path.\n");
+    return;
+  }
+  if (_makepath_s(module_path, MAX_PATH, drive, dir, module, MODULE_SUFFIX)) {
+    fprintf(stderr, "Failed to calculate module path.\n");
+    return;
+  }
+
+  dl = LoadLibrary(module_path);
+  if (!dl) {
+    fprintf(stderr, "Failed to open module: %s\n", module_path);
+    return;
+  }
+
+  funcptr = (module_symbol) GetProcAddress(dl, module_function);
+  if (!funcptr) {
+    fprintf(stderr, "Failed to find symbol: %s\n", module_function);
+    return;
+  }
+  funcptr();
+
+  FreeLibrary(dl);
+#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+  void* dl;
+  char* path_copy = strdup(bin_path);
+  char* bin_dir = dirname(path_copy);
+  int path_size = snprintf(module_path, MAX_PATH, "%s/%s%s", bin_dir, module,
+                           MODULE_SUFFIX);
+  free(path_copy);
+  if (path_size < 0 || path_size > MAX_PATH) {
+    fprintf(stderr, "Failed to calculate module path.\n");
+    return;
+  }
+  module_path[path_size] = 0;
+
+  dl = dlopen(module_path, RTLD_LAZY);
+  if (!dl) {
+    fprintf(stderr, "Failed to open module: %s\n", module_path);
+    return;
+  }
+
+  funcptr = dlsym(dl, module_function);
+  if (!funcptr) {
+    fprintf(stderr, "Failed to find symbol: %s\n", module_function);
+    return;
+  }
+  funcptr();
+
+  dlclose(dl);
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+  fprintf(stdout, "Hello from program.c\n");
+  fflush(stdout);
+
+#if defined(PLATFORM_WIN)
+  if (!GetModuleFileName(NULL, bin_path, MAX_PATH)) {
+    fprintf(stderr, "Failed to determine executable path.\n");
+    return 1;
+  }
+#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+  // Using argv[0] should be OK here since we control how the tests run, and
+  // can avoid exec and such issues that make it unreliable.
+  if (!realpath(argv[0], bin_path)) {
+    fprintf(stderr, "Failed to determine executable path (%s).\n", argv[0]);
+    return 1;
+  }
+#endif
+
+  CallModule("lib1");
+  CallModule("lib2");
+  return 0;
+}
diff --git a/gyp/test/msvs/buildevents/buildevents.gyp b/gyp/test/msvs/buildevents/buildevents.gyp
new file mode 100644 (file)
index 0000000..e0304dd
--- /dev/null
@@ -0,0 +1,14 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'main',
+      'type': 'executable',
+      'sources': [ 'main.cc', ],
+      'msvs_prebuild': r'echo starting',
+      'msvs_postbuild': r'echo finished',
+    },
+  ],
+}
diff --git a/gyp/test/msvs/buildevents/gyptest-msbuild-supports-prepostbuild.py b/gyp/test/msvs/buildevents/gyptest-msbuild-supports-prepostbuild.py
new file mode 100755 (executable)
index 0000000..208f434
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that msvs_prebuild and msvs_postbuild can be specified in both
+VS 2008 and 2010.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['msvs'], workdir='workarea_all')
+
+test.run_gyp('buildevents.gyp', '-G', 'msvs_version=2008')
+test.must_contain('main.vcproj', 'Name="VCPreBuildEventTool"')
+test.must_contain('main.vcproj', 'Name="VCPostBuildEventTool"')
+
+test.run_gyp('buildevents.gyp', '-G', 'msvs_version=2010')
+test.must_contain('main.vcxproj', '<PreBuildEvent>')
+test.must_contain('main.vcxproj', '<PostBuildEvent>')
+
+test.pass_test()
diff --git a/gyp/test/msvs/buildevents/gyptest-ninja-warnings.py b/gyp/test/msvs/buildevents/gyptest-ninja-warnings.py
new file mode 100755 (executable)
index 0000000..732a200
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that ninja errors out when encountering msvs_prebuild/msvs_postbuild.
+"""
+
+import sys
+import TestCmd
+import TestGyp
+
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  test.run_gyp('buildevents.gyp',
+      status=1,
+      stderr='.*msvs_prebuild not supported \(target main\).*',
+      match=TestCmd.match_re_dotall)
+
+  test.run_gyp('buildevents.gyp',
+      status=1,
+      stderr='.*msvs_postbuild not supported \(target main\).*',
+      match=TestCmd.match_re_dotall)
+
+  test.pass_test()
diff --git a/gyp/test/msvs/buildevents/main.cc b/gyp/test/msvs/buildevents/main.cc
new file mode 100644 (file)
index 0000000..03c0285
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {}
diff --git a/gyp/test/msvs/config_attrs/gyptest-config_attrs.py b/gyp/test/msvs/config_attrs/gyptest-config_attrs.py
new file mode 100644 (file)
index 0000000..15f4b4e
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that msvs_configuration_attributes and
+msbuild_configuration_attributes are applied by using
+them to set the OutputDirectory.
+"""
+
+import TestGyp
+import os
+
+test = TestGyp.TestGyp(workdir='workarea_all',formats=['msvs'])
+
+vc_version = 'VC90'
+
+if os.getenv('GYP_MSVS_VERSION'):
+  vc_version = ['VC90','VC100'][int(os.getenv('GYP_MSVS_VERSION')) >= 2010]
+
+expected_exe_file = os.path.join(test.workdir, vc_version, 'hello.exe')
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp')
+
+test.must_exist(expected_exe_file)
+
+test.pass_test()
diff --git a/gyp/test/msvs/config_attrs/hello.c b/gyp/test/msvs/config_attrs/hello.c
new file mode 100644 (file)
index 0000000..faadc75
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello, world!\n");
+  return 0;
+}
diff --git a/gyp/test/msvs/config_attrs/hello.gyp b/gyp/test/msvs/config_attrs/hello.gyp
new file mode 100644 (file)
index 0000000..810a80e
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+      'msvs_configuration_attributes': {
+        'OutputDirectory':'$(SolutionDir)VC90/'
+      },
+      'msbuild_configuration_attributes': {
+        'OutputDirectory':'$(SolutionDir)VC100/',
+      },
+    },
+  ],
+}
diff --git a/gyp/test/msvs/express/base/base.gyp b/gyp/test/msvs/express/base/base.gyp
new file mode 100644 (file)
index 0000000..b7c9fc6
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'a',
+      'type': 'static_library',
+      'sources': [
+        'a.c',
+      ],
+    },
+    {
+      'target_name': 'b',
+      'type': 'static_library',
+      'sources': [
+        'b.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/msvs/express/express.gyp b/gyp/test/msvs/express/express.gyp
new file mode 100644 (file)
index 0000000..917abe2
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'express',
+      'type': 'executable',
+      'dependencies': [
+        'base/base.gyp:a',
+        'base/base.gyp:b',
+      ],
+      'sources': [
+        'main.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/msvs/express/gyptest-express.py b/gyp/test/msvs/express/gyptest-express.py
new file mode 100755 (executable)
index 0000000..54c06f6
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that flat solutions get generated for Express versions of
+Visual Studio.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['msvs'])
+
+test.run_gyp('express.gyp', '-G', 'msvs_version=2005')
+test.must_contain('express.sln', '(base)')
+
+test.run_gyp('express.gyp', '-G', 'msvs_version=2008')
+test.must_contain('express.sln', '(base)')
+
+test.run_gyp('express.gyp', '-G', 'msvs_version=2005e')
+test.must_not_contain('express.sln', '(base)')
+
+test.run_gyp('express.gyp', '-G', 'msvs_version=2008e')
+test.must_not_contain('express.sln', '(base)')
+
+
+test.pass_test()
diff --git a/gyp/test/msvs/external_builder/external.gyp b/gyp/test/msvs/external_builder/external.gyp
new file mode 100644 (file)
index 0000000..abe5b58
--- /dev/null
@@ -0,0 +1,68 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    # the test driver switches this flag when testing external builder
+    'use_external_builder%': 0,
+  },
+  'targets': [
+    {
+      'target_name': 'external',
+      'type': 'executable',
+      'sources': [
+        'hello.cpp',
+        'hello.z',
+      ],
+      'rules': [
+        {
+          'rule_name': 'test_rule',
+          'extension': 'z',
+          'outputs': [
+            'msbuild_rule.out',
+          ],
+          'action': [
+            'python',
+            'msbuild_rule.py',
+            '<(RULE_INPUT_PATH)',
+            'a', 'b', 'c',
+          ],
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+      'actions': [
+        {
+          'action_name': 'test action',
+          'inputs': [
+            'msbuild_action.py',
+          ],
+          'outputs': [
+            'msbuild_action.out',
+          ],
+          'action': [
+            'python',
+            '<@(_inputs)',
+            'x', 'y', 'z',
+          ],
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+      'conditions': [
+        ['use_external_builder==1', {
+          'msvs_external_builder': 'test',
+          'msvs_external_builder_build_cmd': [
+            'python',
+            'external_builder.py',
+            'build', '1', '2', '3',
+          ],
+          'msvs_external_builder_clean_cmd': [
+            'python',
+            'external_builder.py',
+            'clean', '4', '5',
+          ],
+        }],
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/msvs/external_builder/external_builder.py b/gyp/test/msvs/external_builder/external_builder.py
new file mode 100644 (file)
index 0000000..ddfc1e5
--- /dev/null
@@ -0,0 +1,9 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+with open('external_builder.out', 'w') as f:
+  f.write(' '.join(sys.argv))
+
diff --git a/gyp/test/msvs/external_builder/gyptest-all.py b/gyp/test/msvs/external_builder/gyptest-all.py
new file mode 100644 (file)
index 0000000..72faa7a
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that msvs_external_builder being set will invoke the provided
+msvs_external_builder_build_cmd and msvs_external_builder_clean_cmd, and will
+not invoke MSBuild actions and rules.
+"""
+
+import os
+import sys
+import TestGyp
+
+if int(os.environ.get('GYP_MSVS_VERSION', 0)) < 2010:
+  sys.exit(0)
+
+test = TestGyp.TestGyp(formats=['msvs'], workdir='workarea_all')
+
+# without the flag set
+test.run_gyp('external.gyp')
+test.build('external.gyp', target='external')
+test.must_not_exist('external_builder.out')
+test.must_exist('msbuild_rule.out')
+test.must_exist('msbuild_action.out')
+test.must_match('msbuild_rule.out', 'msbuild_rule.py hello.z a b c')
+test.must_match('msbuild_action.out', 'msbuild_action.py x y z')
+os.remove('msbuild_rule.out')
+os.remove('msbuild_action.out')
+
+# with the flag set, using Build
+try:
+  os.environ['GYP_DEFINES'] = 'use_external_builder=1'
+  test.run_gyp('external.gyp')
+  test.build('external.gyp', target='external')
+finally:
+  del os.environ['GYP_DEFINES']
+test.must_not_exist('msbuild_rule.out')
+test.must_not_exist('msbuild_action.out')
+test.must_exist('external_builder.out')
+test.must_match('external_builder.out', 'external_builder.py build 1 2 3')
+os.remove('external_builder.out')
+
+# with the flag set, using Clean
+try:
+  os.environ['GYP_DEFINES'] = 'use_external_builder=1'
+  test.run_gyp('external.gyp')
+  test.build('external.gyp', target='external', clean=True)
+finally:
+  del os.environ['GYP_DEFINES']
+test.must_not_exist('msbuild_rule.out')
+test.must_not_exist('msbuild_action.out')
+test.must_exist('external_builder.out')
+test.must_match('external_builder.out', 'external_builder.py clean 4 5')
+os.remove('external_builder.out')
+
+test.pass_test()
diff --git a/gyp/test/msvs/external_builder/hello.cpp b/gyp/test/msvs/external_builder/hello.cpp
new file mode 100644 (file)
index 0000000..bc0c026
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+int main(void) {
+  printf("Hello, world!\n");
+  return 0;
+}
diff --git a/gyp/test/msvs/external_builder/hello.z b/gyp/test/msvs/external_builder/hello.z
new file mode 100644 (file)
index 0000000..aa47882
--- /dev/null
@@ -0,0 +1,6 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+This file will be passed to the test rule.
+
diff --git a/gyp/test/msvs/external_builder/msbuild_action.py b/gyp/test/msvs/external_builder/msbuild_action.py
new file mode 100644 (file)
index 0000000..632d786
--- /dev/null
@@ -0,0 +1,9 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+with open('msbuild_action.out', 'w') as f:
+  f.write(' '.join(sys.argv))
+
diff --git a/gyp/test/msvs/external_builder/msbuild_rule.py b/gyp/test/msvs/external_builder/msbuild_rule.py
new file mode 100644 (file)
index 0000000..0d6e315
--- /dev/null
@@ -0,0 +1,11 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys, os.path
+
+sys.argv[1] = os.path.basename(sys.argv[1])
+
+with open('msbuild_rule.out', 'w') as f:
+  f.write(' '.join(sys.argv))
+
diff --git a/gyp/test/msvs/filters/filters.gyp b/gyp/test/msvs/filters/filters.gyp
new file mode 100644 (file)
index 0000000..a4106dc
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'no_source_files',
+      'type': 'none',
+      'sources': [ ],
+    },
+    {
+      'target_name': 'one_source_file',
+      'type': 'executable',
+      'sources': [
+        '../folder/a.c',
+      ],
+    },
+    {
+      'target_name': 'two_source_files',
+      'type': 'executable',
+      'sources': [
+        '../folder/a.c',
+        '../folder/b.c',
+      ],
+    },
+    {
+      'target_name': 'three_files_in_two_folders',
+      'type': 'executable',
+      'sources': [
+        '../folder1/a.c',
+        '../folder1/b.c',
+        '../folder2/c.c',
+      ],
+    },
+    {
+      'target_name': 'nested_folders',
+      'type': 'executable',
+      'sources': [
+        '../folder1/nested/a.c',
+        '../folder2/d.c',
+        '../folder1/nested/b.c',
+        '../folder1/other/c.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/msvs/filters/gyptest-filters-2008.py b/gyp/test/msvs/filters/gyptest-filters-2008.py
new file mode 100644 (file)
index 0000000..41ca085
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that extra filters are pruned correctly for Visual Studio 2008.
+"""
+
+import re
+import TestGyp
+
+
+def strip_ws(str):
+    return re.sub('^ +', '', str, flags=re.M).replace('\n', '')
+
+
+test = TestGyp.TestGyp(formats=['msvs'])
+
+test.run_gyp('filters.gyp', '-G', 'standalone', '-G', 'msvs_version=2008')
+
+test.must_contain('no_source_files.vcproj', '<Files/>')
+
+test.must_contain('one_source_file.vcproj', strip_ws('''\
+<Files>
+  <File RelativePath="..\\folder\\a.c"/>
+</Files>
+'''))
+
+test.must_contain('two_source_files.vcproj', strip_ws('''\
+<Files>
+  <File RelativePath="..\\folder\\a.c"/>
+  <File RelativePath="..\\folder\\b.c"/>
+</Files>
+'''))
+
+test.must_contain('three_files_in_two_folders.vcproj', strip_ws('''\
+<Files>
+  <Filter Name="folder1">
+    <File RelativePath="..\\folder1\\a.c"/>
+    <File RelativePath="..\\folder1\\b.c"/>
+  </Filter>
+  <Filter Name="folder2">
+    <File RelativePath="..\\folder2\\c.c"/>
+  </Filter>
+</Files>
+'''))
+
+test.must_contain('nested_folders.vcproj', strip_ws('''\
+<Files>
+  <Filter Name="folder1">
+    <Filter Name="nested">
+      <File RelativePath="..\\folder1\\nested\\a.c"/>
+      <File RelativePath="..\\folder1\\nested\\b.c"/>
+    </Filter>
+    <Filter Name="other">
+      <File RelativePath="..\\folder1\\other\\c.c"/>
+    </Filter>
+  </Filter>
+  <Filter Name="folder2">
+    <File RelativePath="..\\folder2\\d.c"/>
+  </Filter>
+</Files>
+'''))
+
+
+test.pass_test()
diff --git a/gyp/test/msvs/filters/gyptest-filters-2010.py b/gyp/test/msvs/filters/gyptest-filters-2010.py
new file mode 100644 (file)
index 0000000..91fbc74
--- /dev/null
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that extra filters are pruned correctly for Visual Studio 2010
+and later.
+"""
+
+import TestGyp
+
+
+test = TestGyp.TestGyp(formats=['msvs'])
+
+test.run_gyp('filters.gyp', '-G', 'standalone', '-G', 'msvs_version=2010')
+
+test.must_not_exist('no_source_files.vcxproj.filters')
+
+test.must_not_exist('one_source_file.vcxproj.filters')
+
+test.must_not_exist('two_source_files.vcxproj.filters')
+
+test.must_contain('three_files_in_two_folders.vcxproj.filters', '''\
+  <ItemGroup>
+    <ClCompile Include="..\\folder1\\a.c">
+      <Filter>folder1</Filter>
+    </ClCompile>
+    <ClCompile Include="..\\folder1\\b.c">
+      <Filter>folder1</Filter>
+    </ClCompile>
+    <ClCompile Include="..\\folder2\\c.c">
+      <Filter>folder2</Filter>
+    </ClCompile>
+  </ItemGroup>
+'''.replace('\n', '\r\n'))
+
+test.must_contain('nested_folders.vcxproj.filters', '''\
+  <ItemGroup>
+    <ClCompile Include="..\\folder1\\nested\\a.c">
+      <Filter>folder1\\nested</Filter>
+    </ClCompile>
+    <ClCompile Include="..\\folder2\\d.c">
+      <Filter>folder2</Filter>
+    </ClCompile>
+    <ClCompile Include="..\\folder1\\nested\\b.c">
+      <Filter>folder1\\nested</Filter>
+    </ClCompile>
+    <ClCompile Include="..\\folder1\\other\c.c">
+      <Filter>folder1\\other</Filter>
+    </ClCompile>
+  </ItemGroup>
+'''.replace('\n', '\r\n'))
+
+
+test.pass_test()
diff --git a/gyp/test/msvs/list_excluded/gyptest-all.py b/gyp/test/msvs/list_excluded/gyptest-all.py
new file mode 100644 (file)
index 0000000..5a370f6
--- /dev/null
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that msvs_list_excluded_files=0 doesn't list files that would
+normally be in _excluded_files, and that if that flag is not set, then they
+are still listed.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['msvs'], workdir='workarea_all')
+
+
+# with the flag set to 0
+try:
+  os.environ['GYP_GENERATOR_FLAGS'] = 'msvs_list_excluded_files=0'
+  test.run_gyp('hello_exclude.gyp')
+finally:
+  del os.environ['GYP_GENERATOR_FLAGS']
+if test.uses_msbuild:
+  test.must_not_contain('hello.vcxproj', 'hello_mac')
+else:
+  test.must_not_contain('hello.vcproj', 'hello_mac')
+
+
+# with the flag not set
+test.run_gyp('hello_exclude.gyp')
+if test.uses_msbuild:
+  test.must_contain('hello.vcxproj', 'hello_mac')
+else:
+  test.must_contain('hello.vcproj', 'hello_mac')
+
+
+# with the flag explicitly set to 1
+try:
+  os.environ['GYP_GENERATOR_FLAGS'] = 'msvs_list_excluded_files=1'
+  test.run_gyp('hello_exclude.gyp')
+finally:
+  del os.environ['GYP_GENERATOR_FLAGS']
+if test.uses_msbuild:
+  test.must_contain('hello.vcxproj', 'hello_mac')
+else:
+  test.must_contain('hello.vcproj', 'hello_mac')
+
+
+test.pass_test()
diff --git a/gyp/test/msvs/list_excluded/hello.cpp b/gyp/test/msvs/list_excluded/hello.cpp
new file mode 100644 (file)
index 0000000..bc0c026
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+int main(void) {
+  printf("Hello, world!\n");
+  return 0;
+}
diff --git a/gyp/test/msvs/list_excluded/hello_exclude.gyp b/gyp/test/msvs/list_excluded/hello_exclude.gyp
new file mode 100644 (file)
index 0000000..aa160f2
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello.cpp',
+        'hello_mac.cpp',
+      ],
+      'conditions': [
+        ['OS!="mac"', {'sources!': ['hello_mac.cpp']}],
+      ]
+    },
+  ],
+}
diff --git a/gyp/test/msvs/list_excluded/hello_mac.cpp b/gyp/test/msvs/list_excluded/hello_mac.cpp
new file mode 100644 (file)
index 0000000..b9f6242
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+int hello2() {
+  printf("Hello, two!\n");
+  return 0;
+}
diff --git a/gyp/test/msvs/missing_sources/gyptest-missing.py b/gyp/test/msvs/missing_sources/gyptest-missing.py
new file mode 100644 (file)
index 0000000..62a99ef
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that missing 'sources' files are treated as fatal errors when the
+the generator flag 'msvs_error_on_missing_sources' is set.
+"""
+
+import TestGyp
+import os
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'], workdir='workarea_all')
+
+  # With the flag not set
+  test.run_gyp('hello_missing.gyp')
+
+  # With the flag explicitly set to 0
+  try:
+    os.environ['GYP_GENERATOR_FLAGS'] = 'msvs_error_on_missing_sources=0'
+    test.run_gyp('hello_missing.gyp')
+  finally:
+    del os.environ['GYP_GENERATOR_FLAGS']
+
+  # With the flag explicitly set to 1
+  try:
+    os.environ['GYP_GENERATOR_FLAGS'] = 'msvs_error_on_missing_sources=1'
+    # Test to make sure GYP raises an exception (exit status 1). Since this will
+    # also print a backtrace, ensure that TestGyp is not checking that stderr is
+    # empty by specifying None, which means do not perform any checking.
+    # Instead, stderr is checked below to ensure it contains the expected
+    # output.
+    test.run_gyp('hello_missing.gyp', status=1, stderr=None)
+  finally:
+    del os.environ['GYP_GENERATOR_FLAGS']
+  test.must_contain_any_line(test.stderr(),
+                            ["Missing input files:"])
+
+  test.pass_test()
diff --git a/gyp/test/msvs/missing_sources/hello_missing.gyp b/gyp/test/msvs/missing_sources/hello_missing.gyp
new file mode 100644 (file)
index 0000000..c08926b
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello_missing.cpp',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/msvs/multiple_actions_error_handling/action_fail.py b/gyp/test/msvs/multiple_actions_error_handling/action_fail.py
new file mode 100644 (file)
index 0000000..286fc4e
--- /dev/null
@@ -0,0 +1,7 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+sys.exit(1)
diff --git a/gyp/test/msvs/multiple_actions_error_handling/action_succeed.py b/gyp/test/msvs/multiple_actions_error_handling/action_succeed.py
new file mode 100644 (file)
index 0000000..3554373
--- /dev/null
@@ -0,0 +1,7 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+sys.exit(0)
diff --git a/gyp/test/msvs/multiple_actions_error_handling/actions.gyp b/gyp/test/msvs/multiple_actions_error_handling/actions.gyp
new file mode 100644 (file)
index 0000000..ab99e92
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'actions-test',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'first action (fails)',
+          'inputs': [
+            'action_fail.py',
+          ],
+          'outputs': [
+            'ALWAYS_OUT_OF_DATE',
+          ],
+          'action': [
+            'python', '<@(_inputs)'
+          ],
+          'msvs_cygwin_shell': 0,
+        },
+        {
+          'action_name': 'second action (succeeds)',
+          'inputs': [
+            'action_succeed.py',
+          ],
+          'outputs': [
+            'ALWAYS_OUT_OF_DATE',
+          ],
+          'action': [
+            'python', '<@(_inputs)'
+          ],
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/msvs/multiple_actions_error_handling/gyptest.py b/gyp/test/msvs/multiple_actions_error_handling/gyptest.py
new file mode 100644 (file)
index 0000000..3aa6b8f
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that failing actions make the build fail reliably, even when there
+are multiple actions in one project.
+"""
+
+import os
+import sys
+import TestGyp
+import TestCmd
+
+test = TestGyp.TestGyp(formats=['msvs'], workdir='workarea_all')
+
+test.run_gyp('actions.gyp')
+test.build('actions.gyp',
+           target='actions-test',
+           status=1,
+           stdout=r'.*"cmd\.exe" exited with code 1\..*',
+           match=TestCmd.match_re_dotall)
+
+test.pass_test()
diff --git a/gyp/test/msvs/props/AppName.props b/gyp/test/msvs/props/AppName.props
new file mode 100644 (file)
index 0000000..b688f66
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Label="UserMacros">
+    <AppName>Greet</AppName>
+  </PropertyGroup>
+  <PropertyGroup>
+    <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+  </PropertyGroup>
+  <ItemGroup>
+    <BuildMacro Include="AppName">
+      <Value>$(AppName)</Value>
+    </BuildMacro>
+  </ItemGroup>
+</Project>
diff --git a/gyp/test/msvs/props/AppName.vsprops b/gyp/test/msvs/props/AppName.vsprops
new file mode 100644 (file)
index 0000000..84b9af3
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+    ProjectType="Visual C++"
+    Version="8.00"
+    Name="Common"
+    >
+    <UserMacro
+        Name="AppName"
+        Value="Greet"
+    />
+</VisualStudioPropertySheet>
diff --git a/gyp/test/msvs/props/gyptest-props.py b/gyp/test/msvs/props/gyptest-props.py
new file mode 100644 (file)
index 0000000..abd4df2
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies props files are added by using a
+props file to set the name of the built executable.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_all', formats=['msvs'])
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp')
+
+test.built_file_must_exist('Greet.exe')
+
+test.pass_test()
diff --git a/gyp/test/msvs/props/hello.c b/gyp/test/msvs/props/hello.c
new file mode 100644 (file)
index 0000000..faadc75
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello, world!\n");
+  return 0;
+}
diff --git a/gyp/test/msvs/props/hello.gyp b/gyp/test/msvs/props/hello.gyp
new file mode 100644 (file)
index 0000000..5a58317
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'product_name': '$(AppName)',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+      'msvs_props': [
+        '$(SolutionDir)AppName.vsprops'
+      ],
+      'msbuild_props': [
+        '$(SolutionDir)AppName.props'
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/msvs/shared_output/common.gypi b/gyp/test/msvs/shared_output/common.gypi
new file mode 100644 (file)
index 0000000..c6fa341
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'default_configuration': 'Baz',
+    'configurations': {
+      'Baz': {
+        'msvs_configuration_attributes': {
+          'OutputDirectory': '<(DEPTH)/foo',
+          'IntermediateDirectory': '$(OutDir)/bar',
+        },
+      },
+    },
+  },
+}
diff --git a/gyp/test/msvs/shared_output/gyptest-shared_output.py b/gyp/test/msvs/shared_output/gyptest-shared_output.py
new file mode 100644 (file)
index 0000000..270b280
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test checking that IntermediateDirectory can be defined in terms of
+OutputDirectory. We previously had emitted the definition of
+IntermediateDirectory before the definition of OutputDirectory.
+This is required so that $(IntDir) can be based on $(OutDir).
+"""
+
+import TestGyp
+import os
+
+# NOTE: This test really is vcbuild/msbuild specific (not applicable to windows
+#       ninja), as it is testing the msvs output location when opening an .sln
+#       other than all.sln.
+test = TestGyp.TestGyp(workdir='workarea_shared_output', formats=['msvs'])
+
+test.run_gyp('hello.gyp')
+test.set_configuration('Baz')
+
+test.build('there/there.gyp', test.ALL)
+test.must_exist(os.path.join(test.workdir, 'foo', 'there.exe'))
+test.must_exist(os.path.join(test.workdir, 'foo', 'bar', 'there.obj'))
+
+test.build('hello.gyp', test.ALL)
+test.must_exist(os.path.join(test.workdir, 'foo', 'hello.exe'))
+test.must_exist(os.path.join(test.workdir, 'foo', 'bar', 'hello.obj'))
+
+if test.format == 'msvs':
+  if test.uses_msbuild:
+    test.must_contain('pull_in_there.vcxproj',
+      '<IntDir>$(OutDir)bar\\</IntDir>')
+  else:
+    test.must_contain('pull_in_there.vcproj',
+      'IntermediateDirectory="$(OutDir)bar\\"')
+
+test.pass_test()
diff --git a/gyp/test/msvs/shared_output/hello.c b/gyp/test/msvs/shared_output/hello.c
new file mode 100644 (file)
index 0000000..698e4fd
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+int main(void) {
+  printf("Hello, world!\n");
+  return 0;
+}
diff --git a/gyp/test/msvs/shared_output/hello.gyp b/gyp/test/msvs/shared_output/hello.gyp
new file mode 100644 (file)
index 0000000..f80e5cf
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': ['common.gypi'],
+  'targets': [
+    {
+      'target_name': 'pull_in_there',
+      'type': 'none',
+      'dependencies': ['there/there.gyp:*'],
+    },
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/msvs/shared_output/there/there.c b/gyp/test/msvs/shared_output/there/there.c
new file mode 100644 (file)
index 0000000..698e4fd
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+int main(void) {
+  printf("Hello, world!\n");
+  return 0;
+}
diff --git a/gyp/test/msvs/shared_output/there/there.gyp b/gyp/test/msvs/shared_output/there/there.gyp
new file mode 100644 (file)
index 0000000..56feff3
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': ['../common.gypi'],
+  'targets': [
+    {
+      'target_name': 'there',
+      'type': 'executable',
+      'sources': [
+        'there.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/msvs/uldi2010/gyptest-all.py b/gyp/test/msvs/uldi2010/gyptest-all.py
new file mode 100644 (file)
index 0000000..cc248fb
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that uldi can be disabled on a per-project-reference basis in vs2010.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['msvs'], workdir='workarea_all')
+
+test.run_gyp('hello.gyp')
+
+if test.uses_msbuild:
+  test.must_contain('hello.vcxproj', '<UseLibraryDependencyInputs>false')
+
+test.pass_test()
diff --git a/gyp/test/msvs/uldi2010/hello.c b/gyp/test/msvs/uldi2010/hello.c
new file mode 100644 (file)
index 0000000..06e6a02
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+extern int hello2();
+
+int main(void) {
+  printf("Hello, world!\n");
+  hello2();
+  return 0;
+}
diff --git a/gyp/test/msvs/uldi2010/hello.gyp b/gyp/test/msvs/uldi2010/hello.gyp
new file mode 100644 (file)
index 0000000..a2bf2ba
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+      'dependencies': [
+        'hellolib',
+      ]
+    },
+    {
+      'target_name': 'hellolib',
+      'type': 'static_library',
+      'sources': [
+        'hello2.c',
+      ],
+      'msvs_2010_disable_uldi_when_referenced': 1,
+    },
+  ],
+}
diff --git a/gyp/test/msvs/uldi2010/hello2.c b/gyp/test/msvs/uldi2010/hello2.c
new file mode 100644 (file)
index 0000000..e2f2323
--- /dev/null
@@ -0,0 +1,10 @@
+/* Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int hello2() {
+  printf("Hello, two!\n");
+  return 0;
+}
diff --git a/gyp/test/multiple-targets/gyptest-all.py b/gyp/test/multiple-targets/gyptest-all.py
new file mode 100755 (executable)
index 0000000..98a9adc
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('multiple.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('multiple.gyp', test.ALL, chdir='relocate/src', stderr=None)
+
+expect1 = """\
+hello from prog1.c
+hello from common.c
+"""
+
+expect2 = """\
+hello from prog2.c
+hello from common.c
+"""
+
+test.run_built_executable('prog1', stdout=expect1, chdir='relocate/src')
+test.run_built_executable('prog2', stdout=expect2, chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/multiple-targets/gyptest-default.py b/gyp/test/multiple-targets/gyptest-default.py
new file mode 100755 (executable)
index 0000000..736ca19
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('multiple.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('multiple.gyp', chdir='relocate/src')
+
+expect1 = """\
+hello from prog1.c
+hello from common.c
+"""
+
+expect2 = """\
+hello from prog2.c
+hello from common.c
+"""
+
+test.run_built_executable('prog1', stdout=expect1, chdir='relocate/src')
+test.run_built_executable('prog2', stdout=expect2, chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/multiple-targets/src/common.c b/gyp/test/multiple-targets/src/common.c
new file mode 100644 (file)
index 0000000..f1df7c1
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void common(void)
+{
+  printf("hello from common.c\n");
+  return;
+}
diff --git a/gyp/test/multiple-targets/src/multiple.gyp b/gyp/test/multiple-targets/src/multiple.gyp
new file mode 100644 (file)
index 0000000..3db4ea3
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'prog1',
+      'type': 'executable',
+      'sources': [
+        'prog1.c',
+        'common.c',
+      ],
+    },
+    {
+      'target_name': 'prog2',
+      'type': 'executable',
+      'sources': [
+        'prog2.c',
+        'common.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/multiple-targets/src/prog1.c b/gyp/test/multiple-targets/src/prog1.c
new file mode 100644 (file)
index 0000000..fbf8d4c
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void common(void);
+
+int main(void)
+{
+  printf("hello from prog1.c\n");
+  common();
+  return 0;
+}
diff --git a/gyp/test/multiple-targets/src/prog2.c b/gyp/test/multiple-targets/src/prog2.c
new file mode 100644 (file)
index 0000000..a94b5c1
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void common(void);
+
+int main(void)
+{
+  printf("hello from prog2.c\n");
+  common();
+  return 0;
+}
diff --git a/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py b/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py
new file mode 100755 (executable)
index 0000000..9c5acea
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that building an object file correctly depends on running actions in
+dependent targets, but not the targets themselves.
+"""
+
+import os
+import sys
+import TestGyp
+
+# NOTE(piman): This test will not work with other generators because:
+# - it explicitly tests the optimization, which is not implemented (yet?) on
+# other generators
+# - it relies on the exact path to output object files, which is generator
+# dependent, and actually, relies on the ability to build only that object file,
+# which I don't think is available on all generators.
+# TODO(piman): Extend to other generators when possible.
+test = TestGyp.TestGyp(formats=['ninja'])
+
+test.run_gyp('action_dependencies.gyp', chdir='src')
+
+chdir = 'relocate/src'
+test.relocate('src', chdir)
+
+objext = '.obj' if sys.platform == 'win32' else '.o'
+
+test.build('action_dependencies.gyp',
+           os.path.join('obj', 'b.b' + objext),
+           chdir=chdir)
+
+# The 'a' actions should be run (letting b.c compile), but the a static library
+# should not be built.
+test.built_file_must_not_exist('a', type=test.STATIC_LIB, chdir=chdir)
+test.built_file_must_not_exist('b', type=test.STATIC_LIB, chdir=chdir)
+test.built_file_must_exist(os.path.join('obj', 'b.b' + objext), chdir=chdir)
+
+test.build('action_dependencies.gyp',
+           os.path.join('obj', 'c.c' + objext),
+           chdir=chdir)
+
+# 'a' and 'b' should be built, so that the 'c' action succeeds, letting c.c
+# compile
+test.built_file_must_exist('a', type=test.STATIC_LIB, chdir=chdir)
+test.built_file_must_exist('b', type=test.EXECUTABLE, chdir=chdir)
+test.built_file_must_exist(os.path.join('obj', 'c.c' + objext), chdir=chdir)
+
+
+test.pass_test()
diff --git a/gyp/test/ninja/action_dependencies/src/a.c b/gyp/test/ninja/action_dependencies/src/a.c
new file mode 100644 (file)
index 0000000..4d7af9b
--- /dev/null
@@ -0,0 +1,10 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "a.h"
+
+int funcA() {
+  return 42;
+}
diff --git a/gyp/test/ninja/action_dependencies/src/a.h b/gyp/test/ninja/action_dependencies/src/a.h
new file mode 100644 (file)
index 0000000..335db56
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef A_H_
+#define A_H_
+
+#include "a/generated.h"
+
+int funcA();
+
+#endif  // A_H_
diff --git a/gyp/test/ninja/action_dependencies/src/action_dependencies.gyp b/gyp/test/ninja/action_dependencies/src/action_dependencies.gyp
new file mode 100644 (file)
index 0000000..5baa7a7
--- /dev/null
@@ -0,0 +1,88 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'a',
+      'type': 'static_library',
+      'sources': [
+        'a.c',
+        'a.h',
+      ],
+      'actions': [
+        {
+          'action_name': 'generate_headers',
+          'inputs': [
+            'emit.py'
+          ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/a/generated.h'
+          ],
+          'action': [
+            'python',
+            'emit.py',
+            '<(SHARED_INTERMEDIATE_DIR)/a/generated.h',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+      'include_dirs': [
+        '<(SHARED_INTERMEDIATE_DIR)',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '<(SHARED_INTERMEDIATE_DIR)',
+        ],
+      },
+    },
+    {
+      'target_name': 'b',
+      'type': 'executable',
+      'sources': [
+        'b.c',
+        'b.h',
+      ],
+      'dependencies': [
+        'a',
+      ],
+    },
+    {
+      'target_name': 'c',
+      'type': 'static_library',
+      'sources': [
+        'c.c',
+        'c.h',
+      ],
+      'dependencies': [
+        'b',
+      ],
+      'actions': [
+        {
+          'action_name': 'generate_headers',
+          'inputs': [
+          ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/c/generated.h'
+          ],
+          'action': [
+            '<(PRODUCT_DIR)/b',
+            '<(SHARED_INTERMEDIATE_DIR)/c/generated.h',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+      'include_dirs': [
+        '<(SHARED_INTERMEDIATE_DIR)',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '<(SHARED_INTERMEDIATE_DIR)',
+        ],
+      },
+    },
+  ],
+}
diff --git a/gyp/test/ninja/action_dependencies/src/b.c b/gyp/test/ninja/action_dependencies/src/b.c
new file mode 100644 (file)
index 0000000..8244646
--- /dev/null
@@ -0,0 +1,18 @@
+/* Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+#include "b.h"
+
+int main(int argc, char** argv) {
+  FILE* f;
+  if (argc < 2)
+    return 1;
+  f = fopen(argv[1], "wt");
+  fprintf(f, "#define VALUE %d\n", funcA());
+  fclose(f);
+  return 0;
+}
diff --git a/gyp/test/ninja/action_dependencies/src/b.h b/gyp/test/ninja/action_dependencies/src/b.h
new file mode 100644 (file)
index 0000000..91362cd
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef B_H_
+#define B_H_
+
+#include "a.h"
+
+int funcB();
+
+#endif  // B_H_
diff --git a/gyp/test/ninja/action_dependencies/src/c.c b/gyp/test/ninja/action_dependencies/src/c.c
new file mode 100644 (file)
index 0000000..b412087
--- /dev/null
@@ -0,0 +1,10 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "c.h"
+
+int funcC() {
+  return VALUE;
+}
diff --git a/gyp/test/ninja/action_dependencies/src/c.h b/gyp/test/ninja/action_dependencies/src/c.h
new file mode 100644 (file)
index 0000000..c81a45b
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef C_H_
+#define C_H_
+
+#include "c/generated.h"
+
+int funcC();
+
+#endif  // C_H_
diff --git a/gyp/test/ninja/action_dependencies/src/emit.py b/gyp/test/ninja/action_dependencies/src/emit.py
new file mode 100755 (executable)
index 0000000..2df74b7
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+f = open(sys.argv[1], 'wb')
+f.write('/* Hello World */\n')
+f.close()
diff --git a/gyp/test/ninja/chained-dependency/chained-dependency.gyp b/gyp/test/ninja/chained-dependency/chained-dependency.gyp
new file mode 100644 (file)
index 0000000..3fe68ae
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    # This first target generates a header.
+    {
+      'target_name': 'generate_header',
+      'type': 'none',
+      'msvs_cygwin_shell': '0',
+      'actions': [
+        {
+          'action_name': 'generate header',
+          'inputs': [],
+          'outputs': ['<(SHARED_INTERMEDIATE_DIR)/generated/header.h'],
+          'action': [
+            'python', '-c', 'open(<(_outputs), "w")'
+          ]
+        },
+      ],
+      'all_dependent_settings': {
+        'include_dirs': [
+          '<(SHARED_INTERMEDIATE_DIR)',
+        ],
+      },
+    },
+
+    # This intermediate target does nothing other than pull in a
+    # dependency on the above generated target.
+    {
+      'target_name': 'chain',
+      'type': 'none',
+      'dependencies': [
+        'generate_header',
+      ],
+    },
+
+    # This final target is:
+    # - a static library (so gyp doesn't transitively pull in dependencies);
+    # - that relies on the generated file two dependencies away.
+    {
+      'target_name': 'chained',
+      'type': 'static_library',
+      'dependencies': [
+        'chain',
+      ],
+      'sources': [
+        'chained.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/ninja/chained-dependency/chained.c b/gyp/test/ninja/chained-dependency/chained.c
new file mode 100644 (file)
index 0000000..c1ff1a7
--- /dev/null
@@ -0,0 +1,5 @@
+#include "generated/header.h"
+
+int main(void) {
+  return 0;
+}
diff --git a/gyp/test/ninja/chained-dependency/gyptest-chained-dependency.py b/gyp/test/ninja/chained-dependency/gyptest-chained-dependency.py
new file mode 100755 (executable)
index 0000000..9fcd9a4
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that files generated by two-steps-removed actions are built before
+dependent compile steps.
+"""
+
+import os
+import sys
+import TestGyp
+
+# This test is Ninja-specific in that:
+# - the bug only showed nondeterministically in parallel builds;
+# - it relies on a ninja-specific output file path.
+
+test = TestGyp.TestGyp(formats=['ninja'])
+test.run_gyp('chained-dependency.gyp')
+objext = '.obj' if sys.platform == 'win32' else '.o'
+test.build('chained-dependency.gyp',
+           os.path.join('obj', 'chained.chained' + objext))
+# The test passes if the .o file builds successfully.
+test.pass_test()
diff --git a/gyp/test/ninja/normalize-paths-win/gyptest-normalize-paths.py b/gyp/test/ninja/normalize-paths-win/gyptest-normalize-paths.py
new file mode 100644 (file)
index 0000000..f56dbe5
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure paths are normalized with VS macros properly expanded on Windows.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  test.run_gyp('normalize-paths.gyp')
+
+  # We can't use existence tests because any case will pass, so we check the
+  # contents of ninja files directly since that's what we're most concerned
+  # with anyway.
+  subninja = open(test.built_file_path('obj/some_target.ninja')).read()
+  if '$!product_dir' in subninja:
+    test.fail_test()
+  if 'out\\Default' in subninja:
+    test.fail_test()
+
+  second = open(test.built_file_path('obj/second.ninja')).read()
+  if ('..\\..\\things\\AnotherName.exe' in second or
+      'AnotherName.exe' not in second):
+    test.fail_test()
+
+  copytarget = open(test.built_file_path('obj/copy_target.ninja')).read()
+  if '$(VSInstallDir)' in copytarget:
+    test.fail_test()
+
+  action = open(test.built_file_path('obj/action.ninja')).read()
+  if '..\\..\\out\\Default' in action:
+    test.fail_test()
+  if '..\\..\\SomethingElse' in action or 'SomethingElse' not in action:
+    test.fail_test()
+  if '..\\..\\SomeOtherInput' in action or 'SomeOtherInput' not in action:
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/ninja/normalize-paths-win/hello.cc b/gyp/test/ninja/normalize-paths-win/hello.cc
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/ninja/normalize-paths-win/normalize-paths.gyp b/gyp/test/ninja/normalize-paths-win/normalize-paths.gyp
new file mode 100644 (file)
index 0000000..544d064
--- /dev/null
@@ -0,0 +1,68 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'Some_Target',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '<(PRODUCT_DIR)/stuff/AnotherName.exe',
+        },
+      },
+      'sources': [
+        'HeLLo.cc',
+        'blOrP.idl',
+      ],
+    },
+    {
+      'target_name': 'second',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '$(OutDir)\\things\\AnotherName.exe',
+        },
+      },
+      'sources': [
+        'HeLLo.cc',
+      ],
+    },
+    {
+      'target_name': 'Copy_Target',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)',
+          'files': [
+            '$(VSInstallDir)\\bin\\cl.exe',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'action',
+      'type': 'none',
+      'msvs_cygwin_shell': '0',
+      'actions': [
+        {
+          'inputs': [
+            '$(IntDir)\\SomeInput',
+            '$(OutDir)\\SomeOtherInput',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/ReSuLt',
+            '<(SHARED_INTERMEDIATE_DIR)/TempFile',
+            '$(OutDir)\SomethingElse',
+          ],
+          'action_name': 'Test action',
+          # Unfortunately, we can't normalize this field because it's
+          # free-form. Fortunately, ninja doesn't inspect it at all (only the
+          # inputs and outputs) so it's not mandatory.
+          'action': [],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/ninja/s-needs-no-depfiles/empty.s b/gyp/test/ninja/s-needs-no-depfiles/empty.s
new file mode 100644 (file)
index 0000000..218d892
--- /dev/null
@@ -0,0 +1 @@
+# This file intentionally left blank.
diff --git a/gyp/test/ninja/s-needs-no-depfiles/gyptest-s-needs-no-depfiles.py b/gyp/test/ninja/s-needs-no-depfiles/gyptest-s-needs-no-depfiles.py
new file mode 100755 (executable)
index 0000000..77a3245
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that .s files don't always trigger a rebuild, as would happen if depfiles
+were used for them (since clang & gcc ignore -MMD when building .s->.o on
+linux).
+"""
+
+import os
+import sys
+import TestCommon
+import TestGyp
+
+# NOTE(fischman): Each generator uses depfiles (or not) differently, so this is
+# a ninja-specific test.
+test = TestGyp.TestGyp(formats=['ninja'])
+
+if sys.platform == 'win32' or sys.platform == 'win64':
+  # This test is about clang/gcc vs. depfiles; VS gets a pass.
+  test.pass_test()
+  sys.exit(0)
+
+test.run_gyp('s-needs-no-depfiles.gyp')
+
+# Build the library, grab its timestamp, rebuild the library, ensure timestamp
+# hasn't changed.
+test.build('s-needs-no-depfiles.gyp', 'empty')
+empty_dll = test.built_file_path('empty', test.SHARED_LIB)
+test.built_file_must_exist(empty_dll)
+pre_stat = os.stat(test.built_file_path(empty_dll))
+test.sleep()
+test.build('s-needs-no-depfiles.gyp', 'empty')
+post_stat = os.stat(test.built_file_path(empty_dll))
+
+if pre_stat.st_mtime != post_stat.st_mtime:
+  test.fail_test()
+else:
+  test.pass_test()
diff --git a/gyp/test/ninja/s-needs-no-depfiles/s-needs-no-depfiles.gyp b/gyp/test/ninja/s-needs-no-depfiles/s-needs-no-depfiles.gyp
new file mode 100644 (file)
index 0000000..bd66b1a
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'empty',
+      'type': 'shared_library',
+      'sources': [ 'empty.s' ],
+    },
+  ],
+}
diff --git a/gyp/test/ninja/solibs_avoid_relinking/gyptest-solibs-avoid-relinking.py b/gyp/test/ninja/solibs_avoid_relinking/gyptest-solibs-avoid-relinking.py
new file mode 100755 (executable)
index 0000000..1b8e812
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that relinking a solib doesn't relink a dependent executable if the
+solib's public API hasn't changed.
+"""
+
+import os
+import sys
+import TestCommon
+import TestGyp
+
+# NOTE(fischman): This test will not work with other generators because the
+# API-hash-based-mtime-preservation optimization is only implemented in
+# ninja.py.  It could be extended to the make.py generator as well pretty
+# easily, probably.
+# (also, it tests ninja-specific out paths, which would have to be generalized
+# if this was extended to other generators).
+test = TestGyp.TestGyp(formats=['ninja'])
+
+if not os.environ.get('ProgramFiles(x86)'):
+  # TODO(scottmg)
+  print 'Skipping test on x86, http://crbug.com/365833'
+  test.pass_test()
+
+test.run_gyp('solibs_avoid_relinking.gyp')
+
+# Build the executable, grab its timestamp, touch the solib's source, rebuild
+# executable, ensure timestamp hasn't changed.
+test.build('solibs_avoid_relinking.gyp', 'b')
+test.built_file_must_exist('b' + TestCommon.exe_suffix)
+pre_stat = os.stat(test.built_file_path('b' + TestCommon.exe_suffix))
+os.utime(os.path.join(test.workdir, 'solib.cc'),
+         (pre_stat.st_atime, pre_stat.st_mtime + 100))
+test.sleep()
+test.build('solibs_avoid_relinking.gyp', 'b')
+post_stat = os.stat(test.built_file_path('b' + TestCommon.exe_suffix))
+
+if pre_stat.st_mtime != post_stat.st_mtime:
+  test.fail_test()
+else:
+  test.pass_test()
diff --git a/gyp/test/ninja/solibs_avoid_relinking/main.cc b/gyp/test/ninja/solibs_avoid_relinking/main.cc
new file mode 100644 (file)
index 0000000..2cd74d3
--- /dev/null
@@ -0,0 +1,5 @@
+extern int foo();
+
+int main() {
+  return foo();
+}
diff --git a/gyp/test/ninja/solibs_avoid_relinking/solib.cc b/gyp/test/ninja/solibs_avoid_relinking/solib.cc
new file mode 100644 (file)
index 0000000..0856cd4
--- /dev/null
@@ -0,0 +1,8 @@
+#ifdef _MSC_VER
+__declspec(dllexport)
+#else
+__attribute__((visibility("default")))
+#endif
+int foo() {
+  return 42;
+}
diff --git a/gyp/test/ninja/solibs_avoid_relinking/solibs_avoid_relinking.gyp b/gyp/test/ninja/solibs_avoid_relinking/solibs_avoid_relinking.gyp
new file mode 100644 (file)
index 0000000..e816351
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'a',
+      'type': 'shared_library',
+      'sources': [ 'solib.cc' ],
+      # Incremental linking enabled so that .lib timestamp is maintained when
+      # exports are unchanged.
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkIncremental': '2',
+        }
+      },
+    },
+    {
+      'target_name': 'b',
+      'type': 'executable',
+      'sources': [ 'main.cc' ],
+      'dependencies': [ 'a' ],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkIncremental': '2',
+        }
+      },
+    },
+  ],
+  'conditions': [
+    ['OS=="linux"', {
+      'target_defaults': {
+        'cflags': ['-fPIC'],
+      },
+    }],
+  ],
+}
diff --git a/gyp/test/ninja/use-console/foo.bar b/gyp/test/ninja/use-console/foo.bar
new file mode 100644 (file)
index 0000000..07c476a
--- /dev/null
@@ -0,0 +1,5 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+This is a dummy file for rule/action input.
diff --git a/gyp/test/ninja/use-console/gyptest-use-console.py b/gyp/test/ninja/use-console/gyptest-use-console.py
new file mode 100644 (file)
index 0000000..f76fcd9
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure 'ninja_use_console' is supported in actions and rules.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['ninja'])
+
+test.run_gyp('use-console.gyp')
+
+no_pool = open(test.built_file_path('obj/no_pool.ninja')).read()
+if 'pool =' in no_pool:
+  test.fail_test()
+
+action_pool = open(test.built_file_path('obj/action_pool.ninja')).read()
+if 'pool = console' not in action_pool:
+  test.fail_test()
+
+rule_pool = open(test.built_file_path('obj/rule_pool.ninja')).read()
+if 'pool = console' not in rule_pool:
+  test.fail_test()
+
+test.pass_test()
diff --git a/gyp/test/ninja/use-console/use-console.gyp b/gyp/test/ninja/use-console/use-console.gyp
new file mode 100644 (file)
index 0000000..84e6318
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'no_pool',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'some_action',
+          'action': ['echo', 'hello'],
+          'inputs': ['foo.bar'],
+          'outputs': ['dummy'],
+        },
+      ],
+      'rules': [
+        {
+          'rule_name': 'some_rule',
+          'extension': 'bar',
+          'action': ['echo', 'hello'],
+          'outputs': ['dummy'],
+        },
+      ],
+      'sources': [
+        'foo.bar',
+      ],
+    },
+    {
+      'target_name': 'action_pool',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'some_action',
+          'action': ['echo', 'hello'],
+          'inputs': ['foo.bar'],
+          'outputs': ['dummy'],
+          'ninja_use_console': 1,
+        },
+      ],
+    },
+    {
+      'target_name': 'rule_pool',
+      'type': 'none',
+      'rules': [
+        {
+          'rule_name': 'some_rule',
+          'extension': 'bar',
+          'action': ['echo', 'hello'],
+          'outputs': ['dummy'],
+          'ninja_use_console': 1,
+        },
+      ],
+      'sources': [
+        'foo.bar',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/ninja/use-custom-environment-files/gyptest-use-custom-environment-files.py b/gyp/test/ninja/use-custom-environment-files/gyptest-use-custom-environment-files.py
new file mode 100644 (file)
index 0000000..0c44b1d
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure environment files can be suppressed.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  test.run_gyp('use-custom-environment-files.gyp',
+               '-G', 'ninja_use_custom_environment_files')
+
+  # Make sure environment files do not exist.
+  if os.path.exists(test.built_file_path('environment.x86')):
+    test.fail_test()
+  if os.path.exists(test.built_file_path('environment.x64')):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/ninja/use-custom-environment-files/use-custom-environment-files.cc b/gyp/test/ninja/use-custom-environment-files/use-custom-environment-files.cc
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/ninja/use-custom-environment-files/use-custom-environment-files.gyp b/gyp/test/ninja/use-custom-environment-files/use-custom-environment-files.gyp
new file mode 100644 (file)
index 0000000..dbc95a9
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'test_use_custom_environment_files',
+      'type': 'executable',
+      'sources': [
+        'use-custom-environment-files.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/no-cpp/gyptest-no-cpp.py b/gyp/test/no-cpp/gyptest-no-cpp.py
new file mode 100644 (file)
index 0000000..432fe77
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Checks that C-only targets aren't linked against libstdc++.
+"""
+
+import TestGyp
+
+import re
+import subprocess
+import sys
+
+# set |match| to ignore build stderr output.
+test = TestGyp.TestGyp(match = lambda a, b: True)
+if sys.platform != 'win32' and test.format not in ('make', 'android'):
+  # TODO: This doesn't pass with make.
+  # TODO: Does a test like this make sense with Windows? Android?
+
+  CHDIR = 'src'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', 'no_cpp', chdir=CHDIR)
+
+  def LinksLibStdCpp(path):
+    path = test.built_file_path(path, chdir=CHDIR)
+    if sys.platform == 'darwin':
+      proc = subprocess.Popen(['otool', '-L', path], stdout=subprocess.PIPE)
+    else:
+      proc = subprocess.Popen(['ldd', path], stdout=subprocess.PIPE)
+    output = proc.communicate()[0]
+    assert not proc.returncode
+    return 'libstdc++' in output or 'libc++' in output
+
+  if LinksLibStdCpp('no_cpp'):
+    test.fail_test()
+
+  build_error_code = {
+    'xcode': [1, 65],  # 1 for xcode 3, 65 for xcode 4 (see `man sysexits`)
+    'make': 2,
+    'ninja': 1,
+    'cmake': 0,  # CMake picks the compiler driver based on transitive checks.
+  }[test.format]
+
+  test.build('test.gyp', 'no_cpp_dep_on_cc_lib', chdir=CHDIR,
+             status=build_error_code)
+
+  test.pass_test()
diff --git a/gyp/test/no-cpp/src/call-f-main.c b/gyp/test/no-cpp/src/call-f-main.c
new file mode 100644 (file)
index 0000000..8b95c59
--- /dev/null
@@ -0,0 +1,2 @@
+void* f();
+int main() { f(); }
diff --git a/gyp/test/no-cpp/src/empty-main.c b/gyp/test/no-cpp/src/empty-main.c
new file mode 100644 (file)
index 0000000..237c8ce
--- /dev/null
@@ -0,0 +1 @@
+int main() {}
diff --git a/gyp/test/no-cpp/src/f.cc b/gyp/test/no-cpp/src/f.cc
new file mode 100644 (file)
index 0000000..02f50f2
--- /dev/null
@@ -0,0 +1,3 @@
+extern "C" { void* f(); }
+
+void* f() { return new int; }
diff --git a/gyp/test/no-cpp/src/test.gyp b/gyp/test/no-cpp/src/test.gyp
new file mode 100644 (file)
index 0000000..417015e
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'no_cpp',
+      'type': 'executable',
+      'sources': [ 'empty-main.c' ],
+    },
+    # A static_library with a cpp file and a linkable with only .c files
+    # depending on it causes a linker error:
+    {
+      'target_name': 'cpp_lib',
+      'type': 'static_library',
+      'sources': [ 'f.cc' ],
+    },
+    {
+      'target_name': 'no_cpp_dep_on_cc_lib',
+      'type': 'executable',
+      'dependencies': [ 'cpp_lib' ],
+      'sources': [ 'call-f-main.c' ],
+    },
+  ],
+}
diff --git a/gyp/test/no-output/gyptest-no-output.py b/gyp/test/no-output/gyptest-no-output.py
new file mode 100755 (executable)
index 0000000..bf9a0b5
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verified things don't explode when there are targets without outputs.
+"""
+
+import TestGyp
+
+# TODO(evan): in ninja when there are no targets, there is no 'all'
+# target either.  Disabling this test for now.
+test = TestGyp.TestGyp(formats=['!ninja'])
+
+test.run_gyp('nooutput.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+test.build('nooutput.gyp', chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/no-output/src/nooutput.gyp b/gyp/test/no-output/src/nooutput.gyp
new file mode 100644 (file)
index 0000000..c40124e
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'no_output',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'defines': [
+          'NADA',
+        ],
+      },
+    },
+  ],
+}
diff --git a/gyp/test/product/gyptest-product.py b/gyp/test/product/gyptest-product.py
new file mode 100755 (executable)
index 0000000..955295d
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using the default build target.
+"""
+
+import TestGyp
+
+# Android does not support setting the build directory.
+test = TestGyp.TestGyp(formats=['!android'])
+
+test.run_gyp('product.gyp')
+test.build('product.gyp')
+
+# executables
+test.built_file_must_exist('alt1' + test._exe, test.EXECUTABLE, bare=True)
+test.built_file_must_exist('hello2.stuff', test.EXECUTABLE, bare=True)
+test.built_file_must_exist('yoalt3.stuff', test.EXECUTABLE, bare=True)
+
+# shared libraries
+test.built_file_must_exist(test.dll_ + 'alt4' + test._dll,
+                           test.SHARED_LIB, bare=True)
+test.built_file_must_exist(test.dll_ + 'hello5.stuff',
+                           test.SHARED_LIB, bare=True)
+test.built_file_must_exist('yoalt6.stuff', test.SHARED_LIB, bare=True)
+
+# static libraries
+test.built_file_must_exist(test.lib_ + 'alt7' + test._lib,
+                           test.STATIC_LIB, bare=True)
+test.built_file_must_exist(test.lib_ + 'hello8.stuff',
+                           test.STATIC_LIB, bare=True)
+test.built_file_must_exist('yoalt9.stuff', test.STATIC_LIB, bare=True)
+
+# alternate product_dir
+test.built_file_must_exist('bob/yoalt10.stuff', test.EXECUTABLE, bare=True)
+test.built_file_must_exist('bob/yoalt11.stuff', test.EXECUTABLE, bare=True)
+test.built_file_must_exist('bob/yoalt12.stuff', test.EXECUTABLE, bare=True)
+
+test.pass_test()
diff --git a/gyp/test/product/hello.c b/gyp/test/product/hello.c
new file mode 100644 (file)
index 0000000..41fdff0
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int func1(void) {
+  return 42;
+}
+
+int main(void) {
+  printf("Hello, world!\n");
+  printf("%d\n", func1());
+  return 0;
+}
diff --git a/gyp/test/product/product.gyp b/gyp/test/product/product.gyp
new file mode 100644 (file)
index 0000000..c25eaaa
--- /dev/null
@@ -0,0 +1,128 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello1',
+      'product_name': 'alt1',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+    },
+    {
+      'target_name': 'hello2',
+      'product_extension': 'stuff',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+    },
+    {
+      'target_name': 'hello3',
+      'product_name': 'alt3',
+      'product_extension': 'stuff',
+      'product_prefix': 'yo',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+    },
+
+    {
+      'target_name': 'hello4',
+      'product_name': 'alt4',
+      'type': 'shared_library',
+      'sources': [
+        'hello.c',
+      ],
+    },
+    {
+      'target_name': 'hello5',
+      'product_extension': 'stuff',
+      'type': 'shared_library',
+      'sources': [
+        'hello.c',
+      ],
+    },
+    {
+      'target_name': 'hello6',
+      'product_name': 'alt6',
+      'product_extension': 'stuff',
+      'product_prefix': 'yo',
+      'type': 'shared_library',
+      'sources': [
+        'hello.c',
+      ],
+    },
+
+    {
+      'target_name': 'hello7',
+      'product_name': 'alt7',
+      'type': 'static_library',
+      'sources': [
+        'hello.c',
+      ],
+    },
+    {
+      'target_name': 'hello8',
+      'product_extension': 'stuff',
+      'type': 'static_library',
+      'sources': [
+        'hello.c',
+      ],
+    },
+    {
+      'target_name': 'hello9',
+      'product_name': 'alt9',
+      'product_extension': 'stuff',
+      'product_prefix': 'yo',
+      'type': 'static_library',
+      'sources': [
+        'hello.c',
+      ],
+    },
+    {
+      'target_name': 'hello10',
+      'product_name': 'alt10',
+      'product_extension': 'stuff',
+      'product_prefix': 'yo',
+      'product_dir': '<(PRODUCT_DIR)/bob',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+    },
+    {
+      'target_name': 'hello11',
+      'product_name': 'alt11',
+      'product_extension': 'stuff',
+      'product_prefix': 'yo',
+      'product_dir': '<(PRODUCT_DIR)/bob',
+      'type': 'shared_library',
+      'sources': [
+        'hello.c',
+      ],
+    },
+    {
+      'target_name': 'hello12',
+      'product_name': 'alt12',
+      'product_extension': 'stuff',
+      'product_prefix': 'yo',
+      'product_dir': '<(PRODUCT_DIR)/bob',
+      'type': 'static_library',
+      'sources': [
+        'hello.c',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="linux"', {
+      'target_defaults': {
+        'cflags': ['-fPIC'],
+      },
+    }],
+  ],
+}
diff --git a/gyp/test/prune_targets/gyptest-prune-targets.py b/gyp/test/prune_targets/gyptest-prune-targets.py
new file mode 100644 (file)
index 0000000..4f1e64a
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies --root-target removes the unnecessary targets.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+build_error_code = {
+  'android': 2,
+  'cmake': 1,
+  'make': 2,
+  'msvs': 1,
+  'ninja': 1,
+  'xcode': 65,
+}[test.format]
+
+# By default, everything will be included.
+test.run_gyp('test1.gyp')
+test.build('test2.gyp', 'lib1')
+test.build('test2.gyp', 'lib2')
+test.build('test2.gyp', 'lib3')
+test.build('test2.gyp', 'lib_indirect')
+test.build('test1.gyp', 'program1')
+test.build('test1.gyp', 'program2')
+test.build('test1.gyp', 'program3')
+
+# With deep dependencies of program1 only.
+test.run_gyp('test1.gyp', '--root-target=program1')
+test.build('test2.gyp', 'lib1')
+test.build('test2.gyp', 'lib2', status=build_error_code, stderr=None)
+test.build('test2.gyp', 'lib3', status=build_error_code, stderr=None)
+test.build('test2.gyp', 'lib_indirect')
+test.build('test1.gyp', 'program1')
+test.build('test1.gyp', 'program2', status=build_error_code, stderr=None)
+test.build('test1.gyp', 'program3', status=build_error_code, stderr=None)
+
+# With deep dependencies of program2 only.
+test.run_gyp('test1.gyp', '--root-target=program2')
+test.build('test2.gyp', 'lib1', status=build_error_code, stderr=None)
+test.build('test2.gyp', 'lib2')
+test.build('test2.gyp', 'lib3', status=build_error_code, stderr=None)
+test.build('test2.gyp', 'lib_indirect')
+test.build('test1.gyp', 'program1', status=build_error_code, stderr=None)
+test.build('test1.gyp', 'program2')
+test.build('test1.gyp', 'program3', status=build_error_code, stderr=None)
+
+# With deep dependencies of program1 and program2.
+test.run_gyp('test1.gyp', '--root-target=program1', '--root-target=program2')
+test.build('test2.gyp', 'lib1')
+test.build('test2.gyp', 'lib2')
+test.build('test2.gyp', 'lib3', status=build_error_code, stderr=None)
+test.build('test2.gyp', 'lib_indirect')
+test.build('test1.gyp', 'program1')
+test.build('test1.gyp', 'program2')
+test.build('test1.gyp', 'program3', status=build_error_code, stderr=None)
+
+test.pass_test()
diff --git a/gyp/test/prune_targets/lib1.cc b/gyp/test/prune_targets/lib1.cc
new file mode 100644 (file)
index 0000000..692b7de
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+void libfunc1() {
+}
diff --git a/gyp/test/prune_targets/lib2.cc b/gyp/test/prune_targets/lib2.cc
new file mode 100644 (file)
index 0000000..aed394a
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+void libfunc2() {
+}
diff --git a/gyp/test/prune_targets/lib3.cc b/gyp/test/prune_targets/lib3.cc
new file mode 100644 (file)
index 0000000..af0f717
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+void libfunc3() {
+}
diff --git a/gyp/test/prune_targets/lib_indirect.cc b/gyp/test/prune_targets/lib_indirect.cc
new file mode 100644 (file)
index 0000000..92d9ea4
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+void libfunc_indirect() {
+}
diff --git a/gyp/test/prune_targets/program.cc b/gyp/test/prune_targets/program.cc
new file mode 100644 (file)
index 0000000..c9ac070
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/prune_targets/test1.gyp b/gyp/test/prune_targets/test1.gyp
new file mode 100644 (file)
index 0000000..b65ec19
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program1',
+      'type': 'executable',
+      'sources': [ 'program.cc' ],
+      'dependencies': [ 'test2.gyp:lib1' ],
+    },
+    {
+      'target_name': 'program2',
+      'type': 'executable',
+      'sources': [ 'program.cc' ],
+      'dependencies': [ 'test2.gyp:lib2' ],
+    },
+    {
+      'target_name': 'program3',
+      'type': 'executable',
+      'sources': [ 'program.cc' ],
+      'dependencies': [ 'test2.gyp:lib3' ],
+    },
+  ],
+}
diff --git a/gyp/test/prune_targets/test2.gyp b/gyp/test/prune_targets/test2.gyp
new file mode 100644 (file)
index 0000000..16f0fd3
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'lib1',
+      'type': 'static_library',
+      'sources': [ 'lib1.cc' ],
+      'dependencies': [ 'lib_indirect' ],
+    },
+    {
+      'target_name': 'lib2',
+      'type': 'static_library',
+      'sources': [ 'lib2.cc' ],
+      'dependencies': [ 'lib_indirect' ],
+    },
+    {
+      'target_name': 'lib3',
+      'type': 'static_library',
+      'sources': [ 'lib3.cc' ],
+    },
+    {
+      'target_name': 'lib_indirect',
+      'type': 'static_library',
+      'sources': [ 'lib_indirect.cc' ],
+    },
+  ],
+}
diff --git a/gyp/test/relative/foo/a/a.cc b/gyp/test/relative/foo/a/a.cc
new file mode 100644 (file)
index 0000000..7d1c953
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/relative/foo/a/a.gyp b/gyp/test/relative/foo/a/a.gyp
new file mode 100644 (file)
index 0000000..66316ac
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  'targets': [
+    {
+      'target_name': 'a',
+      'type': 'executable',
+      'sources': ['a.cc'],
+      'dependencies': [
+        '../../foo/b/b.gyp:b',
+        'c/c.gyp:c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/relative/foo/a/c/c.cc b/gyp/test/relative/foo/a/c/c.cc
new file mode 100644 (file)
index 0000000..9d22471
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+int func() {
+  return 0;
+}
diff --git a/gyp/test/relative/foo/a/c/c.gyp b/gyp/test/relative/foo/a/c/c.gyp
new file mode 100644 (file)
index 0000000..c1f087d
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  'targets': [
+    {
+      'target_name': 'c',
+      'type': 'static_library',
+      'sources': ['c.cc'],
+      'dependencies': [
+        '../../b/b.gyp:b',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/relative/foo/b/b.cc b/gyp/test/relative/foo/b/b.cc
new file mode 100644 (file)
index 0000000..011d59c
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+int func2() {
+  return 0;
+}
diff --git a/gyp/test/relative/foo/b/b.gyp b/gyp/test/relative/foo/b/b.gyp
new file mode 100644 (file)
index 0000000..0ebe453
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  'targets': [
+    {
+      'target_name': 'b',
+      'type': 'static_library',
+      'sources': ['b.cc'],
+    },
+  ],
+}
diff --git a/gyp/test/relative/gyptest-default.py b/gyp/test/relative/gyptest-default.py
new file mode 100755 (executable)
index 0000000..2d657aa
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using the default build target.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_default', formats=['msvs'])
+
+# Run from down in foo.
+test.run_gyp('a.gyp', chdir='foo/a')
+sln = test.workpath('foo/a/a.sln')
+sln_data = open(sln, 'rb').read()
+vcproj = sln_data.count('b.vcproj')
+vcxproj = sln_data.count('b.vcxproj')
+if (vcproj, vcxproj) not in [(1, 0), (0, 1)]:
+  test.fail_test()
+
+test.pass_test()
diff --git a/gyp/test/rename/filecase/file.c b/gyp/test/rename/filecase/file.c
new file mode 100644 (file)
index 0000000..76e8197
--- /dev/null
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/gyp/test/rename/filecase/test-casesensitive.gyp b/gyp/test/rename/filecase/test-casesensitive.gyp
new file mode 100644 (file)
index 0000000..48eaa6e
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'filecaserename_sensitive',
+      'type': 'executable',
+      'sources': [
+        'FiLe.c',
+        'fIlE.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rename/filecase/test.gyp b/gyp/test/rename/filecase/test.gyp
new file mode 100644 (file)
index 0000000..eaee933
--- /dev/null
@@ -0,0 +1,14 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'filecaserename',
+      'type': 'executable',
+      'sources': [
+        'file.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rename/gyptest-filecase.py b/gyp/test/rename/gyptest-filecase.py
new file mode 100644 (file)
index 0000000..daed518
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Checks that files whose file case changes get rebuilt correctly.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+CHDIR = 'filecase'
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+os.rename('filecase/file.c', 'filecase/fIlE.c')
+test.write('filecase/test.gyp',
+           test.read('filecase/test.gyp').replace('file.c', 'fIlE.c'))
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+
+# Check that having files that differ just in their case still work on
+# case-sensitive file systems.
+test.write('filecase/FiLe.c', 'int f(); int main() { return f(); }')
+test.write('filecase/fIlE.c', 'int f() { return 42; }')
+is_case_sensitive = test.read('filecase/FiLe.c') != test.read('filecase/fIlE.c')
+if is_case_sensitive:
+  test.run_gyp('test-casesensitive.gyp', chdir=CHDIR)
+  test.build('test-casesensitive.gyp', test.ALL, chdir=CHDIR)
+
+test.pass_test()
diff --git a/gyp/test/restat/gyptest-restat.py b/gyp/test/restat/gyptest-restat.py
new file mode 100644 (file)
index 0000000..8737904
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that dependent rules are executed iff a dependency action modifies its
+outputs.
+"""
+
+import TestGyp
+import os
+
+test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+test.run_gyp('restat.gyp', chdir='src')
+
+chdir = 'relocate/src'
+test.relocate('src', chdir)
+
+# Building 'dependent' the first time generates 'side_effect', but building it
+# the second time doesn't, because 'create_intermediate' doesn't update its
+# output.
+test.build('restat.gyp', 'dependent', chdir=chdir)
+test.built_file_must_exist('side_effect', chdir=chdir)
+os.remove(test.built_file_path('side_effect', chdir=chdir))
+test.build('restat.gyp', 'dependent', chdir=chdir)
+test.built_file_must_not_exist('side_effect', chdir=chdir)
+
+test.pass_test()
diff --git a/gyp/test/restat/src/create_intermediate.py b/gyp/test/restat/src/create_intermediate.py
new file mode 100644 (file)
index 0000000..a4d7450
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+
+"""
+Create argv[1] iff it doesn't already exist.
+"""
+
+outfile = sys.argv[1]
+if os.path.exists(outfile):
+  sys.exit()
+open(outfile, "wb").close()
diff --git a/gyp/test/restat/src/restat.gyp b/gyp/test/restat/src/restat.gyp
new file mode 100644 (file)
index 0000000..ff020e0
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'create_intermediate',
+      'type': 'none',
+      'msvs_cygwin_shell': '0',
+      'actions': [
+        {
+          'action_name': 'create_intermediate',
+          'inputs': [
+            'create_intermediate.py',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/intermediate',
+            'ALWAYS.run.ALWAYS',
+          ],
+          'action': [
+            'python', 'create_intermediate.py', '<(PRODUCT_DIR)/intermediate',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'dependent',
+      'type': 'none',
+      'msvs_cygwin_shell': '0',
+      'dependencies': [
+        'create_intermediate',
+      ],
+      'actions': [
+        {
+          'action_name': 'dependent',
+          'inputs': [
+            '<(PRODUCT_DIR)/intermediate',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/dependent'
+          ],
+          'action': [
+            'python', 'touch.py', '<(PRODUCT_DIR)/dependent', '<(PRODUCT_DIR)/side_effect',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/restat/src/touch.py b/gyp/test/restat/src/touch.py
new file mode 100644 (file)
index 0000000..7cd781a
--- /dev/null
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+
+"""Cross-platform touch."""
+
+for fname in sys.argv[1:]:
+  if os.path.exists(fname):
+    os.utime(fname, None)
+  else:
+    open(fname, 'w').close()
diff --git a/gyp/test/rules-dirname/gyptest-dirname.py b/gyp/test/rules-dirname/gyptest-dirname.py
new file mode 100755 (executable)
index 0000000..420b80f
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple rules when using an explicit build target of 'all'.
+"""
+
+import TestGyp
+import os
+import sys
+
+test = TestGyp.TestGyp(formats=['make', 'ninja', 'android', 'xcode', 'msvs'])
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('actions.gyp', chdir='relocate/src')
+
+expect = """\
+no dir here
+hi c
+hello baz
+"""
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('gencc_int_output', chdir=chdir, stdout=expect)
+if test.format == 'msvs':
+  test.run_built_executable('gencc_int_output_external', chdir=chdir,
+                            stdout=expect)
+
+test.must_match('relocate/src/subdir/foo/bar/baz.dirname',
+                os.path.join('foo', 'bar'))
+test.must_match('relocate/src/subdir/a/b/c.dirname',
+                os.path.join('a', 'b'))
+
+# FIXME the xcode and make generators incorrectly convert RULE_INPUT_PATH
+# to an absolute path, making the tests below fail!
+if test.format != 'xcode' and test.format != 'make':
+  test.must_match('relocate/src/subdir/foo/bar/baz.path',
+                  os.path.join('foo', 'bar', 'baz.printvars'))
+  test.must_match('relocate/src/subdir/a/b/c.path',
+                  os.path.join('a', 'b', 'c.printvars'))
+
+test.pass_test()
diff --git a/gyp/test/rules-dirname/src/actions.gyp b/gyp/test/rules-dirname/src/actions.gyp
new file mode 100644 (file)
index 0000000..c5693c6
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'pull_in_all_actions',
+      'type': 'none',
+      'dependencies': [
+        'subdir/input-rule-dirname.gyp:*',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules-dirname/src/copy-file.py b/gyp/test/rules-dirname/src/copy-file.py
new file mode 100755 (executable)
index 0000000..9774ccc
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import sys
+
+contents = open(sys.argv[1], 'r').read()
+open(sys.argv[2], 'wb').write(contents)
+
+sys.exit(0)
diff --git a/gyp/test/rules-dirname/src/subdir/a/b/c.gencc b/gyp/test/rules-dirname/src/subdir/a/b/c.gencc
new file mode 100644 (file)
index 0000000..29cb5f7
--- /dev/null
@@ -0,0 +1,8 @@
+// -*- mode: c++ -*-
+#include <stdio.h>
+
+namespace gen {
+  void c() {
+    printf("hi c\n");
+  }
+}
diff --git a/gyp/test/rules-dirname/src/subdir/a/b/c.printvars b/gyp/test/rules-dirname/src/subdir/a/b/c.printvars
new file mode 100644 (file)
index 0000000..cc4561d
--- /dev/null
@@ -0,0 +1 @@
+# Empty file for testing build rules
diff --git a/gyp/test/rules-dirname/src/subdir/foo/bar/baz.gencc b/gyp/test/rules-dirname/src/subdir/foo/bar/baz.gencc
new file mode 100644 (file)
index 0000000..90b4ce9
--- /dev/null
@@ -0,0 +1,8 @@
+// -*- mode: c++ -*-
+#include <stdio.h>
+
+namespace gen {
+  void baz() {
+    printf("hello baz\n");
+  }
+}
diff --git a/gyp/test/rules-dirname/src/subdir/foo/bar/baz.printvars b/gyp/test/rules-dirname/src/subdir/foo/bar/baz.printvars
new file mode 100644 (file)
index 0000000..cc4561d
--- /dev/null
@@ -0,0 +1 @@
+# Empty file for testing build rules
diff --git a/gyp/test/rules-dirname/src/subdir/input-rule-dirname.gyp b/gyp/test/rules-dirname/src/subdir/input-rule-dirname.gyp
new file mode 100644 (file)
index 0000000..da749a2
--- /dev/null
@@ -0,0 +1,140 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'print_rule_input_dirname',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'foo/bar/baz.printvars',
+        'a/b/c.printvars',
+      ],
+      'rules': [
+        {
+          'rule_name': 'printvars',
+          'extension': 'printvars',
+          'inputs': [
+            'printvars.py',
+          ],
+          'outputs': [
+            '<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).dirname',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<(RULE_INPUT_DIRNAME)', '<@(_outputs)',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'print_rule_input_path',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'foo/bar/baz.printvars',
+        'a/b/c.printvars',
+      ],
+      'rules': [
+        {
+          'rule_name': 'printvars',
+          'extension': 'printvars',
+          'inputs': [
+            'printvars.py',
+          ],
+          'outputs': [
+            '<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).path',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'gencc_int_output',
+      'type': 'executable',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'nodir.gencc',
+        'foo/bar/baz.gencc',
+        'a/b/c.gencc',
+        'main.cc',
+      ],
+      'rules': [
+        {
+          'rule_name': 'gencc',
+          'extension': 'gencc',
+          'inputs': [
+            '<(DEPTH)/copy-file.py',
+          ],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).cc',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="win"', {
+      'targets': [
+        {
+          'target_name': 'gencc_int_output_external',
+          'type': 'executable',
+          'msvs_cygwin_shell': 0,
+          'msvs_cygwin_dirs': ['../../../../../../<(DEPTH)/third_party/cygwin'],
+          'sources': [
+            'nodir.gencc',
+            'foo/bar/baz.gencc',
+            'a/b/c.gencc',
+            'main.cc',
+          ],
+          'dependencies': [
+            'cygwin',
+          ],
+          'rules': [
+            {
+              'rule_name': 'gencc',
+              'extension': 'gencc',
+              'msvs_external_rule': 1,
+              'inputs': [
+                '<(DEPTH)/copy-file.py',
+              ],
+              'outputs': [
+                '<(INTERMEDIATE_DIR)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).cc',
+              ],
+              'action': [
+                'python', '<@(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+              ],
+              'process_outputs_as_sources': 1,
+            },
+          ],
+        },
+        {
+          'target_name': 'cygwin',
+          'type': 'none',
+          'actions': [
+            {
+              'action_name': 'setup_mount',
+              'msvs_cygwin_shell': 0,
+              'inputs': [
+                '../../../../../../<(DEPTH)/third_party/cygwin/setup_mount.bat',
+              ],
+              # Visual Studio requires an output file, or else the
+              # custom build step won't run.
+              'outputs': [
+                '<(INTERMEDIATE_DIR)/_always_run_setup_mount.marker',
+              ],
+              'action': ['<@(_inputs)'],
+            },
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/gyp/test/rules-dirname/src/subdir/main.cc b/gyp/test/rules-dirname/src/subdir/main.cc
new file mode 100644 (file)
index 0000000..3bb8e01
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+namespace gen {
+  extern void nodir();
+  extern void c();
+  extern void baz();
+}
+
+int main() {
+  gen::nodir();
+  gen::c();
+  gen::baz();
+}
diff --git a/gyp/test/rules-dirname/src/subdir/nodir.gencc b/gyp/test/rules-dirname/src/subdir/nodir.gencc
new file mode 100644 (file)
index 0000000..720f589
--- /dev/null
@@ -0,0 +1,8 @@
+// -*- mode: c++ -*-
+#include <stdio.h>
+
+namespace gen {
+  void nodir() {
+    printf("no dir here\n");
+  }
+}
diff --git a/gyp/test/rules-dirname/src/subdir/printvars.py b/gyp/test/rules-dirname/src/subdir/printvars.py
new file mode 100755 (executable)
index 0000000..ef3d92e
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Prints interesting vars
+"""
+
+import sys;
+
+out = open(sys.argv[2], 'w')
+out.write(sys.argv[1]);
diff --git a/gyp/test/rules-rebuild/gyptest-all.py b/gyp/test/rules-rebuild/gyptest-all.py
new file mode 100755 (executable)
index 0000000..aaaa2a6
--- /dev/null
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a rule that generates multiple outputs rebuilds
+correctly when the inputs change.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_all')
+
+test.run_gyp('same_target.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+
+test.build('same_target.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in!
+Hello from prog2.in!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.sleep()
+contents = test.read(['relocate', 'src', 'prog1.in'])
+contents = contents.replace('!', ' AGAIN!')
+test.write(['relocate', 'src', 'prog1.in'], contents)
+
+test.build('same_target.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in AGAIN!
+Hello from prog2.in!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.sleep()
+contents = test.read(['relocate', 'src', 'prog2.in'])
+contents = contents.replace('!', ' AGAIN!')
+test.write(['relocate', 'src', 'prog2.in'], contents)
+
+test.build('same_target.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in AGAIN!
+Hello from prog2.in AGAIN!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.pass_test()
diff --git a/gyp/test/rules-rebuild/gyptest-default.py b/gyp/test/rules-rebuild/gyptest-default.py
new file mode 100755 (executable)
index 0000000..ac3f020
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a rule that generates multiple outputs rebuilds
+correctly when the inputs change.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_default')
+
+test.run_gyp('same_target.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+
+test.build('same_target.gyp', chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in!
+Hello from prog2.in!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.sleep()
+contents = test.read(['relocate', 'src', 'prog1.in'])
+contents = contents.replace('!', ' AGAIN!')
+test.write(['relocate', 'src', 'prog1.in'], contents)
+
+test.build('same_target.gyp', chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in AGAIN!
+Hello from prog2.in!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.sleep()
+contents = test.read(['relocate', 'src', 'prog2.in'])
+contents = contents.replace('!', ' AGAIN!')
+test.write(['relocate', 'src', 'prog2.in'], contents)
+
+test.build('same_target.gyp', chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in AGAIN!
+Hello from prog2.in AGAIN!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+# Test that modifying a rule's inputs (specifically, make-sources.py) causes
+# the targets to be built.
+
+test.sleep()
+contents = test.read(['relocate', 'src', 'make-sources.py'])
+contents = contents.replace('%s', 'the amazing %s')
+test.write(['relocate', 'src', 'make-sources.py'], contents)
+
+test.build('same_target.gyp', chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from the amazing prog1.in AGAIN!
+Hello from the amazing prog2.in AGAIN!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.pass_test()
diff --git a/gyp/test/rules-rebuild/src/main.c b/gyp/test/rules-rebuild/src/main.c
new file mode 100644 (file)
index 0000000..bd8fbb2
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern void prog1(void);
+extern void prog2(void);
+
+int main(void)
+{
+  printf("Hello from main.c\n");
+  prog1();
+  prog2();
+  return 0;
+}
diff --git a/gyp/test/rules-rebuild/src/make-sources.py b/gyp/test/rules-rebuild/src/make-sources.py
new file mode 100755 (executable)
index 0000000..7ec0227
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+assert len(sys.argv) == 4, sys.argv
+
+(in_file, c_file, h_file) = sys.argv[1:]
+
+def write_file(filename, contents):
+  open(filename, 'wb').write(contents)
+
+write_file(c_file, open(in_file, 'rb').read())
+
+write_file(h_file, '#define NAME "%s"\n' % in_file)
+
+sys.exit(0)
diff --git a/gyp/test/rules-rebuild/src/prog1.in b/gyp/test/rules-rebuild/src/prog1.in
new file mode 100644 (file)
index 0000000..191b00e
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "prog1.h"
+
+void prog1(void)
+{
+  printf("Hello from %s!\n", NAME);
+}
diff --git a/gyp/test/rules-rebuild/src/prog2.in b/gyp/test/rules-rebuild/src/prog2.in
new file mode 100644 (file)
index 0000000..7bfac51
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "prog2.h"
+
+void prog2(void)
+{
+  printf("Hello from %s!\n", NAME);
+}
diff --git a/gyp/test/rules-rebuild/src/same_target.gyp b/gyp/test/rules-rebuild/src/same_target.gyp
new file mode 100644 (file)
index 0000000..22ba560
--- /dev/null
@@ -0,0 +1,31 @@
+{
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'main.c',
+        'prog1.in',
+        'prog2.in',
+      ],
+      'rules': [
+        {
+          'rule_name': 'make_sources',
+          'extension': 'in',
+          'inputs': [
+            'make-sources.py',
+          ],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).c',
+            '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).h',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<(RULE_INPUT_NAME)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules-use-built-dependencies/gyptest-use-built-dependencies.py b/gyp/test/rules-use-built-dependencies/gyptest-use-built-dependencies.py
new file mode 100755 (executable)
index 0000000..4955ecb
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that rules which use built dependencies work correctly.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('use-built-dependencies-rule.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+test.build('use-built-dependencies-rule.gyp', chdir='relocate/src')
+
+test.built_file_must_exist('main_output', chdir='relocate/src')
+test.built_file_must_match('main_output', 'output', chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/rules-use-built-dependencies/src/main.cc b/gyp/test/rules-use-built-dependencies/src/main.cc
new file mode 100644 (file)
index 0000000..937d284
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+    if (argc < 2) {
+        return 2;
+    }
+    FILE* file;
+    file = fopen(argv[1], "wb");
+    const char output[] = "output";
+    fwrite(output, 1, sizeof(output) - 1, file);
+    fclose(file);
+    return 0;
+}
+
diff --git a/gyp/test/rules-use-built-dependencies/src/use-built-dependencies-rule.gyp b/gyp/test/rules-use-built-dependencies/src/use-built-dependencies-rule.gyp
new file mode 100644 (file)
index 0000000..92bfeda
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'main',
+      'toolsets': ['host'],
+      'type': 'executable',
+      'sources': [
+        'main.cc',
+      ],
+    },
+    {
+      'target_name': 'post',
+      'toolsets': ['host'],
+      'type': 'none',
+      'dependencies': [
+        'main',
+      ],
+      'sources': [
+        # As this test is written it could easily be made into an action.
+        # An acutal use case would have a number of these 'sources'.
+        '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)main<(EXECUTABLE_SUFFIX)',
+      ],
+      'rules': [
+        {
+          'rule_name': 'generate_output',
+          'extension': '<(EXECUTABLE_SUFFIX)',
+          'outputs': [ '<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)_output', ],
+          'msvs_cygwin_shell': 0,
+          'action': [
+            '<(RULE_INPUT_PATH)',
+            '<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)_output',
+          ],
+          'message': 'Generating output for <(RULE_INPUT_ROOT)'
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules-variables/gyptest-rules-variables.py b/gyp/test/rules-variables/gyptest-rules-variables.py
new file mode 100755 (executable)
index 0000000..06ee5ca
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies rules related variables are expanded.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['ninja'])
+
+test.relocate('src', 'relocate/src')
+
+test.run_gyp('variables.gyp', chdir='relocate/src')
+
+test.build('variables.gyp', chdir='relocate/src')
+
+test.run_built_executable('all_rule_variables',
+                          chdir='relocate/src',
+                          stdout="input_root\ninput_dirname\ninput_path\n" +
+                          "input_ext\ninput_name\n")
+
+test.pass_test()
diff --git a/gyp/test/rules-variables/src/input_ext.c b/gyp/test/rules-variables/src/input_ext.c
new file mode 100644 (file)
index 0000000..f41e73e
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+void input_ext() {
+  printf("input_ext\n");
+}
diff --git a/gyp/test/rules-variables/src/input_name/test.c b/gyp/test/rules-variables/src/input_name/test.c
new file mode 100644 (file)
index 0000000..e28b74d
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+void input_name() {
+  printf("input_name\n");
+}
diff --git a/gyp/test/rules-variables/src/input_path/subdir/test.c b/gyp/test/rules-variables/src/input_path/subdir/test.c
new file mode 100644 (file)
index 0000000..403dbbd
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+void input_path() {
+  printf("input_path\n");
+}
diff --git a/gyp/test/rules-variables/src/subdir/input_dirname.c b/gyp/test/rules-variables/src/subdir/input_dirname.c
new file mode 100644 (file)
index 0000000..40cecd8
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+void input_dirname() {
+  printf("input_dirname\n");
+}
diff --git a/gyp/test/rules-variables/src/subdir/test.c b/gyp/test/rules-variables/src/subdir/test.c
new file mode 100644 (file)
index 0000000..6c0280b
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern void input_root();
+extern void input_dirname();
+extern void input_path();
+extern void input_ext();
+extern void input_name();
+
+int main() {
+  input_root();
+  input_dirname();
+  input_path();
+  input_ext();
+  input_name();
+  return 0;
+}
diff --git a/gyp/test/rules-variables/src/test.input_root.c b/gyp/test/rules-variables/src/test.input_root.c
new file mode 100644 (file)
index 0000000..33a7740
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+void input_root() {
+  printf("input_root\n");
+}
diff --git a/gyp/test/rules-variables/src/variables.gyp b/gyp/test/rules-variables/src/variables.gyp
new file mode 100644 (file)
index 0000000..6debba1
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    # This test shouldn't ever actually need to execute its rules: there's no
+    # command line that generates any output anyway. However, there's something
+    # slightly broken in either ninja or (maybe more likely?) on the win32 VM
+    # gypbots that breaks dependency checking and causes this rule to want to
+    # run. When it does run, the cygwin path is wrong, so the do-nothing step
+    # fails.
+    # TODO: Investigate and fix whatever's actually failing and remove this.
+    'msvs_cygwin_dirs': ['../../../../../../<(DEPTH)/third_party/cygwin'],
+  },
+  'targets': [
+    {
+      'target_name': 'all_rule_variables',
+      'type': 'executable',
+      'sources': [
+        'subdir/test.c',
+      ],
+      'rules': [
+        {
+          'rule_name': 'rule_variable',
+          'extension': 'c',
+          'outputs': [
+            '<(RULE_INPUT_ROOT).input_root.c',
+            '<(RULE_INPUT_DIRNAME)/input_dirname.c',
+            'input_path/<(RULE_INPUT_PATH)',
+            'input_ext<(RULE_INPUT_EXT)',
+            'input_name/<(RULE_INPUT_NAME)',
+          ],
+          'action': [],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/gyptest-all.py b/gyp/test/rules/gyptest-all.py
new file mode 100755 (executable)
index 0000000..99b2109
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple rules when using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('no_action_with_rules_fails.gyp', chdir='src/noaction', status=1,
+             stderr=None)
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('actions.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Hello from function1.in
+Hello from function2.in
+"""
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir1'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+expect = """\
+Hello from program.c
+Hello from function3.in
+"""
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir3'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('program2', chdir=chdir, stdout=expect)
+
+test.must_match('relocate/src/subdir2/file1.out', 'Hello from file1.in\n')
+test.must_match('relocate/src/subdir2/file2.out', 'Hello from file2.in\n')
+
+test.must_match('relocate/src/subdir2/file1.out2', 'Hello from file1.in\n')
+test.must_match('relocate/src/subdir2/file2.out2', 'Hello from file2.in\n')
+
+test.must_match('relocate/src/subdir2/file1.out4', 'Hello from file1.in\n')
+test.must_match('relocate/src/subdir2/file2.out4', 'Hello from file2.in\n')
+test.must_match('relocate/src/subdir2/file1.copy', 'Hello from file1.in\n')
+
+test.must_match('relocate/src/external/file1.external_rules.out',
+                'Hello from file1.in\n')
+test.must_match('relocate/src/external/file2.external_rules.out',
+                'Hello from file2.in\n')
+
+expect = """\
+Hello from program.c
+Got 41.
+"""
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir4'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('program4', chdir=chdir, stdout=expect)
+
+test.pass_test()
diff --git a/gyp/test/rules/gyptest-default.py b/gyp/test/rules/gyptest-default.py
new file mode 100755 (executable)
index 0000000..048c93c
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple rules when using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('actions.gyp', chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Hello from function1.in
+Hello from function2.in
+"""
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir1'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+expect = """\
+Hello from program.c
+Hello from function3.in
+"""
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir3'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('program2', chdir=chdir, stdout=expect)
+
+test.must_match('relocate/src/subdir2/file1.out', 'Hello from file1.in\n')
+test.must_match('relocate/src/subdir2/file2.out', 'Hello from file2.in\n')
+
+test.must_match('relocate/src/subdir2/file1.out2', 'Hello from file1.in\n')
+test.must_match('relocate/src/subdir2/file2.out2', 'Hello from file2.in\n')
+
+test.must_match('relocate/src/subdir2/file1.out4', 'Hello from file1.in\n')
+test.must_match('relocate/src/subdir2/file2.out4', 'Hello from file2.in\n')
+test.must_match('relocate/src/subdir2/file1.copy', 'Hello from file1.in\n')
+
+test.must_match('relocate/src/external/file1.external_rules.out',
+                'Hello from file1.in\n')
+test.must_match('relocate/src/external/file2.external_rules.out',
+                'Hello from file2.in\n')
+
+test.pass_test()
diff --git a/gyp/test/rules/gyptest-input-root.py b/gyp/test/rules/gyptest-input-root.py
new file mode 100755 (executable)
index 0000000..92bade6
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that RULE_INPUT_ROOT isn't turned into a path in rule actions
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('input-root.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('input-root.gyp', target='test', chdir='relocate/src')
+
+expect = """\
+Hello somefile
+"""
+
+test.run_built_executable('test', chdir='relocate/src', stdout=expect)
+test.pass_test()
diff --git a/gyp/test/rules/gyptest-special-variables.py b/gyp/test/rules/gyptest-special-variables.py
new file mode 100644 (file)
index 0000000..05ea7ce
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Verifies that VS variables that require special variables are expanded
+correctly. """
+
+import sys
+import TestGyp
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp()
+
+  test.run_gyp('special-variables.gyp', chdir='src')
+  test.build('special-variables.gyp', test.ALL, chdir='src')
+  test.pass_test()
diff --git a/gyp/test/rules/src/actions.gyp b/gyp/test/rules/src/actions.gyp
new file mode 100644 (file)
index 0000000..84376a7
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'pull_in_all_actions',
+      'type': 'none',
+      'dependencies': [
+        'subdir1/executable.gyp:*',
+        'subdir2/both_rule_and_action_input.gyp:*',
+        'subdir2/never_used.gyp:*',
+        'subdir2/no_inputs.gyp:*',
+        'subdir2/no_action.gyp:*',
+        'subdir2/none.gyp:*',
+        'subdir3/executable2.gyp:*',
+        'subdir4/build-asm.gyp:*',
+        'external/external.gyp:*',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/an_asm.S b/gyp/test/rules/src/an_asm.S
new file mode 100644 (file)
index 0000000..eeb1345
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Fake asm file.
+int main() {}
diff --git a/gyp/test/rules/src/as.bat b/gyp/test/rules/src/as.bat
new file mode 100644 (file)
index 0000000..903c31a
--- /dev/null
@@ -0,0 +1,7 @@
+@echo off\r
+:: Copyright (c) 2011 Google Inc. All rights reserved.\r
+:: Use of this source code is governed by a BSD-style license that can be\r
+:: found in the LICENSE file.\r
+\r
+:: Fake assembler for Windows\r
+cl /TP /c %1 /Fo%2\r
diff --git a/gyp/test/rules/src/copy-file.py b/gyp/test/rules/src/copy-file.py
new file mode 100755 (executable)
index 0000000..5a5feae
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import sys
+
+contents = open(sys.argv[1], 'r').read()
+open(sys.argv[2], 'wb').write(contents)
+
+sys.exit(0)
diff --git a/gyp/test/rules/src/external/external.gyp b/gyp/test/rules/src/external/external.gyp
new file mode 100644 (file)
index 0000000..b28174f
--- /dev/null
@@ -0,0 +1,66 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Test that the case where there are no inputs (other than the
+# file the rule applies to).
+{
+  'target_defaults': {
+    'msvs_cygwin_dirs': ['../../../../../../<(DEPTH)/third_party/cygwin'],
+  },
+  'targets': [
+    {
+      'target_name': 'external_rules',
+      'type': 'none',
+      'sources': [
+        'file1.in',
+        'file2.in',
+      ],
+      'conditions': [
+        ['OS=="win"', {
+          'dependencies': [
+            'cygwin',
+          ],
+        }],
+      ],
+      'rules': [
+        {
+          'rule_name': 'copy_file',
+          'extension': 'in',
+          'msvs_external_rule': 1,
+          'outputs': [
+            '<(RULE_INPUT_ROOT).external_rules.out',
+          ],
+          'action': [
+            'python', '../copy-file.py', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+        },
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="win"', {
+      'targets': [
+        {
+          'target_name': 'cygwin',
+          'type': 'none',
+          'actions': [
+            {
+              'action_name': 'setup_mount',
+              'msvs_cygwin_shell': 0,
+              'inputs': [
+                '../../../../../../<(DEPTH)/third_party/cygwin/setup_mount.bat',
+              ],
+              # Visual Studio requires an output file, or else the
+              # custom build step won't run.
+              'outputs': [
+                '<(INTERMEDIATE_DIR)/_always_run_setup_mount.marker',
+              ],
+              'action': ['<@(_inputs)'],
+            },
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/gyp/test/rules/src/external/file1.in b/gyp/test/rules/src/external/file1.in
new file mode 100644 (file)
index 0000000..86ac3ad
--- /dev/null
@@ -0,0 +1 @@
+Hello from file1.in
diff --git a/gyp/test/rules/src/external/file2.in b/gyp/test/rules/src/external/file2.in
new file mode 100644 (file)
index 0000000..bf83d8e
--- /dev/null
@@ -0,0 +1 @@
+Hello from file2.in
diff --git a/gyp/test/rules/src/input-root.gyp b/gyp/test/rules/src/input-root.gyp
new file mode 100644 (file)
index 0000000..b6600e7
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'test',
+      'type': 'executable',
+      'sources': [ 'somefile.ext', ],
+      'rules': [{
+        'rule_name': 'rule',
+        'extension': 'ext',
+        'inputs': [ 'rule.py', ],
+        'outputs': [ '<(RULE_INPUT_ROOT).cc', ],
+        'action': [ 'python', 'rule.py', '<(RULE_INPUT_ROOT)', ],
+        'message': 'Processing <(RULE_INPUT_PATH)',
+        'process_outputs_as_sources': 1,
+        # Allows the test to run without hermetic cygwin on windows.
+        'msvs_cygwin_shell': 0,
+      }],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/noaction/file1.in b/gyp/test/rules/src/noaction/file1.in
new file mode 100644 (file)
index 0000000..86ac3ad
--- /dev/null
@@ -0,0 +1 @@
+Hello from file1.in
diff --git a/gyp/test/rules/src/noaction/no_action_with_rules_fails.gyp b/gyp/test/rules/src/noaction/no_action_with_rules_fails.gyp
new file mode 100644 (file)
index 0000000..9b6a656
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Test the case where there's no action but there are input rules that should
+# be processed results in a gyp failure.
+{
+  'targets': [
+    {
+      'target_name': 'extension_does_match_sources_but_no_action',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'file1.in',
+      ],
+      'rules': [
+        {
+          'rule_name': 'assembled',
+          'extension': 'in',
+          'outputs': [
+            '<(RULE_INPUT_ROOT).in',
+          ],
+          'conditions': [
+            # Always fails.
+            [ '"true"=="false"', {
+              'action': [
+                'python', '../copy-file.py', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+              ],
+              'process_outputs_as_sources': 1,
+              'message': 'test_rule',
+            }],
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/rule.py b/gyp/test/rules/src/rule.py
new file mode 100755 (executable)
index 0000000..8a1f36d
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+f = open(sys.argv[1] + ".cc", "w")
+f.write("""\
+#include <stdio.h>
+
+int main() {
+  puts("Hello %s");
+  return 0;
+}
+""" % sys.argv[1])
+f.close()
diff --git a/gyp/test/rules/src/somefile.ext b/gyp/test/rules/src/somefile.ext
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/rules/src/special-variables.gyp b/gyp/test/rules/src/special-variables.gyp
new file mode 100644 (file)
index 0000000..d1443af
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'rules': [
+        {
+          'rule_name': 'assembler (gnu-compatible)',
+          'msvs_cygwin_shell': 0,
+          'msvs_quote_cmd': 0,
+          'extension': 'S',
+          'inputs': [
+            'as.bat',
+          ],
+          'outputs': [
+            '$(IntDir)/$(InputName).obj',
+          ],
+          'action': [
+            'as.bat',
+            '$(InputPath)',
+            '$(IntDir)/$(InputName).obj',
+          ],
+          'message': 'Building assembly language file $(InputPath)',
+          'process_outputs_as_sources': 1,
+        },
+      ],
+      'target_name': 'test',
+      'type': 'static_library',
+      'sources': [ 'an_asm.S' ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/subdir1/executable.gyp b/gyp/test/rules/src/subdir1/executable.gyp
new file mode 100644 (file)
index 0000000..c34cce5
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'program.c',
+        'function1.in',
+        'function2.in',
+      ],
+      'rules': [
+        {
+          'rule_name': 'copy_file',
+          'extension': 'in',
+          'inputs': [
+            '../copy-file.py',
+          ],
+          'outputs': [
+            # TODO:  fix Make to support generated files not
+            # in a variable-named path like <(INTERMEDIATE_DIR)
+            #'<(RULE_INPUT_ROOT).c',
+            '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).c',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/subdir1/function1.in b/gyp/test/rules/src/subdir1/function1.in
new file mode 100644 (file)
index 0000000..60ff289
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void function1(void)
+{
+  printf("Hello from function1.in\n");
+}
diff --git a/gyp/test/rules/src/subdir1/function2.in b/gyp/test/rules/src/subdir1/function2.in
new file mode 100644 (file)
index 0000000..0fcfc03
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void function2(void)
+{
+  printf("Hello from function2.in\n");
+}
diff --git a/gyp/test/rules/src/subdir1/program.c b/gyp/test/rules/src/subdir1/program.c
new file mode 100644 (file)
index 0000000..6b11ff9
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern void function1(void);
+extern void function2(void);
+
+int main(void)
+{
+  printf("Hello from program.c\n");
+  function1();
+  function2();
+  return 0;
+}
diff --git a/gyp/test/rules/src/subdir2/both_rule_and_action_input.gyp b/gyp/test/rules/src/subdir2/both_rule_and_action_input.gyp
new file mode 100644 (file)
index 0000000..e5e6f3e
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Tests that if a rule input is also an action input, both the rule and action
+# are executed
+{
+  'targets': [
+    {
+      'target_name': 'files_both_rule_and_action_input',
+      'type': 'executable',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'program.c',
+        'file1.in',
+        'file2.in',
+      ],
+      'rules': [
+        {
+          'rule_name': 'copy_file',
+          'extension': 'in',
+          'inputs': [
+            '../copy-file.py',
+          ],
+          'outputs': [
+            '<(RULE_INPUT_ROOT).out4',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+        },
+      ],
+      'actions': [
+        {
+          'action_name': 'copy_file1_in',
+          'inputs': [
+            '../copy-file.py',
+            'file1.in',
+          ],
+          'outputs': [
+            'file1.copy',
+          ],
+          'action': [
+            'python', '<@(_inputs)', '<(_outputs)'
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/subdir2/file1.in b/gyp/test/rules/src/subdir2/file1.in
new file mode 100644 (file)
index 0000000..86ac3ad
--- /dev/null
@@ -0,0 +1 @@
+Hello from file1.in
diff --git a/gyp/test/rules/src/subdir2/file2.in b/gyp/test/rules/src/subdir2/file2.in
new file mode 100644 (file)
index 0000000..bf83d8e
--- /dev/null
@@ -0,0 +1 @@
+Hello from file2.in
diff --git a/gyp/test/rules/src/subdir2/never_used.gyp b/gyp/test/rules/src/subdir2/never_used.gyp
new file mode 100644 (file)
index 0000000..17f6f55
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Test that the case where there is a rule that doesn't apply to anything.
+{
+  'targets': [
+    {
+      'target_name': 'files_no_input2',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'file1.in',
+        'file2.in',
+      ],
+      'rules': [
+        {
+          'rule_name': 'copy_file3',
+          'extension': 'in2',
+          'outputs': [
+            '<(RULE_INPUT_ROOT).out3',
+          ],
+          'action': [
+            'python', '../copy-file.py', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/subdir2/no_action.gyp b/gyp/test/rules/src/subdir2/no_action.gyp
new file mode 100644 (file)
index 0000000..ffa1cef
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Test that the case where an action is only specified under a conditional is
+# evaluated appropriately.
+{
+  'targets': [
+    {
+      'target_name': 'extension_does_not_match_sources_and_no_action',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'file1.in',
+        'file2.in',
+      ],
+      'rules': [
+        {
+          'rule_name': 'assemble',
+          'extension': 'asm',
+          'outputs': [
+            '<(RULE_INPUT_ROOT).fail',
+          ],
+          'conditions': [
+            # Always fails.
+            [ '"true"=="false"', {
+              'action': [
+                'python', '../copy-file.py', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+              ],
+              'process_outputs_as_sources': 1,
+              'message': 'test_rule',
+            }],
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/subdir2/no_inputs.gyp b/gyp/test/rules/src/subdir2/no_inputs.gyp
new file mode 100644 (file)
index 0000000..e61a1a3
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Test that the case where there are no inputs (other than the
+# file the rule applies to).
+{
+  'targets': [
+    {
+      'target_name': 'files_no_input',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'file1.in',
+        'file2.in',
+      ],
+      'rules': [
+        {
+          'rule_name': 'copy_file2',
+          'extension': 'in',
+          'outputs': [
+            '<(RULE_INPUT_ROOT).out2',
+          ],
+          'action': [
+            'python', '../copy-file.py', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/subdir2/none.gyp b/gyp/test/rules/src/subdir2/none.gyp
new file mode 100644 (file)
index 0000000..38bcdab
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'files',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'file1.in',
+        'file2.in',
+      ],
+      'rules': [
+        {
+          'rule_name': 'copy_file',
+          'extension': 'in',
+          'inputs': [
+            '../copy-file.py',
+          ],
+          'outputs': [
+            '<(RULE_INPUT_ROOT).out',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/subdir2/program.c b/gyp/test/rules/src/subdir2/program.c
new file mode 100644 (file)
index 0000000..e5db175
--- /dev/null
@@ -0,0 +1,12 @@
+/* Copyright (c) 2014 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from program.c\n");
+  return 0;
+}
diff --git a/gyp/test/rules/src/subdir3/executable2.gyp b/gyp/test/rules/src/subdir3/executable2.gyp
new file mode 100644 (file)
index 0000000..a2a528f
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This one tests that rules are properly written if extensions are different
+# between the target's sources (program.c) and the generated files
+# (function3.cc)
+
+{
+  'targets': [
+    {
+      'target_name': 'program2',
+      'type': 'executable',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'program.c',
+        'function3.in',
+      ],
+      'rules': [
+        {
+          'rule_name': 'copy_file',
+          'extension': 'in',
+          'inputs': [
+            '../copy-file.py',
+          ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).cc',
+          ],
+          'action': [
+            'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+          ],
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/subdir3/function3.in b/gyp/test/rules/src/subdir3/function3.in
new file mode 100644 (file)
index 0000000..99f46ab
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+extern "C" void function3(void)
+{
+  printf("Hello from function3.in\n");
+}
diff --git a/gyp/test/rules/src/subdir3/program.c b/gyp/test/rules/src/subdir3/program.c
new file mode 100644 (file)
index 0000000..c38eead
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void function3(void);
+
+int main(void)
+{
+  printf("Hello from program.c\n");
+  function3();
+  return 0;
+}
diff --git a/gyp/test/rules/src/subdir4/asm-function.assem b/gyp/test/rules/src/subdir4/asm-function.assem
new file mode 100644 (file)
index 0000000..ed47cad
--- /dev/null
@@ -0,0 +1,10 @@
+#if PLATFORM_WINDOWS || PLATFORM_MAC
+# define IDENTIFIER(n)  _##n
+#else /* Linux */
+# define IDENTIFIER(n)  n
+#endif
+
+.globl IDENTIFIER(asm_function)
+IDENTIFIER(asm_function):
+  movl $41, %eax
+  ret
diff --git a/gyp/test/rules/src/subdir4/build-asm.gyp b/gyp/test/rules/src/subdir4/build-asm.gyp
new file mode 100644 (file)
index 0000000..6b9505b
--- /dev/null
@@ -0,0 +1,49 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This one tests that assembly files ended as .s and .S are compiled.
+
+{
+  'target_defaults': {
+    'conditions': [
+      ['OS=="win"', {
+        'defines': ['PLATFORM_WIN'],
+      }],
+      ['OS=="mac"', {
+        'defines': ['PLATFORM_MAC'],
+      }],
+      ['OS=="linux"', {
+        'defines': ['PLATFORM_LINUX'],
+      }],
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'program4',
+      'type': 'executable',
+      'sources': [
+        'asm-function.assem',
+        'program.c',
+      ],
+      'conditions': [
+        ['OS=="linux" or OS=="mac"', {
+          'rules': [
+            {
+              'rule_name': 'convert_assem',
+              'extension': 'assem',
+              'inputs': [],
+              'outputs': [
+                '<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).S',
+              ],
+              'action': [
+               'bash', '-c', 'mv <(RULE_INPUT_PATH) <@(_outputs)',
+              ],
+              'process_outputs_as_sources': 1,
+            },
+          ],
+        }],
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/rules/src/subdir4/program.c b/gyp/test/rules/src/subdir4/program.c
new file mode 100644 (file)
index 0000000..ad647f4
--- /dev/null
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+// Use the assembly function in linux and mac where it is built.
+#if PLATFORM_LINUX || PLATFORM_MAC
+extern int asm_function(void);
+#else
+int asm_function() {
+  return 41;
+}
+#endif
+
+int main(void)
+{
+  fprintf(stdout, "Hello from program.c\n");
+  fflush(stdout);
+  fprintf(stdout, "Got %d.\n", asm_function());
+  fflush(stdout);
+  return 0;
+}
diff --git a/gyp/test/same-gyp-name/gyptest-all.py b/gyp/test/same-gyp-name/gyptest-all.py
new file mode 100755 (executable)
index 0000000..cda1a72
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Build a .gyp that depends on 2 gyp files with the same name.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('all.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+expect1 = """\
+Hello from main1.cc
+"""
+
+expect2 = """\
+Hello from main2.cc
+"""
+
+if test.format == 'xcode':
+  chdir1 = 'relocate/src/subdir1'
+  chdir2 = 'relocate/src/subdir2'
+else:
+  chdir1 = chdir2 = 'relocate/src'
+
+test.run_built_executable('program1', chdir=chdir1, stdout=expect1)
+test.run_built_executable('program2', chdir=chdir2, stdout=expect2)
+
+test.pass_test()
diff --git a/gyp/test/same-gyp-name/gyptest-default.py b/gyp/test/same-gyp-name/gyptest-default.py
new file mode 100755 (executable)
index 0000000..5e4bba0
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Build a .gyp that depends on 2 gyp files with the same name.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('all.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', chdir='relocate/src')
+
+expect1 = """\
+Hello from main1.cc
+"""
+
+expect2 = """\
+Hello from main2.cc
+"""
+
+if test.format == 'xcode':
+  chdir1 = 'relocate/src/subdir1'
+  chdir2 = 'relocate/src/subdir2'
+else:
+  chdir1 = chdir2 = 'relocate/src'
+
+test.run_built_executable('program1', chdir=chdir1, stdout=expect1)
+test.run_built_executable('program2', chdir=chdir2, stdout=expect2)
+
+test.pass_test()
diff --git a/gyp/test/same-gyp-name/gyptest-library.py b/gyp/test/same-gyp-name/gyptest-library.py
new file mode 100644 (file)
index 0000000..957a4a5
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a dependency on two gyp files with the same name do not create a
+uid collision in the resulting generated xcode file.
+"""
+
+import TestGyp
+
+import sys
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('test.gyp', chdir='library')
+
+test.pass_test()
diff --git a/gyp/test/same-gyp-name/library/one/sub.gyp b/gyp/test/same-gyp-name/library/one/sub.gyp
new file mode 100644 (file)
index 0000000..1bed941
--- /dev/null
@@ -0,0 +1,11 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'one',
+      'type': 'static_library',
+    },
+  ],
+}
diff --git a/gyp/test/same-gyp-name/library/test.gyp b/gyp/test/same-gyp-name/library/test.gyp
new file mode 100644 (file)
index 0000000..552a77e
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'duplicate_names',
+      'type': 'shared_library',
+      'dependencies': [
+        'one/sub.gyp:one',
+        'two/sub.gyp:two',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-gyp-name/library/two/sub.gyp b/gyp/test/same-gyp-name/library/two/sub.gyp
new file mode 100644 (file)
index 0000000..934c98a
--- /dev/null
@@ -0,0 +1,11 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'two',
+      'type': 'static_library',
+    },
+  ],
+}
diff --git a/gyp/test/same-gyp-name/src/all.gyp b/gyp/test/same-gyp-name/src/all.gyp
new file mode 100644 (file)
index 0000000..229f02e
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'all_exes',
+      'type': 'none',
+      'dependencies': [
+        'subdir1/executable.gyp:*',
+        'subdir2/executable.gyp:*',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-gyp-name/src/subdir1/executable.gyp b/gyp/test/same-gyp-name/src/subdir1/executable.gyp
new file mode 100644 (file)
index 0000000..82483b4
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program1',
+      'type': 'executable',
+      'sources': [
+        'main1.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-gyp-name/src/subdir1/main1.cc b/gyp/test/same-gyp-name/src/subdir1/main1.cc
new file mode 100644 (file)
index 0000000..3645558
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main() {
+  printf("Hello from main1.cc\n");
+  return 0;
+}
diff --git a/gyp/test/same-gyp-name/src/subdir2/executable.gyp b/gyp/test/same-gyp-name/src/subdir2/executable.gyp
new file mode 100644 (file)
index 0000000..e353701
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program2',
+      'type': 'executable',
+      'sources': [
+        'main2.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-gyp-name/src/subdir2/main2.cc b/gyp/test/same-gyp-name/src/subdir2/main2.cc
new file mode 100644 (file)
index 0000000..0c724de
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main() {
+  printf("Hello from main2.cc\n");
+  return 0;
+}
diff --git a/gyp/test/same-rule-output-file-name/gyptest-all.py b/gyp/test/same-rule-output-file-name/gyptest-all.py
new file mode 100644 (file)
index 0000000..964e6b7
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests the use of rules with the same output file name.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('subdirs.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('subdirs.gyp', test.ALL, chdir='relocate/src')
+test.must_exist('relocate/src/subdir1/rule.txt')
+test.must_exist('relocate/src/subdir2/rule.txt')
+
+test.pass_test()
diff --git a/gyp/test/same-rule-output-file-name/src/subdir1/subdir1.gyp b/gyp/test/same-rule-output-file-name/src/subdir1/subdir1.gyp
new file mode 100644 (file)
index 0000000..bff381a
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'target1',
+      'type': 'none',
+      'sources': [
+        '../touch.py'
+      ],
+      'rules': [
+        {
+          'rule_name': 'rule1',
+          'extension': 'py',
+          'inputs': [],
+          'outputs': [
+            'rule.txt',
+          ],
+          'action': [
+            'python', '../touch.py', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-rule-output-file-name/src/subdir2/subdir2.gyp b/gyp/test/same-rule-output-file-name/src/subdir2/subdir2.gyp
new file mode 100644 (file)
index 0000000..12a3560
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'target2',
+      'type': 'none',
+      'sources': [
+        '../touch.py'
+      ],
+      'rules': [
+        {
+          'rule_name': 'rule2',
+          'extension': 'py',
+          'inputs': [],
+          'outputs': [
+            'rule.txt',
+          ],
+          'action': [
+            'python', '../touch.py', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-rule-output-file-name/src/subdirs.gyp b/gyp/test/same-rule-output-file-name/src/subdirs.gyp
new file mode 100644 (file)
index 0000000..25259a3
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'subdirs',
+      'type': 'none',
+      'dependencies': [
+        'subdir1/subdir1.gyp:*',
+        'subdir2/subdir2.gyp:*',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-rule-output-file-name/src/touch.py b/gyp/test/same-rule-output-file-name/src/touch.py
new file mode 100644 (file)
index 0000000..2291e9c
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+f = open(sys.argv[1], 'w+')
+f.write('Hello from touch.py\n')
+f.close()
diff --git a/gyp/test/same-source-file-name/gyptest-all.py b/gyp/test/same-source-file-name/gyptest-all.py
new file mode 100755 (executable)
index 0000000..4c21502
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Build a .gyp with two targets that share a common .c source file.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('all.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+expect1 = """\
+Hello from prog1.c
+Hello prog1 from func.c
+"""
+
+expect2 = """\
+Hello from prog2.c
+Hello prog2 from func.c
+"""
+
+test.run_built_executable('prog1', chdir='relocate/src', stdout=expect1)
+test.run_built_executable('prog2', chdir='relocate/src', stdout=expect2)
+
+test.pass_test()
diff --git a/gyp/test/same-source-file-name/gyptest-default.py b/gyp/test/same-source-file-name/gyptest-default.py
new file mode 100755 (executable)
index 0000000..98757c2
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Build a .gyp with two targets that share a common .c source file.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('all.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', chdir='relocate/src')
+
+expect1 = """\
+Hello from prog1.c
+Hello prog1 from func.c
+"""
+
+expect2 = """\
+Hello from prog2.c
+Hello prog2 from func.c
+"""
+
+test.run_built_executable('prog1', chdir='relocate/src', stdout=expect1)
+test.run_built_executable('prog2', chdir='relocate/src', stdout=expect2)
+
+test.pass_test()
diff --git a/gyp/test/same-source-file-name/gyptest-pass-executable.py b/gyp/test/same-source-file-name/gyptest-pass-executable.py
new file mode 100755 (executable)
index 0000000..1a3dcda
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Checks that gyp does not fail on executable targets which have several files
+with the same basename.
+"""
+
+import TestGyp
+
+# While MSVS supports building executables that contain several files with the
+# same name, the msvs gyp generator does not.
+test = TestGyp.TestGyp(formats=['!msvs'])
+
+test.run_gyp('double-executable.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('double-executable.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from prog3.c
+Hello prog3 from func.c
+Hello prog3 from subdir1/func.c
+Hello prog3 from subdir2/func.c
+"""
+
+test.run_built_executable('prog3', chdir='relocate/src', stdout=expect)
+
+test.pass_test()
diff --git a/gyp/test/same-source-file-name/gyptest-shared.py b/gyp/test/same-source-file-name/gyptest-shared.py
new file mode 100755 (executable)
index 0000000..a57eb61
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Checks that gyp fails on shared_library targets which have several files with
+the same basename.
+"""
+
+import os
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# Fails by default for the compatibility with Visual C++ 2008 generator.
+# TODO: Update expected behavior when these legacy generators are deprecated.
+test.run_gyp('double-shared.gyp', chdir='src', status=1, stderr=None)
+
+if ((test.format == 'msvs') and
+       (int(os.environ.get('GYP_MSVS_VERSION', 2010)) < 2010)):
+  test.run_gyp('double-shared.gyp', '--no-duplicate-basename-check',
+               chdir='src', status=0, stderr=None)
+else:
+  test.run_gyp('double-shared.gyp', '--no-duplicate-basename-check',
+               chdir='src')
+  test.build('double-shared.gyp', test.ALL, chdir='src')
+
+test.pass_test()
diff --git a/gyp/test/same-source-file-name/gyptest-static.py b/gyp/test/same-source-file-name/gyptest-static.py
new file mode 100755 (executable)
index 0000000..7fa2772
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Checks that gyp fails on static_library targets which have several files with
+the same basename.
+"""
+
+import os
+import sys
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# Fails by default for the compatibility with legacy generators such as
+# VCProj generator for Visual C++ 2008 and Makefile generator on Mac.
+# TODO: Update expected behavior when these legacy generators are deprecated.
+test.run_gyp('double-static.gyp', chdir='src', status=1, stderr=None)
+
+if ((test.format == 'make' and sys.platform == 'darwin') or
+    (test.format == 'msvs' and
+        int(os.environ.get('GYP_MSVS_VERSION', 2010)) < 2010)):
+  test.run_gyp('double-static.gyp', '--no-duplicate-basename-check',
+               chdir='src', status=1, stderr=None)
+else:
+  test.run_gyp('double-static.gyp', '--no-duplicate-basename-check',
+               chdir='src')
+  test.build('double-static.gyp', test.ALL, chdir='src')
+
+test.pass_test()
diff --git a/gyp/test/same-source-file-name/src/all.gyp b/gyp/test/same-source-file-name/src/all.gyp
new file mode 100644 (file)
index 0000000..4fe052c
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'prog1',
+      'type': 'executable',
+      'defines': [
+        'PROG="prog1"',
+      ],
+      'sources': [
+        'prog1.c',
+        'func.c',
+      ],
+    },
+    {
+      'target_name': 'prog2',
+      'type': 'executable',
+      'defines': [
+        'PROG="prog2"',
+      ],
+      'sources': [
+        'prog2.c',
+        'func.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-source-file-name/src/double-executable.gyp b/gyp/test/same-source-file-name/src/double-executable.gyp
new file mode 100644 (file)
index 0000000..477bd87
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'prog3',
+      'type': 'executable',
+      'sources': [
+        'prog3.c',
+        'func.c',
+        'subdir1/func.c',
+        'subdir2/func.c',
+      ],
+      'defines': [
+        'PROG="prog3"',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-source-file-name/src/double-shared.gyp b/gyp/test/same-source-file-name/src/double-shared.gyp
new file mode 100644 (file)
index 0000000..438b50f
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'lib',
+      'product_name': 'test_shared_lib',
+      'type': 'shared_library',
+      'sources': [
+        'prog2.c',
+        'func.c',
+        'subdir1/func.c',
+        'subdir2/func.c',
+      ],
+      'defines': [
+        'PROG="prog2"',
+      ],
+      'conditions': [
+        ['OS=="linux"', {
+          'cflags': ['-fPIC'],
+        }],
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-source-file-name/src/double-static.gyp b/gyp/test/same-source-file-name/src/double-static.gyp
new file mode 100644 (file)
index 0000000..e49c0e1
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'lib',
+      'product_name': 'test_static_lib',
+      'type': 'static_library',
+      'sources': [
+        'prog1.c',
+        'func.c',
+        'subdir1/func.c',
+        'subdir2/func.c',
+      ],
+      'defines': [
+        'PROG="prog1"',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-source-file-name/src/func.c b/gyp/test/same-source-file-name/src/func.c
new file mode 100644 (file)
index 0000000..e069c69
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func(void)
+{
+  printf("Hello %s from func.c\n", PROG);
+}
diff --git a/gyp/test/same-source-file-name/src/prog1.c b/gyp/test/same-source-file-name/src/prog1.c
new file mode 100644 (file)
index 0000000..604e2b9
--- /dev/null
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void func(void);
+
+int main(void)
+{
+  printf("Hello from prog1.c\n");
+  func();
+  /*
+   * Uncomment to test same-named files in different directories,
+   * which Visual Studio doesn't support.
+  subdir1_func();
+  subdir2_func();
+   */
+  return 0;
+}
diff --git a/gyp/test/same-source-file-name/src/prog2.c b/gyp/test/same-source-file-name/src/prog2.c
new file mode 100644 (file)
index 0000000..466ee35
--- /dev/null
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void func(void);
+
+int main(void)
+{
+  printf("Hello from prog2.c\n");
+  func();
+  /*
+   * Uncomment to test same-named files in different directories,
+   * which Visual Studio doesn't support.
+  subdir1_func();
+  subdir2_func();
+   */
+  return 0;
+}
diff --git a/gyp/test/same-source-file-name/src/prog3.c b/gyp/test/same-source-file-name/src/prog3.c
new file mode 100644 (file)
index 0000000..34d495c
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+extern void func(void);
+extern void subdir1_func(void);
+extern void subdir2_func(void);
+
+int main(void)
+{
+  printf("Hello from prog3.c\n");
+  func();
+  subdir1_func();
+  subdir2_func();
+  return 0;
+}
diff --git a/gyp/test/same-source-file-name/src/subdir1/func.c b/gyp/test/same-source-file-name/src/subdir1/func.c
new file mode 100644 (file)
index 0000000..b73450d
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void subdir1_func(void)
+{
+  printf("Hello %s from subdir1/func.c\n", PROG);
+}
diff --git a/gyp/test/same-source-file-name/src/subdir2/func.c b/gyp/test/same-source-file-name/src/subdir2/func.c
new file mode 100644 (file)
index 0000000..0248b57
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void subdir2_func(void)
+{
+  printf("Hello %s from subdir2/func.c\n", PROG);
+}
diff --git a/gyp/test/same-target-name-different-directory/gyptest-all.py b/gyp/test/same-target-name-different-directory/gyptest-all.py
new file mode 100644 (file)
index 0000000..bc4f466
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test cases when multiple targets in different directories have the same name.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['android', 'ninja', 'make'])
+
+test.run_gyp('subdirs.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Test that we build all targets.
+test.build('subdirs.gyp', 'target', chdir='relocate/src')
+test.must_exist('relocate/src/subdir1/action1.txt')
+test.must_exist('relocate/src/subdir2/action2.txt')
+
+# Test that we build all targets using the correct actions, even if they have
+# the same names.
+test.build('subdirs.gyp', 'target_same_action_name', chdir='relocate/src')
+test.must_exist('relocate/src/subdir1/action.txt')
+test.must_exist('relocate/src/subdir2/action.txt')
+
+# Test that we build all targets using the correct rules, even if they have
+# the same names.
+test.build('subdirs.gyp', 'target_same_rule_name', chdir='relocate/src')
+test.must_exist('relocate/src/subdir1/rule.txt')
+test.must_exist('relocate/src/subdir2/rule.txt')
+
+test.pass_test()
diff --git a/gyp/test/same-target-name-different-directory/src/subdir1/subdir1.gyp b/gyp/test/same-target-name-different-directory/src/subdir1/subdir1.gyp
new file mode 100644 (file)
index 0000000..d4ec2e6
--- /dev/null
@@ -0,0 +1,66 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'target',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'action1',
+          'inputs': [],
+          'outputs': [
+            'action1.txt',
+          ],
+          'action': [
+            'python', '../touch.py', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+    {
+      'target_name': 'target_same_action_name',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'action',
+          'inputs': [],
+          'outputs': [
+            'action.txt',
+          ],
+          'action': [
+            'python', '../touch.py', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+    {
+      'target_name': 'target_same_rule_name',
+      'type': 'none',
+      'sources': [
+        '../touch.py'
+      ],
+      'rules': [
+        {
+          'rule_name': 'rule',
+          'extension': 'py',
+          'inputs': [],
+          'outputs': [
+            'rule.txt',
+          ],
+          'action': [
+            'python', '../touch.py', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-target-name-different-directory/src/subdir2/subdir2.gyp b/gyp/test/same-target-name-different-directory/src/subdir2/subdir2.gyp
new file mode 100644 (file)
index 0000000..9006d45
--- /dev/null
@@ -0,0 +1,66 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'target',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'action2',
+          'inputs': [],
+          'outputs': [
+            'action2.txt',
+          ],
+          'action': [
+            'python', '../touch.py', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+    {
+      'target_name': 'target_same_action_name',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'action',
+          'inputs': [],
+          'outputs': [
+            'action.txt',
+          ],
+          'action': [
+            'python', '../touch.py', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+    {
+      'target_name': 'target_same_rule_name',
+      'type': 'none',
+      'sources': [
+        '../touch.py'
+      ],
+      'rules': [
+        {
+          'rule_name': 'rule',
+          'extension': 'py',
+          'inputs': [],
+          'outputs': [
+            'rule.txt',
+          ],
+          'action': [
+            'python', '../touch.py', '<(_outputs)',
+          ],
+          # Allows the test to run without hermetic cygwin on windows.
+          'msvs_cygwin_shell': 0,
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-target-name-different-directory/src/subdirs.gyp b/gyp/test/same-target-name-different-directory/src/subdirs.gyp
new file mode 100644 (file)
index 0000000..65413e7
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'subdirs',
+      'type': 'none',
+      'dependencies': [
+        'subdir1/subdir1.gyp:*',
+        'subdir2/subdir2.gyp:*',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-target-name-different-directory/src/touch.py b/gyp/test/same-target-name-different-directory/src/touch.py
new file mode 100644 (file)
index 0000000..2291e9c
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+f = open(sys.argv[1], 'w+')
+f.write('Hello from touch.py\n')
+f.close()
diff --git a/gyp/test/same-target-name/gyptest-same-target-name.py b/gyp/test/same-target-name/gyptest-same-target-name.py
new file mode 100755 (executable)
index 0000000..bfe5540
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Check that duplicate targets in a directory gives an error.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# Require that gyp files with duplicate targets spit out an error.
+test.run_gyp('all.gyp', chdir='src', status=1, stderr=None)
+
+test.pass_test()
diff --git a/gyp/test/same-target-name/src/all.gyp b/gyp/test/same-target-name/src/all.gyp
new file mode 100644 (file)
index 0000000..ac16976
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'all_exes',
+      'type': 'none',
+      'dependencies': [
+        'executable1.gyp:*',
+        'executable2.gyp:*',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-target-name/src/executable1.gyp b/gyp/test/same-target-name/src/executable1.gyp
new file mode 100644 (file)
index 0000000..3c492c1
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'sources': [
+        'main1.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/same-target-name/src/executable2.gyp b/gyp/test/same-target-name/src/executable2.gyp
new file mode 100644 (file)
index 0000000..41e84a6
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'sources': [
+        'main2.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/sanitize-rule-names/blah.S b/gyp/test/sanitize-rule-names/blah.S
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/sanitize-rule-names/gyptest-sanitize-rule-names.py b/gyp/test/sanitize-rule-names/gyptest-sanitize-rule-names.py
new file mode 100644 (file)
index 0000000..968a0ce
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure rule names with non-"normal" characters in them don't cause
+broken build files. This test was originally causing broken .ninja files.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+test.run_gyp('sanitize-rule-names.gyp')
+test.build('sanitize-rule-names.gyp', test.ALL)
+test.pass_test()
diff --git a/gyp/test/sanitize-rule-names/hello.cc b/gyp/test/sanitize-rule-names/hello.cc
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/sanitize-rule-names/sanitize-rule-names.gyp b/gyp/test/sanitize-rule-names/sanitize-rule-names.gyp
new file mode 100644 (file)
index 0000000..184253e
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 's_test',
+      'type': 'executable',
+      'rules': [
+        {
+          # Make sure this rule name doesn't cause an invalid ninja file.
+          'rule_name': 'rule name with odd characters ()/',
+          'extension': 'S',
+          'outputs': ['outfile'],
+          'msvs_cygwin_shell': 0,
+          'msvs_quote_cmd': 0,
+          'action': ['python', 'script.py', '<(RULE_INPUT_PATH)', 'outfile'],
+        },
+      ],
+      'sources': [
+        'blah.S',
+        'hello.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/sanitize-rule-names/script.py b/gyp/test/sanitize-rule-names/script.py
new file mode 100644 (file)
index 0000000..ae2efa1
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import shutil
+import sys
+
+shutil.copyfile(*sys.argv[1:])
diff --git a/gyp/test/self-dependency/common.gypi b/gyp/test/self-dependency/common.gypi
new file mode 100644 (file)
index 0000000..aae221a
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# A common file that other .gyp files include.
+# Makes every target in the project depend on dep.gyp:dep.
+{
+  'target_defaults': {
+    'dependencies': [
+      'dep.gyp:dep',
+    ],
+  },
+}
diff --git a/gyp/test/self-dependency/dep.gyp b/gyp/test/self-dependency/dep.gyp
new file mode 100644 (file)
index 0000000..2b6c9dd
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# dep.gyp contains a target dep, on which all the targets in the project
+# depend. This means there's a self-dependency of dep on itself, which is
+# pruned by setting prune_self_dependency to 1.
+
+{
+  'includes': [
+    'common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'dep',
+      'type': 'none',
+      'variables': {
+        # Without this GYP will report a cycle in dependency graph.
+        'prune_self_dependency': 1,
+      },
+    },
+  ],
+}
diff --git a/gyp/test/self-dependency/gyptest-self-dependency.py b/gyp/test/self-dependency/gyptest-self-dependency.py
new file mode 100755 (executable)
index 0000000..82fab27
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that pulling in a dependency a second time in a conditional works for
+shared_library targets. Regression test for http://crbug.com/122588
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('self_dependency.gyp')
+
+# If running gyp worked, all is well.
+test.pass_test()
diff --git a/gyp/test/self-dependency/self_dependency.gyp b/gyp/test/self-dependency/self_dependency.gyp
new file mode 100644 (file)
index 0000000..0ca76c6
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    'common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'a',
+      'type': 'none',
+    },
+  ],
+}
diff --git a/gyp/test/sibling/gyptest-all.py b/gyp/test/sibling/gyptest-all.py
new file mode 100755 (executable)
index 0000000..4fa8e97
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('build/all.gyp', chdir='src')
+
+test.build('build/all.gyp', test.ALL, chdir='src')
+
+chdir = 'src/build'
+
+# The top-level Makefile is in the directory where gyp was run.
+# TODO(mmoss) Should the Makefile go in the directory of the passed in .gyp
+# file? What about when passing in multiple .gyp files? Would sub-project
+# Makefiles (see http://codereview.chromium.org/340008 comments) solve this?
+if test.format in ('make', 'ninja', 'cmake'):
+  chdir = 'src'
+
+if test.format == 'xcode':
+  chdir = 'src/prog1'
+test.run_built_executable('program1',
+                          chdir=chdir,
+                          stdout="Hello from prog1.c\n")
+
+if test.format == 'xcode':
+  chdir = 'src/prog2'
+test.run_built_executable('program2',
+                          chdir=chdir,
+                          stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/gyp/test/sibling/gyptest-relocate.py b/gyp/test/sibling/gyptest-relocate.py
new file mode 100755 (executable)
index 0000000..7296d72
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('build/all.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('build/all.gyp', test.ALL, chdir='relocate/src')
+
+chdir = 'relocate/src/build'
+
+# The top-level Makefile is in the directory where gyp was run.
+# TODO(mmoss) Should the Makefile go in the directory of the passed in .gyp
+# file? What about when passing in multiple .gyp files? Would sub-project
+# Makefiles (see http://codereview.chromium.org/340008 comments) solve this?
+if test.format in ('make', 'ninja', 'cmake'):
+  chdir = 'relocate/src'
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/prog1'
+test.run_built_executable('program1',
+                          chdir=chdir,
+                          stdout="Hello from prog1.c\n")
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/prog2'
+test.run_built_executable('program2',
+                          chdir=chdir,
+                          stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/gyp/test/sibling/src/build/all.gyp b/gyp/test/sibling/src/build/all.gyp
new file mode 100644 (file)
index 0000000..79c80c9
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'All',
+      'type': 'none',
+      'dependencies': [
+        '../prog1/prog1.gyp:*',
+        '../prog2/prog2.gyp:*',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/sibling/src/prog1/prog1.c b/gyp/test/sibling/src/prog1/prog1.c
new file mode 100644 (file)
index 0000000..218e994
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from prog1.c\n");
+  return 0;
+}
diff --git a/gyp/test/sibling/src/prog1/prog1.gyp b/gyp/test/sibling/src/prog1/prog1.gyp
new file mode 100644 (file)
index 0000000..4532e4b
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program1',
+      'type': 'executable',
+      'sources': [
+        'prog1.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/sibling/src/prog2/prog2.c b/gyp/test/sibling/src/prog2/prog2.c
new file mode 100644 (file)
index 0000000..12a3188
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from prog2.c\n");
+  return 0;
+}
diff --git a/gyp/test/sibling/src/prog2/prog2.gyp b/gyp/test/sibling/src/prog2/prog2.gyp
new file mode 100644 (file)
index 0000000..4cf7f6e
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program2',
+      'type': 'executable',
+      'sources': [
+        'prog2.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/small/gyptest-small.py b/gyp/test/small/gyptest-small.py
new file mode 100755 (executable)
index 0000000..a8d61fb
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Runs small tests.
+"""
+
+import imp
+import os
+import sys
+import unittest
+
+import TestGyp
+
+
+test = TestGyp.TestGyp()
+
+# Add pylib to the import path (so tests can import their dependencies).
+# This is consistant with the path.append done in the top file "gyp".
+sys.path.append(os.path.join(test._cwd, 'pylib'))
+
+# Add new test suites here.
+files_to_test = [
+    'pylib/gyp/MSVSSettings_test.py',
+    'pylib/gyp/easy_xml_test.py',
+    'pylib/gyp/generator/msvs_test.py',
+    'pylib/gyp/generator/ninja_test.py',
+    'pylib/gyp/generator/xcode_test.py',
+    'pylib/gyp/common_test.py',
+    'pylib/gyp/input_test.py',
+]
+
+# Collect all the suites from the above files.
+suites = []
+for filename in files_to_test:
+  # Carve the module name out of the path.
+  name = os.path.splitext(os.path.split(filename)[1])[0]
+  # Find the complete module path.
+  full_filename = os.path.join(test._cwd, filename)
+  # Load the module.
+  module = imp.load_source(name, full_filename)
+  # Add it to the list of test suites.
+  suites.append(unittest.defaultTestLoader.loadTestsFromModule(module))
+# Create combined suite.
+all_tests = unittest.TestSuite(suites)
+
+# Run all the tests.
+result = unittest.TextTestRunner(verbosity=2).run(all_tests)
+if result.failures or result.errors:
+  test.fail_test()
+
+test.pass_test()
diff --git a/gyp/test/standalone-static-library/gyptest-standalone-static-library.py b/gyp/test/standalone-static-library/gyptest-standalone-static-library.py
new file mode 100644 (file)
index 0000000..ff12570
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of a static_library with the standalone_static_library flag set.
+"""
+
+import os
+import subprocess
+import sys
+import TestGyp
+
+# standalone_static_library currently means two things: a specific output
+# location for the built target and non-thin archive files. The Android gyp
+# generator leaves both decisions to the Android build system, so this test
+# doesn't work for that format.
+test = TestGyp.TestGyp(formats=['!android'])
+
+# Verify that types other than static_library cause a failure.
+test.run_gyp('invalid.gyp', status=1, stderr=None)
+target_str = 'invalid.gyp:bad#target'
+err = ['gyp: Target %s has type executable but standalone_static_library flag '
+       'is only valid for static_library type.' % target_str]
+test.must_contain_all_lines(test.stderr(), err)
+
+# Build a valid standalone_static_library.
+test.run_gyp('mylib.gyp')
+test.build('mylib.gyp', target='prog')
+
+# Verify that the static library is copied to the correct location.
+# We expect the library to be copied to $PRODUCT_DIR.
+standalone_static_library_dir = test.EXECUTABLE
+path_to_lib = os.path.split(
+    test.built_file_path('mylib', type=standalone_static_library_dir))[0]
+lib_name = test.built_file_basename('mylib', type=test.STATIC_LIB)
+path = os.path.join(path_to_lib, lib_name)
+test.must_exist(path)
+
+# Verify that the program runs properly.
+expect = 'hello from mylib.c\n'
+test.run_built_executable('prog', stdout=expect)
+
+# Verify that libmylib.a contains symbols.  "ar -x" fails on a 'thin' archive.
+supports_thick = ('make', 'ninja', 'cmake')
+if test.format in supports_thick and sys.platform.startswith('linux'):
+  retcode = subprocess.call(['ar', '-x', path])
+  assert retcode == 0
+
+test.pass_test()
diff --git a/gyp/test/standalone-static-library/invalid.gyp b/gyp/test/standalone-static-library/invalid.gyp
new file mode 100644 (file)
index 0000000..54b3211
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'bad',
+      'type': 'executable',
+      'standalone_static_library': 1,
+      'sources': [
+        'prog.c',
+      ],
+    },
+  ],
+}
\ No newline at end of file
diff --git a/gyp/test/standalone-static-library/mylib.c b/gyp/test/standalone-static-library/mylib.c
new file mode 100644 (file)
index 0000000..108be61
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void print(void)
+{
+  printf("hello from mylib.c\n");
+  return;
+}
diff --git a/gyp/test/standalone-static-library/mylib.gyp b/gyp/test/standalone-static-library/mylib.gyp
new file mode 100644 (file)
index 0000000..2d191de
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'mylib',
+      'type': 'static_library',
+      'standalone_static_library': 1,
+      'sources': [
+        'mylib.c',
+      ],
+    },
+    {
+      'target_name': 'prog',
+      'type': 'executable',
+      'sources': [
+        'prog.c',
+      ],
+      'dependencies': [
+        'mylib',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/standalone-static-library/prog.c b/gyp/test/standalone-static-library/prog.c
new file mode 100644 (file)
index 0000000..8af5c90
--- /dev/null
@@ -0,0 +1,7 @@
+extern void print(void);
+
+int main(void)
+{
+  print();
+  return 0;
+}
diff --git a/gyp/test/standalone/gyptest-standalone.py b/gyp/test/standalone/gyptest-standalone.py
new file mode 100644 (file)
index 0000000..8714370
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a project hierarchy created with the --generator-output=
+option can be built even when it's relocated to a different path.
+"""
+
+import TestGyp
+import os
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('standalone.gyp', '-Gstandalone')
+
+# Look at all the files in the tree to make sure none
+# of them reference the gyp file.
+for root, dirs, files in os.walk("."):
+  for file in files:
+    # ignore ourself
+    if os.path.splitext(__file__)[0] in file:
+      continue
+    file = os.path.join(root, file)
+    contents = open(file).read()
+    if 'standalone.gyp' in contents:
+      print 'gyp file referenced in generated output: %s' % file
+      test.fail_test()
+
+
+test.pass_test()
diff --git a/gyp/test/standalone/standalone.gyp b/gyp/test/standalone/standalone.gyp
new file mode 100644 (file)
index 0000000..b2a6785
--- /dev/null
@@ -0,0 +1,12 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name' : 'foo',
+      'type' : 'executable'
+    },
+  ]
+}
diff --git a/gyp/test/subdirectory/gyptest-SYMROOT-all.py b/gyp/test/subdirectory/gyptest-SYMROOT-all.py
new file mode 100755 (executable)
index 0000000..b750904
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target and a subsidiary dependent target from a
+.gyp file in a subdirectory, without specifying an explicit output build
+directory, and using the generated solution or project file at the top
+of the tree as the entry point.
+                                 
+The configuration sets the Xcode SYMROOT variable and uses --depth=
+to make Xcode behave like the other build tools--that is, put all
+built targets in a single output build directory at the top of the tree.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog1.gyp', '-Dset_symroot=1', '--depth=.', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Suppress the test infrastructure's setting SYMROOT on the command line.
+test.build('prog1.gyp', test.ALL, SYMROOT=None, chdir='relocate/src')
+
+test.run_built_executable('prog1',
+                          stdout="Hello from prog1.c\n",
+                          chdir='relocate/src')
+test.run_built_executable('prog2',
+                          stdout="Hello from prog2.c\n",
+                          chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/subdirectory/gyptest-SYMROOT-default.py b/gyp/test/subdirectory/gyptest-SYMROOT-default.py
new file mode 100755 (executable)
index 0000000..c64ae7d
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target and a subsidiary dependent target from a
+.gyp file in a subdirectory, without specifying an explicit output build
+directory, and using the generated solution or project file at the top
+of the tree as the entry point.
+                                 
+The configuration sets the Xcode SYMROOT variable and uses --depth=
+to make Xcode behave like the other build tools--that is, put all
+built targets in a single output build directory at the top of the tree.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog1.gyp', '-Dset_symroot=1', '--depth=.', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Suppress the test infrastructure's setting SYMROOT on the command line.
+test.build('prog1.gyp', SYMROOT=None, chdir='relocate/src')
+
+test.run_built_executable('prog1',
+                          stdout="Hello from prog1.c\n",
+                          chdir='relocate/src')
+
+test.run_built_executable('prog2',
+                          stdout="Hello from prog2.c\n",
+                          chdir='relocate/src')
+
+test.pass_test()
diff --git a/gyp/test/subdirectory/gyptest-subdir-all.py b/gyp/test/subdirectory/gyptest-subdir-all.py
new file mode 100755 (executable)
index 0000000..93a865a
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a subsidiary dependent target from a .gyp file in a
+subdirectory, without specifying an explicit output build directory,
+and using the subdirectory's solution or project file as the entry point.
+"""
+
+import TestGyp
+
+# Android doesn't support running from subdirectories.
+# Ninja doesn't support relocation.
+# CMake produces a single CMakeLists.txt in the output directory.
+test = TestGyp.TestGyp(formats=['!ninja', '!android', '!cmake'])
+
+test.run_gyp('prog1.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+chdir = 'relocate/src/subdir'
+target = test.ALL
+
+test.build('prog2.gyp', target, chdir=chdir)
+
+test.built_file_must_not_exist('prog1', type=test.EXECUTABLE, chdir=chdir)
+
+test.run_built_executable('prog2',
+                          chdir=chdir,
+                          stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/gyp/test/subdirectory/gyptest-subdir-default.py b/gyp/test/subdirectory/gyptest-subdir-default.py
new file mode 100755 (executable)
index 0000000..5d262f8
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a subsidiary dependent target from a .gyp file in a
+subdirectory, without specifying an explicit output build directory,
+and using the subdirectory's solution or project file as the entry point.
+"""
+
+import TestGyp
+import errno
+
+# Android doesn't support running from subdirectories.
+# Ninja doesn't support relocation.
+# CMake produces a single CMakeLists.txt in the output directory.
+test = TestGyp.TestGyp(formats=['!ninja', '!android', '!cmake'])
+
+test.run_gyp('prog1.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+chdir = 'relocate/src/subdir'
+
+test.build('prog2.gyp', chdir=chdir)
+
+test.built_file_must_not_exist('prog1', type=test.EXECUTABLE, chdir=chdir)
+
+test.run_built_executable('prog2',
+                          chdir=chdir,
+                          stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/gyp/test/subdirectory/gyptest-subdir2-deep.py b/gyp/test/subdirectory/gyptest-subdir2-deep.py
new file mode 100755 (executable)
index 0000000..4854898
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a project rooted several layers under src_dir works.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog3.gyp', chdir='src/subdir/subdir2')
+
+test.relocate('src', 'relocate/src')
+
+test.build('prog3.gyp', test.ALL, chdir='relocate/src/subdir/subdir2')
+
+test.run_built_executable('prog3',
+                          chdir='relocate/src/subdir/subdir2',
+                          stdout="Hello from prog3.c\n")
+
+test.pass_test()
diff --git a/gyp/test/subdirectory/gyptest-top-all.py b/gyp/test/subdirectory/gyptest-top-all.py
new file mode 100755 (executable)
index 0000000..b3c25b1
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target and a subsidiary dependent target from a
+.gyp file in a subdirectory, without specifying an explicit output build
+directory, and using the generated solution or project file at the top
+of the tree as the entry point.
+
+There is a difference here in the default behavior of the underlying
+build tools.  Specifically, when building the entire "solution", Xcode
+puts the output of each project relative to the .xcodeproj directory,
+while Visual Studio (and our implementation of Make) put it
+in a build directory relative to the "solution"--that is, the entry-point
+from which you built the entire tree.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog1.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('prog1.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('prog1',
+                          stdout="Hello from prog1.c\n",
+                          chdir='relocate/src')
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('prog2',
+                          chdir=chdir,
+                          stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/gyp/test/subdirectory/gyptest-top-default.py b/gyp/test/subdirectory/gyptest-top-default.py
new file mode 100755 (executable)
index 0000000..2448dd9
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target and a subsidiary dependent target from a
+.gyp file in a subdirectory, without specifying an explicit output build
+directory, and using the generated solution or project file at the top
+of the tree as the entry point.
+
+There is a difference here in the default behavior of the underlying
+build tools.  Specifically, when building the entire "solution", Xcode
+puts the output of each project relative to the .xcodeproj directory,
+while Visual Studio (and our implementation of Make) put it
+in a build directory relative to the "solution"--that is, the entry-point
+from which you built the entire tree.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog1.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('prog1.gyp', chdir='relocate/src')
+
+test.run_built_executable('prog1',
+                          stdout="Hello from prog1.c\n",
+                          chdir='relocate/src')
+
+if test.format == 'xcode':
+  chdir = 'relocate/src/subdir'
+else:
+  chdir = 'relocate/src'
+test.run_built_executable('prog2',
+                          chdir=chdir,
+                          stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/gyp/test/subdirectory/src/prog1.c b/gyp/test/subdirectory/src/prog1.c
new file mode 100644 (file)
index 0000000..218e994
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from prog1.c\n");
+  return 0;
+}
diff --git a/gyp/test/subdirectory/src/prog1.gyp b/gyp/test/subdirectory/src/prog1.gyp
new file mode 100644 (file)
index 0000000..2aa66ce
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    'symroot.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'prog1',
+      'type': 'executable',
+      'dependencies': [
+        'subdir/prog2.gyp:prog2',
+      ],
+      'sources': [
+        'prog1.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/subdirectory/src/subdir/prog2.c b/gyp/test/subdirectory/src/subdir/prog2.c
new file mode 100644 (file)
index 0000000..12a3188
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from prog2.c\n");
+  return 0;
+}
diff --git a/gyp/test/subdirectory/src/subdir/prog2.gyp b/gyp/test/subdirectory/src/subdir/prog2.gyp
new file mode 100644 (file)
index 0000000..c6cd35f
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../symroot.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'prog2',
+      'type': 'executable',
+      'sources': [
+        'prog2.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/subdirectory/src/subdir/subdir2/prog3.c b/gyp/test/subdirectory/src/subdir/subdir2/prog3.c
new file mode 100644 (file)
index 0000000..a326dc6
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from prog3.c\n");
+  return 0;
+}
diff --git a/gyp/test/subdirectory/src/subdir/subdir2/prog3.gyp b/gyp/test/subdirectory/src/subdir/subdir2/prog3.gyp
new file mode 100644 (file)
index 0000000..b49fb59
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../../symroot.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'prog3',
+      'type': 'executable',
+      'sources': [
+        'prog3.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/subdirectory/src/symroot.gypi b/gyp/test/subdirectory/src/symroot.gypi
new file mode 100644 (file)
index 0000000..5199164
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'set_symroot%': 0,
+  },
+  'conditions': [
+    ['set_symroot == 1', {
+      'xcode_settings': {
+        'SYMROOT': '<(DEPTH)/build',
+      },
+    }],
+  ],
+}
diff --git a/gyp/test/target/gyptest-target.py b/gyp/test/target/gyptest-target.py
new file mode 100644 (file)
index 0000000..4338db7
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using non-default extension. In particular, verifies how
+target_extension is used to avoid MSB8012 for msvs.
+"""
+
+import sys
+import TestGyp
+
+if sys.platform in ('win32', 'cygwin'):
+  test = TestGyp.TestGyp()
+
+  test.run_gyp('target.gyp')
+  test.build('target.gyp')
+
+  # executables
+  test.built_file_must_exist('hello1.stuff', test.EXECUTABLE, bare=True)
+  test.built_file_must_exist('hello2.exe', test.EXECUTABLE, bare=True)
+  test.built_file_must_not_exist('hello2.stuff', test.EXECUTABLE, bare=True)
+
+  # check msvs log for errors
+  if test.format == "msvs":
+    log_file = "obj\\hello1\\hello1.log"
+    test.built_file_must_exist(log_file)
+    test.built_file_must_not_contain(log_file, "MSB8012")
+
+    log_file = "obj\\hello2\\hello2.log"
+    test.built_file_must_exist(log_file)
+    test.built_file_must_not_contain(log_file, "MSB8012")
+
+  test.pass_test()
diff --git a/gyp/test/target/hello.c b/gyp/test/target/hello.c
new file mode 100644 (file)
index 0000000..3d535d3
--- /dev/null
@@ -0,0 +1,7 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+void main(void) {
+  printf("Hello, world!\n");
+}
diff --git a/gyp/test/target/target.gyp b/gyp/test/target/target.gyp
new file mode 100644 (file)
index 0000000..c87e30f
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello1',
+      'product_extension': 'stuff',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+    },
+    {
+      'target_name': 'hello2',
+      'target_extension': 'stuff',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+      ],
+    }
+  ]
+}
diff --git a/gyp/test/toolsets/gyptest-toolsets.py b/gyp/test/toolsets/gyptest-toolsets.py
new file mode 100755 (executable)
index 0000000..f80fce7
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that toolsets are correctly applied
+"""
+import os
+import sys
+import TestGyp
+
+if sys.platform.startswith('linux'):
+
+  test = TestGyp.TestGyp(formats=['make', 'ninja'])
+
+  oldenv = os.environ.copy()
+  try:
+    os.environ['GYP_CROSSCOMPILE'] = '1'
+    test.run_gyp('toolsets.gyp')
+  finally:
+    os.environ.clear()
+    os.environ.update(oldenv)
+
+  test.build('toolsets.gyp', test.ALL)
+
+  test.run_built_executable('host-main', stdout="Host\nShared: Host\n")
+  test.run_built_executable('target-main', stdout="Target\nShared: Target\n")
+
+  test.pass_test()
diff --git a/gyp/test/toolsets/main.cc b/gyp/test/toolsets/main.cc
new file mode 100644 (file)
index 0000000..bc47da9
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+const char *GetToolset();
+const char *GetToolsetShared();
+
+int main(void) {
+  printf("%s\n", GetToolset());
+  printf("Shared: %s\n", GetToolsetShared());
+}
diff --git a/gyp/test/toolsets/toolsets.cc b/gyp/test/toolsets/toolsets.cc
new file mode 100644 (file)
index 0000000..a45fa02
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+const char *GetToolset() {
+#ifdef TARGET
+  return "Target";
+#else
+  return "Host";
+#endif
+}
diff --git a/gyp/test/toolsets/toolsets.gyp b/gyp/test/toolsets/toolsets.gyp
new file mode 100644 (file)
index 0000000..3bc3a78
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'target_conditions': [
+      ['_toolset=="target"', {'defines': ['TARGET']}]
+    ]
+  },
+  'targets': [
+    {
+      'target_name': 'toolsets',
+      'type': 'static_library',
+      'toolsets': ['target', 'host'],
+      'sources': [
+        'toolsets.cc',
+      ],
+    },
+    {
+      'target_name': 'host-main',
+      'type': 'executable',
+      'toolsets': ['host'],
+      'dependencies': ['toolsets', 'toolsets_shared'],
+      'sources': [
+        'main.cc',
+      ],
+    },
+    {
+      'target_name': 'target-main',
+      'type': 'executable',
+      'dependencies': ['toolsets', 'toolsets_shared'],
+      'sources': [
+        'main.cc',
+      ],
+    },
+    # This tests that build systems can handle a shared library being build for
+    # both host and target.
+    {
+      'target_name': 'janus',
+      'type': 'shared_library',
+      'toolsets': ['target', 'host'],
+      'sources': [
+        'toolsets.cc',
+      ],
+      'cflags': [ '-fPIC' ],
+    },
+    {
+      'target_name': 'toolsets_shared',
+      'type': 'shared_library',
+      'toolsets': ['target', 'host'],
+      'target_conditions': [
+        # Ensure target and host have different shared_library names
+        ['_toolset=="host"', {'product_extension': 'host'}],
+      ],
+      'sources': [
+        'toolsets_shared.cc',
+      ],
+      'cflags': [ '-fPIC' ],
+    },
+  ],
+}
diff --git a/gyp/test/toolsets/toolsets_shared.cc b/gyp/test/toolsets/toolsets_shared.cc
new file mode 100644 (file)
index 0000000..794af2c
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (c) 2013 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+const char *GetToolsetShared() {
+#ifdef TARGET
+  return "Target";
+#else
+  return "Host";
+#endif
+}
diff --git a/gyp/test/toplevel-dir/gyptest-toplevel-dir.py b/gyp/test/toplevel-dir/gyptest-toplevel-dir.py
new file mode 100755 (executable)
index 0000000..4daa6b2
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a subsidiary dependent target from a .gyp file in a
+subdirectory, without specifying an explicit output build directory,
+and using the subdirectory's solution or project file as the entry point.
+"""
+
+import TestGyp
+import errno
+
+test = TestGyp.TestGyp(formats=['ninja', 'make'])
+
+# We want our Makefile to be one dir up from main.gyp.
+test.run_gyp('main.gyp', '--toplevel-dir=..', chdir='src/sub1')
+
+toplevel_dir = 'src'
+
+test.build('all', chdir=toplevel_dir)
+
+test.built_file_must_exist('prog1', type=test.EXECUTABLE, chdir=toplevel_dir)
+
+test.run_built_executable('prog1',
+                          chdir=toplevel_dir,
+                          stdout="Hello from prog1.c\n")
+
+test.pass_test()
diff --git a/gyp/test/toplevel-dir/src/sub1/main.gyp b/gyp/test/toplevel-dir/src/sub1/main.gyp
new file mode 100644 (file)
index 0000000..3321901
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'prog1',
+      'type': 'executable',
+      'dependencies': [
+        '<(DEPTH)/../sub2/prog2.gyp:prog2',
+      ],
+      'sources': [
+        'prog1.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/toplevel-dir/src/sub1/prog1.c b/gyp/test/toplevel-dir/src/sub1/prog1.c
new file mode 100644 (file)
index 0000000..218e994
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from prog1.c\n");
+  return 0;
+}
diff --git a/gyp/test/toplevel-dir/src/sub2/prog2.c b/gyp/test/toplevel-dir/src/sub2/prog2.c
new file mode 100644 (file)
index 0000000..12a3188
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello from prog2.c\n");
+  return 0;
+}
diff --git a/gyp/test/toplevel-dir/src/sub2/prog2.gyp b/gyp/test/toplevel-dir/src/sub2/prog2.gyp
new file mode 100644 (file)
index 0000000..5934548
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'prog2',
+      'type': 'executable',
+      'sources': [
+        'prog2.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/variables/commands/commands-repeated.gyp b/gyp/test/variables/commands/commands-repeated.gyp
new file mode 100644 (file)
index 0000000..822ae4f
--- /dev/null
@@ -0,0 +1,128 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a simple test file to make sure that variable substitution
+# happens correctly.  Run "run_tests.py" using python to generate the
+# output from this gyp file.
+
+{
+  'variables': {
+    'pi': 'import math; print math.pi',
+    'third_letters': "<(other_letters)HIJK",
+    'letters_list': 'ABCD',
+    'other_letters': '<(letters_list)EFG',
+    'check_included': '<(included_variable)',
+    'check_lists': [
+      '<(included_variable)',
+      '<(third_letters)',
+    ],
+    'check_int': 5,
+    'check_str_int': '6',
+    'check_list_int': [
+      7,
+      '8',
+      9,
+    ],
+    'not_int_1': ' 10',
+    'not_int_2': '11 ',
+    'not_int_3': '012',
+    'not_int_4': '13.0',
+    'not_int_5': '+14',
+    'negative_int': '-15',
+    'zero_int': '0',
+  },
+  'includes': [
+    'commands.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'none',
+      'variables': {
+        'var1': '<!(["python", "-c", "<(pi)"])',
+        'var2': '<!(python -c "print \'<!(python -c "<(pi)") <(letters_list)\'")',
+        'var3': '<!(python -c "print \'<(letters_list)\'")',
+        'var4': '<(<!(python -c "print \'letters_list\'"))',
+        'var5': 'letters_',
+        'var6': 'list',
+        'var7': '<(check_int)',
+        'var8': '<(check_int)blah',
+        'var9': '<(check_str_int)',
+        'var10': '<(check_list_int)',
+        'var11': ['<@(check_list_int)'],
+        'var12': '<(not_int_1)',
+        'var13': '<(not_int_2)',
+        'var14': '<(not_int_3)',
+        'var15': '<(not_int_4)',
+        'var16': '<(not_int_5)',
+        'var17': '<(negative_int)',
+        'var18': '<(zero_int)',
+        # A second set with different names to make sure they only execute the
+        # commands once.
+        'var1prime': '<!(["python", "-c", "<(pi)"])',
+        'var2prime': '<!(python -c "print \'<!(python -c "<(pi)") <(letters_list)\'")',
+        'var3prime': '<!(python -c "print \'<(letters_list)\'")',
+        'var4prime': '<(<!(python -c "print \'letters_list\'"))',
+      },
+      'actions': [
+        {
+          'action_name': 'test_action',
+          'variables': {
+            'var7': '<!(echo <(var5)<(var6))',
+          },
+          'inputs' : [
+            '<(var2)',
+          ],
+          'outputs': [
+            '<(var4)',
+            '<(var7)',
+          ],
+          'action': [
+            'echo',
+            '<(_inputs)',
+            '<(_outputs)',
+          ],
+        },
+        # Again with the same vars to make sure the right things happened.
+        {
+          'action_name': 'test_action_prime',
+          'variables': {
+            'var7': '<!(echo <(var5)<(var6))',
+          },
+          'inputs' : [
+            '<(var2)',
+          ],
+          'outputs': [
+            '<(var4)',
+            '<(var7)',
+          ],
+          'action': [
+            'echo',
+            '<(_inputs)',
+            '<(_outputs)',
+          ],
+        },
+        # And one more time with the other vars...
+        {
+          'action_name': 'test_action_prime_prime',
+          'variables': {
+            'var7': '<!(echo <(var5)<(var6))',
+          },
+          'inputs' : [
+            '<(var2prime)',
+          ],
+          'outputs': [
+            '<(var4prime)',
+            '<(var7)',
+          ],
+          'action': [
+            'echo',
+            '<(_inputs)',
+            '<(_outputs)',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/variables/commands/commands-repeated.gyp.stdout b/gyp/test/variables/commands/commands-repeated.gyp.stdout
new file mode 100644 (file)
index 0000000..56c393f
--- /dev/null
@@ -0,0 +1,136 @@
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFG', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'third_letters', 'is_array': '', 'replace': '<(third_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(other_letters)HIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_str_int', 'is_array': '', 'replace': '<(check_str_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '6', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5blah', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_4', 'is_array': '', 'replace': '<(not_int_4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '13.0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_3', 'is_array': '', 'replace': '<(not_int_3)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '012', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'negative_int', 'is_array': '', 'replace': '<(negative_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '-15', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_5', 'is_array': '', 'replace': '<(not_int_5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '+14', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<(check_list_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '7 8 9', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_2', 'is_array': '', 'replace': '<(not_int_2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '11 ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_1', 'is_array': '', 'replace': '<(not_int_1)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output ' 10', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'zero_int', 'is_array': '', 'replace': '<(zero_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<@(check_list_int)', 'type': '<@', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output [7, 8, 9], recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'echo letters_list', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'echo letters_list' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'echo letters_list', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'echo letters_list' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'echo letters_list', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'echo letters_list' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var2prime', 'is_array': '', 'replace': '<(var2prime)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var4prime', 'is_array': '', 'replace': '<(var4prime)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD letters_list', recursing.
diff --git a/gyp/test/variables/commands/commands-repeated.gypd.golden b/gyp/test/variables/commands/commands-repeated.gypd.golden
new file mode 100644 (file)
index 0000000..b29db5e
--- /dev/null
@@ -0,0 +1,77 @@
+{'_DEPTH': '.',
+ 'included_files': ['commands-repeated.gyp', 'commands.gypi'],
+ 'targets': [{'actions': [{'action': ['echo',
+                                      '"3.14159265359 ABCD"',
+                                      'ABCD letters_list'],
+                           'action_name': 'test_action',
+                           'inputs': ['3.14159265359 ABCD'],
+                           'outputs': ['ABCD', 'letters_list'],
+                           'variables': {'var7': 'letters_list'}},
+                          {'action': ['echo',
+                                      '"3.14159265359 ABCD"',
+                                      'ABCD letters_list'],
+                           'action_name': 'test_action_prime',
+                           'inputs': ['3.14159265359 ABCD'],
+                           'outputs': ['ABCD', 'letters_list'],
+                           'variables': {'var7': 'letters_list'}},
+                          {'action': ['echo',
+                                      '"3.14159265359 ABCD"',
+                                      'ABCD letters_list'],
+                           'action_name': 'test_action_prime_prime',
+                           'inputs': ['3.14159265359 ABCD'],
+                           'outputs': ['ABCD', 'letters_list'],
+                           'variables': {'var7': 'letters_list'}}],
+              'configurations': {'Default': {}},
+              'default_configuration': 'Default',
+              'target_name': 'foo',
+              'toolset': 'target',
+              'type': 'none',
+              'variables': {'var1': '3.14159265359',
+                            'var10': '7 8 9',
+                            'var11': ['7', '8', '9'],
+                            'var12': ' 10',
+                            'var13': '11 ',
+                            'var14': '012',
+                            'var15': '13.0',
+                            'var16': '+14',
+                            'var17': '-15',
+                            'var18': '0',
+                            'var1prime': '3.14159265359',
+                            'var2': '3.14159265359 ABCD',
+                            'var2prime': '3.14159265359 ABCD',
+                            'var3': 'ABCD',
+                            'var3prime': 'ABCD',
+                            'var4': 'ABCD',
+                            'var4prime': 'ABCD',
+                            'var5': 'letters_',
+                            'var6': 'list',
+                            'var7': '5',
+                            'var8': '5blah',
+                            'var9': '6'}},
+             {'configurations': {'Default': {}},
+              'default_configuration': 'Default',
+              'target_name': 'dummy',
+              'toolset': 'target',
+              'type': 'none'}],
+ 'variables': {'check_included': 'XYZ',
+               'check_int': '5',
+               'check_list_int': ['7', '8', '9'],
+               'check_lists': ['XYZ', 'ABCDEFGHIJK'],
+               'check_str_int': '6',
+               'default_empty_files%': '',
+               'default_empty_str%': '',
+               'default_int%': '0',
+               'default_int_files%': '0',
+               'default_str%': 'my_str',
+               'included_variable': 'XYZ',
+               'letters_list': 'ABCD',
+               'negative_int': '-15',
+               'not_int_1': ' 10',
+               'not_int_2': '11 ',
+               'not_int_3': '012',
+               'not_int_4': '13.0',
+               'not_int_5': '+14',
+               'other_letters': 'ABCDEFG',
+               'pi': 'import math; print math.pi',
+               'third_letters': 'ABCDEFGHIJK',
+               'zero_int': '0'}}
diff --git a/gyp/test/variables/commands/commands.gyp b/gyp/test/variables/commands/commands.gyp
new file mode 100644 (file)
index 0000000..78376ed
--- /dev/null
@@ -0,0 +1,91 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a simple test file to make sure that variable substitution
+# happens correctly.  Run "run_tests.py" using python to generate the
+# output from this gyp file.
+
+{
+  'variables': {
+    'pi': 'import math; print math.pi',
+    'third_letters': "<(other_letters)HIJK",
+    'letters_list': 'ABCD',
+    'other_letters': '<(letters_list)EFG',
+    'check_included': '<(included_variable)',
+    'check_lists': [
+      '<(included_variable)',
+      '<(third_letters)',
+    ],
+    'check_int': 5,
+    'check_str_int': '6',
+    'check_list_int': [
+      7,
+      '8',
+      9,
+    ],
+    'not_int_1': ' 10',
+    'not_int_2': '11 ',
+    'not_int_3': '012',
+    'not_int_4': '13.0',
+    'not_int_5': '+14',
+    'negative_int': '-15',
+    'zero_int': '0',
+  },
+  'includes': [
+    'commands.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'none',
+      'variables': {
+        'var1': '<!(["python", "-c", "<(pi)"])',
+        'var2': '<!(python -c "print \'<!(python -c "<(pi)") <(letters_list)\'")',
+        'var3': '<!(python -c "print \'<(letters_list)\'")',
+        'var4': '<(<!(python -c "print \'letters_list\'"))',
+        'var5': 'letters_',
+        'var6': 'list',
+        'var7': '<(check_int)',
+        'var8': '<(check_int)blah',
+        'var9': '<(check_str_int)',
+        'var10': '<(check_list_int)',
+        'var11': ['<@(check_list_int)'],
+        'var12': '<(not_int_1)',
+        'var13': '<(not_int_2)',
+        'var14': '<(not_int_3)',
+        'var15': '<(not_int_4)',
+        'var16': '<(not_int_5)',
+        'var17': '<(negative_int)',
+        'var18': '<(zero_int)',
+        'var19': ['<!@(python test.py)'],
+        'var20': '<!(python test.py)',
+        'var21': '<(default_str)',
+        'var22': '<(default_empty_str)',
+        'var23': '<(default_int)',
+        'var24': '<(default_empty_files)',
+        'var25': '<(default_int_files)',
+      },
+      'actions': [
+        {
+          'action_name': 'test_action',
+          'variables': {
+            'var7': '<!(echo <(var5)<(var6))',
+          },
+          'inputs' : [
+            '<(var2)',
+          ],
+          'outputs': [
+            '<(var4)',
+            '<(var7)',
+          ],
+          'action': [
+            'echo',
+            '<(_inputs)',
+            '<(_outputs)',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/variables/commands/commands.gyp.ignore-env.stdout b/gyp/test/variables/commands/commands.gyp.ignore-env.stdout
new file mode 100644 (file)
index 0000000..a345920
--- /dev/null
@@ -0,0 +1,96 @@
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFG', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'third_letters', 'is_array': '', 'replace': '<(third_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(other_letters)HIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_empty_files', 'is_array': '', 'replace': '<(default_empty_files)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_int_files', 'is_array': '', 'replace': '<(default_int_files)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!(python test.py)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:838:ExpandVariables Executing command 'python test.py' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'sample\\path\\foo.cpp', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_str', 'is_array': '', 'replace': '<(default_str)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'my_str', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_empty_str', 'is_array': '', 'replace': '<(default_empty_str)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_int', 'is_array': '', 'replace': '<(default_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_str_int', 'is_array': '', 'replace': '<(check_str_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '6', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5blah', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_4', 'is_array': '', 'replace': '<(not_int_4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '13.0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_3', 'is_array': '', 'replace': '<(not_int_3)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '012', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'negative_int', 'is_array': '', 'replace': '<(negative_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '-15', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_5', 'is_array': '', 'replace': '<(not_int_5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '+14', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<(check_list_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '7 8 9', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_2', 'is_array': '', 'replace': '<(not_int_2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '11 ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_1', 'is_array': '', 'replace': '<(not_int_1)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output ' 10', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'zero_int', 'is_array': '', 'replace': '<(zero_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<@(check_list_int)', 'type': '<@', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output [7, 8, 9], recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!@(python test.py)', 'type': '<!@', 'command_string': None}
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python test.py' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output ['samplepathfoo.cpp'], recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'echo letters_list', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'echo letters_list' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD letters_list', recursing.
diff --git a/gyp/test/variables/commands/commands.gyp.stdout b/gyp/test/variables/commands/commands.gyp.stdout
new file mode 100644 (file)
index 0000000..a345920
--- /dev/null
@@ -0,0 +1,96 @@
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFG', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'third_letters', 'is_array': '', 'replace': '<(third_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(other_letters)HIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_empty_files', 'is_array': '', 'replace': '<(default_empty_files)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_int_files', 'is_array': '', 'replace': '<(default_int_files)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!(python test.py)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:838:ExpandVariables Executing command 'python test.py' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'sample\\path\\foo.cpp', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_str', 'is_array': '', 'replace': '<(default_str)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'my_str', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_empty_str', 'is_array': '', 'replace': '<(default_empty_str)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_int', 'is_array': '', 'replace': '<(default_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_str_int', 'is_array': '', 'replace': '<(check_str_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '6', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5blah', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_4', 'is_array': '', 'replace': '<(not_int_4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '13.0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_3', 'is_array': '', 'replace': '<(not_int_3)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '012', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'negative_int', 'is_array': '', 'replace': '<(negative_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '-15', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_5', 'is_array': '', 'replace': '<(not_int_5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '+14', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<(check_list_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '7 8 9', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_2', 'is_array': '', 'replace': '<(not_int_2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '11 ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_1', 'is_array': '', 'replace': '<(not_int_1)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output ' 10', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'zero_int', 'is_array': '', 'replace': '<(zero_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<@(check_list_int)', 'type': '<@', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output [7, 8, 9], recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!@(python test.py)', 'type': '<!@', 'command_string': None}
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python test.py' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output ['samplepathfoo.cpp'], recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'echo letters_list', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'echo letters_list' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD letters_list', recursing.
diff --git a/gyp/test/variables/commands/commands.gypd.golden b/gyp/test/variables/commands/commands.gypd.golden
new file mode 100644 (file)
index 0000000..9e5cf89
--- /dev/null
@@ -0,0 +1,66 @@
+{'_DEPTH': '.',
+ 'included_files': ['commands.gyp', 'commands.gypi'],
+ 'targets': [{'actions': [{'action': ['echo',
+                                      '"3.14159265359 ABCD"',
+                                      'ABCD letters_list'],
+                           'action_name': 'test_action',
+                           'inputs': ['3.14159265359 ABCD'],
+                           'outputs': ['ABCD', 'letters_list'],
+                           'variables': {'var7': 'letters_list'}}],
+              'configurations': {'Default': {}},
+              'default_configuration': 'Default',
+              'target_name': 'foo',
+              'toolset': 'target',
+              'type': 'none',
+              'variables': {'var1': '3.14159265359',
+                            'var10': '7 8 9',
+                            'var11': ['7', '8', '9'],
+                            'var12': ' 10',
+                            'var13': '11 ',
+                            'var14': '012',
+                            'var15': '13.0',
+                            'var16': '+14',
+                            'var17': '-15',
+                            'var18': '0',
+                            'var19': ['samplepathfoo.cpp'],
+                            'var2': '3.14159265359 ABCD',
+                            'var20': 'sample\\path\\foo.cpp',
+                            'var21': 'my_str',
+                            'var22': '',
+                            'var23': '0',
+                            'var24': '',
+                            'var25': '0',
+                            'var3': 'ABCD',
+                            'var4': 'ABCD',
+                            'var5': 'letters_',
+                            'var6': 'list',
+                            'var7': '5',
+                            'var8': '5blah',
+                            'var9': '6'}},
+             {'configurations': {'Default': {}},
+              'default_configuration': 'Default',
+              'target_name': 'dummy',
+              'toolset': 'target',
+              'type': 'none'}],
+ 'variables': {'check_included': 'XYZ',
+               'check_int': '5',
+               'check_list_int': ['7', '8', '9'],
+               'check_lists': ['XYZ', 'ABCDEFGHIJK'],
+               'check_str_int': '6',
+               'default_empty_files%': '',
+               'default_empty_str%': '',
+               'default_int%': '0',
+               'default_int_files%': '0',
+               'default_str%': 'my_str',
+               'included_variable': 'XYZ',
+               'letters_list': 'ABCD',
+               'negative_int': '-15',
+               'not_int_1': ' 10',
+               'not_int_2': '11 ',
+               'not_int_3': '012',
+               'not_int_4': '13.0',
+               'not_int_5': '+14',
+               'other_letters': 'ABCDEFG',
+               'pi': 'import math; print math.pi',
+               'third_letters': 'ABCDEFGHIJK',
+               'zero_int': '0'}}
diff --git a/gyp/test/variables/commands/commands.gypi b/gyp/test/variables/commands/commands.gypi
new file mode 100644 (file)
index 0000000..839cb30
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is included from commands.gyp to test evaluation order of includes.
+{
+  'variables': {
+    'included_variable': 'XYZ',
+
+    'default_str%': 'my_str',
+    'default_empty_str%': '',
+    'default_int%': 0,
+
+    'default_empty_files%': '',
+    'default_int_files%': 0,
+  },
+  'targets': [
+    {
+      'target_name': 'dummy',
+      'type': 'none',
+    },
+  ],
+}
diff --git a/gyp/test/variables/commands/gyptest-commands-ignore-env.py b/gyp/test/variables/commands/gyptest-commands-ignore-env.py
new file mode 100755 (executable)
index 0000000..1cf3308
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test that environment variables are ignored when --ignore-environment is
+specified.
+"""
+
+import os
+
+import TestGyp
+
+test = TestGyp.TestGyp(format='gypd')
+
+os.environ['GYP_DEFINES'] = 'FOO=BAR'
+os.environ['GYP_GENERATORS'] = 'foo'
+os.environ['GYP_GENERATOR_FLAGS'] = 'genflag=foo'
+os.environ['GYP_GENERATOR_OUTPUT'] = 'somedir'
+
+expect = test.read('commands.gyp.ignore-env.stdout').replace('\r\n', '\n')
+
+test.run_gyp('commands.gyp',
+             '--debug', 'variables',
+             '--ignore-environment',
+             stdout=expect, ignore_line_numbers=True)
+
+# Verify the commands.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system.  Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('commands.gypd').replace('\r', '')
+expect = test.read('commands.gypd.golden').replace('\r', '')
+if not test.match(contents, expect):
+  print "Unexpected contents of `commands.gypd'"
+  test.diff(expect, contents, 'commands.gypd ')
+  test.fail_test()
+
+test.pass_test()
diff --git a/gyp/test/variables/commands/gyptest-commands-repeated-multidir.py b/gyp/test/variables/commands/gyptest-commands-repeated-multidir.py
new file mode 100755 (executable)
index 0000000..21e0487
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test variable expansion of '<!()' syntax commands where they are evaluated
+more than once from different directories.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# This tests GYP's cache of commands, ensuring that the directory a command is
+# run from is part of its cache key. Parallelism may lead to multiple cache
+# lookups failing, resulting in the command being run multiple times by
+# chance, not by GYP's logic. Turn off parallelism to ensure that the logic is
+# being tested.
+test.run_gyp('repeated_multidir/main.gyp', '--no-parallel')
+
+test.pass_test()
diff --git a/gyp/test/variables/commands/gyptest-commands-repeated.py b/gyp/test/variables/commands/gyptest-commands-repeated.py
new file mode 100755 (executable)
index 0000000..b95fe2d
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test variable expansion of '<!()' syntax commands where they are evaluated
+more then once..
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(format='gypd')
+
+expect = test.read('commands-repeated.gyp.stdout').replace('\r\n', '\n')
+
+test.run_gyp('commands-repeated.gyp',
+             '--debug', 'variables',
+             stdout=expect, ignore_line_numbers=True)
+
+# Verify the commands-repeated.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system.  Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('commands-repeated.gypd').replace('\r\n', '\n')
+expect = test.read('commands-repeated.gypd.golden').replace('\r\n', '\n')
+if not test.match(contents, expect):
+  print "Unexpected contents of `commands-repeated.gypd'"
+  test.diff(expect, contents, 'commands-repeated.gypd ')
+  test.fail_test()
+
+test.pass_test()
diff --git a/gyp/test/variables/commands/gyptest-commands.py b/gyp/test/variables/commands/gyptest-commands.py
new file mode 100755 (executable)
index 0000000..ef1af8c
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test variable expansion of '<!()' syntax commands.
+"""
+
+import os
+
+import TestGyp
+
+test = TestGyp.TestGyp(format='gypd')
+
+expect = test.read('commands.gyp.stdout').replace('\r', '')
+
+test.run_gyp('commands.gyp',
+             '--debug', 'variables',
+             stdout=expect, ignore_line_numbers=True)
+
+# Verify the commands.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system.  Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('commands.gypd').replace('\r', '')
+expect = test.read('commands.gypd.golden').replace('\r', '')
+if not test.match(contents, expect):
+  print "Unexpected contents of `commands.gypd'"
+  test.diff(expect, contents, 'commands.gypd ')
+  test.fail_test()
+
+test.pass_test()
diff --git a/gyp/test/variables/commands/repeated_multidir/dir_1/test_1.gyp b/gyp/test/variables/commands/repeated_multidir/dir_1/test_1.gyp
new file mode 100644 (file)
index 0000000..328fc30
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'expected_value': 'dir_1',
+    'target_name': 'target_1',
+  },
+  'includes': [
+    '../repeated_command_common.gypi',
+  ],
+}
diff --git a/gyp/test/variables/commands/repeated_multidir/dir_2/test_2.gyp b/gyp/test/variables/commands/repeated_multidir/dir_2/test_2.gyp
new file mode 100644 (file)
index 0000000..18e0c62
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'expected_value': 'dir_2',
+    'target_name': 'target_2',
+  },
+  'includes': [
+    '../repeated_command_common.gypi',
+  ],
+}
diff --git a/gyp/test/variables/commands/repeated_multidir/main.gyp b/gyp/test/variables/commands/repeated_multidir/main.gyp
new file mode 100644 (file)
index 0000000..5beeeb7
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'main',
+      'type': 'none',
+      'dependencies': [
+        'dir_1/test_1.gyp:target_1',
+        'dir_2/test_2.gyp:target_2',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/variables/commands/repeated_multidir/print_cwd_basename.py b/gyp/test/variables/commands/repeated_multidir/print_cwd_basename.py
new file mode 100755 (executable)
index 0000000..ace9ed6
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import os.path
+
+print os.path.basename(os.getcwd())
diff --git a/gyp/test/variables/commands/repeated_multidir/repeated_command_common.gypi b/gyp/test/variables/commands/repeated_multidir/repeated_command_common.gypi
new file mode 100644 (file)
index 0000000..7436677
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    # This command will be run from the directories of the .gyp files that
+    # include this .gypi, the subdirectories dir_1 and dir_2, so use a
+    # relative path from those directories to the script.
+    'observed_value': '<!(python ../print_cwd_basename.py)',
+  },
+  'targets': [
+    {
+      'target_name': '<(target_name)',
+      'type': 'none',
+      'conditions': [
+        ['observed_value != expected_value', {
+          # Attempt to expand an undefined variable. This triggers a GYP
+          # error.
+          'assertion': '<(observed_value_must_equal_expected_value)',
+        }],
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/variables/commands/test.py b/gyp/test/variables/commands/test.py
new file mode 100644 (file)
index 0000000..4d9ca6d
--- /dev/null
@@ -0,0 +1 @@
+print "sample\\path\\foo.cpp"
diff --git a/gyp/test/variables/commands/update_golden b/gyp/test/variables/commands/update_golden
new file mode 100755 (executable)
index 0000000..4fcf1eb
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+python ../../../gyp --debug variables --format gypd --depth . commands.gyp > commands.gyp.stdout
+python ../../../gyp --ignore-environment --debug variables --format gypd --depth . commands.gyp > commands.gyp.ignore-env.stdout
+cp -f commands.gypd commands.gypd.golden
+python ../../../gyp --debug variables --format gypd --depth . commands-repeated.gyp > commands-repeated.gyp.stdout
+cp -f commands-repeated.gypd commands-repeated.gypd.golden
diff --git a/gyp/test/variables/filelist/filelist.gyp.stdout b/gyp/test/variables/filelist/filelist.gyp.stdout
new file mode 100644 (file)
index 0000000..595a19c
--- /dev/null
@@ -0,0 +1,26 @@
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'names.txt <@(names', 'is_array': '', 'replace': '<|(names.txt <@(names)', 'type': '<|', 'command_string': None}
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'names', 'is_array': '', 'replace': '<@(names)', 'type': '<@', 'command_string': None}
+VARIABLES:input.py:797:ExpandVariables Found output 'names.txt John Jacob Jingleheimer Schmidt', recursing.
+VARIABLES:input.py:797:ExpandVariables Found output 'names.txt', recursing.
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'names_listfile', 'is_array': '', 'replace': '<(names_listfile)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:797:ExpandVariables Found output 'names.txt', recursing.
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'names_listfile', 'is_array': '', 'replace': '<(names_listfile)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:797:ExpandVariables Found output 'names.txt', recursing.
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'cat <(names_listfile', 'is_array': '', 'replace': '<!@(cat <(names_listfile)', 'type': '<!@', 'command_string': None}
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'names_listfile', 'is_array': '', 'replace': '<(names_listfile)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:797:ExpandVariables Found output 'cat names.txt', recursing.
+VARIABLES:input.py:676:ExpandVariables Executing command 'cat names.txt' in directory 'src'
+VARIABLES:input.py:797:ExpandVariables Found output ['John', 'Jacob', 'Jingleheimer', 'Schmidt'], recursing.
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'sources.txt <@(_sources', 'is_array': '', 'replace': '<|(sources.txt <@(_sources)', 'type': '<|', 'command_string': None}
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_sources', 'is_array': '', 'replace': '<@(_sources)', 'type': '<@', 'command_string': None}
+VARIABLES:input.py:797:ExpandVariables Found output 'sources.txt John Jacob Jingleheimer Schmidt', recursing.
+VARIABLES:input.py:797:ExpandVariables Found output 'sources.txt', recursing.
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'sources_listfile', 'is_array': '', 'replace': '<(sources_listfile)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:797:ExpandVariables Found output 'sources.txt', recursing.
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'sources_listfile', 'is_array': '', 'replace': '<(sources_listfile)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:797:ExpandVariables Found output 'sources.txt', recursing.
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'cat <(sources_listfile', 'is_array': '', 'replace': '<!@(cat <(sources_listfile)', 'type': '<!@', 'command_string': None}
+VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'sources_listfile', 'is_array': '', 'replace': '<(sources_listfile)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:797:ExpandVariables Found output 'cat sources.txt', recursing.
+VARIABLES:input.py:676:ExpandVariables Executing command 'cat sources.txt' in directory 'src'
+VARIABLES:input.py:797:ExpandVariables Found output ['John', 'Jacob', 'Jingleheimer', 'Schmidt'], recursing.
diff --git a/gyp/test/variables/filelist/filelist.gypd.golden b/gyp/test/variables/filelist/filelist.gypd.golden
new file mode 100644 (file)
index 0000000..09d9116
--- /dev/null
@@ -0,0 +1,43 @@
+{'_DEPTH': '.',
+ 'included_files': ['filelist.gyp'],
+ 'targets': [{'actions': [{'action': ['python', 'dummy.py', 'names.txt'],
+                           'action_name': 'test_action',
+                           'inputs': ['names.txt',
+                                      'John',
+                                      'Jacob',
+                                      'Jingleheimer',
+                                      'Schmidt'],
+                           'outputs': ['dummy_foo']}],
+              'configurations': {'Default': {}},
+              'default_configuration': 'Default',
+              'target_name': 'foo',
+              'toolset': 'target',
+              'type': 'none',
+              'variables': {'names_listfile': 'names.txt'}},
+             {'actions': [{'action': ['python', 'dummy.py', 'sources.txt'],
+                           'action_name': 'test_action',
+                           'inputs': ['sources.txt',
+                                      'John',
+                                      'Jacob',
+                                      'Jingleheimer',
+                                      'Schmidt'],
+                           'outputs': ['dummy_foo']}],
+              'configurations': {'Default': {}},
+              'default_configuration': 'Default',
+              'sources': ['John', 'Jacob', 'Jingleheimer', 'Schmidt'],
+              'sources_excluded': ['Astor', 'Jerome', 'Schultz'],
+              'target_name': 'bar',
+              'toolset': 'target',
+              'type': 'none',
+              'variables': {'sources_listfile': 'sources.txt'}}],
+ 'variables': {'names': ['John',
+                         'Jacob',
+                         'Astor',
+                         'Jingleheimer',
+                         'Jerome',
+                         'Schmidt',
+                         'Schultz'],
+               'names!': ['Astor'],
+               'names/': [['exclude', 'Sch.*'],
+                          ['include', '.*dt'],
+                          ['exclude', 'Jer.*']]}}
diff --git a/gyp/test/variables/filelist/gyptest-filelist-golden.py b/gyp/test/variables/filelist/gyptest-filelist-golden.py
new file mode 100644 (file)
index 0000000..55eaf9d
--- /dev/null
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test variable expansion of '<|(list.txt ...)' syntax commands.
+"""
+
+import os
+import sys
+
+import TestGyp
+
+test = TestGyp.TestGyp(format='gypd')
+
+expect = test.read('filelist.gyp.stdout')
+if sys.platform == 'win32':
+  expect = expect.replace('/', r'\\').replace('\r\n', '\n')
+
+test.run_gyp('src/filelist.gyp',
+             '--debug', 'variables',
+             stdout=expect, ignore_line_numbers=True)
+
+# Verify the filelist.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system.  Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('src/filelist.gypd').replace(
+    '\r', '').replace('\\\\', '/')
+expect = test.read('filelist.gypd.golden').replace('\r', '')
+if not test.match(contents, expect):
+  print "Unexpected contents of `src/filelist.gypd'"
+  test.diff(expect, contents, 'src/filelist.gypd ')
+  test.fail_test()
+
+contents = test.read('src/names.txt')
+expect = 'John\nJacob\nJingleheimer\nSchmidt\n'
+if not test.match(contents, expect):
+  print "Unexpected contents of `src/names.txt'"
+  test.diff(expect, contents, 'src/names.txt ')
+  test.fail_test()
+
+test.pass_test()
+
diff --git a/gyp/test/variables/filelist/gyptest-filelist.py b/gyp/test/variables/filelist/gyptest-filelist.py
new file mode 100755 (executable)
index 0000000..84a6cba
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test variable expansion of '<|(list.txt ...)' syntax commands.
+"""
+
+import os
+import sys
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+CHDIR = 'src'
+test.run_gyp('filelist2.gyp', chdir=CHDIR)
+
+test.build('filelist2.gyp', 'foo', chdir=CHDIR)
+contents = test.read('src/dummy_foo').replace('\r', '')
+expect = 'John\nJacob\nJingleheimer\nSchmidt\n'
+if not test.match(contents, expect):
+  print "Unexpected contents of `src/dummy_foo'"
+  test.diff(expect, contents, 'src/dummy_foo')
+  test.fail_test()
+
+test.pass_test()
diff --git a/gyp/test/variables/filelist/src/dummy.py b/gyp/test/variables/filelist/src/dummy.py
new file mode 100644 (file)
index 0000000..e41fc9f
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+import sys
+
+open(sys.argv[1], 'w').write(open(sys.argv[2]).read())
diff --git a/gyp/test/variables/filelist/src/filelist.gyp b/gyp/test/variables/filelist/src/filelist.gyp
new file mode 100644 (file)
index 0000000..df48eb3
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a test to make sure that <|(foo.txt a b c) generates
+# a pre-calculated file list at gyp time and returns foo.txt.
+# This feature is useful to work around limits in the number of arguments that
+# can be passed to rule/action.
+
+{
+  'variables': {
+    'names': [
+      'John',
+      'Jacob',
+      'Astor',
+      'Jingleheimer',
+      'Jerome',
+      'Schmidt',
+      'Schultz',
+    ],
+    'names!': [
+      'Astor',
+    ],
+    'names/': [
+      ['exclude', 'Sch.*'],
+      ['include', '.*dt'],
+      ['exclude', 'Jer.*'],
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'none',
+      'variables': {
+        'names_listfile': '<|(names.txt <@(names))',
+      },
+      'actions': [
+        {
+          'action_name': 'test_action',
+          'inputs' : [
+            '<(names_listfile)',
+            '<!@(cat <(names_listfile))',
+          ],
+          'outputs': [
+            'dummy_foo',
+          ],
+          'action': [
+            'python', 'dummy.py', '<(names_listfile)',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'bar',
+      'type': 'none',
+      'sources': [
+        'John',
+        'Jacob',
+        'Astor',
+        'Jingleheimer',
+        'Jerome',
+        'Schmidt',
+        'Schultz',
+      ],
+      'sources!': [
+        'Astor',
+      ],
+      'sources/': [
+        ['exclude', 'Sch.*'],
+        ['include', '.*dt'],
+        ['exclude', 'Jer.*'],
+      ],
+      'variables': {
+        'sources_listfile': '<|(sources.txt <@(_sources))',
+      },
+      'actions': [
+        {
+          'action_name': 'test_action',
+          'inputs' : [
+            '<(sources_listfile)',
+            '<!@(cat <(sources_listfile))',
+          ],
+          'outputs': [
+            'dummy_foo',
+          ],
+          'action': [
+            'python', 'dummy.py', '<(sources_listfile)',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/variables/filelist/src/filelist2.gyp b/gyp/test/variables/filelist/src/filelist2.gyp
new file mode 100644 (file)
index 0000000..ec215db
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a test to make sure that <|(foo.txt a b c) generates
+# a pre-calculated file list at gyp time and returns foo.txt.
+# This feature is useful to work around limits in the number of arguments that
+# can be passed to rule/action.
+
+{
+  'variables': {
+    'names': [
+      'John',
+      'Jacob',
+      'Jingleheimer',
+      'Schmidt',
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'none',
+      'variables': {
+        'names_listfile': '<|(names.txt <@(names))',
+      },
+      'actions': [
+        {
+          'action_name': 'test_action',
+          'msvs_cygwin_shell': 0,
+          'inputs' : [ '<(names_listfile)' ],
+          'outputs': [ 'dummy_foo' ],
+          'action': [
+            'python', 'dummy.py', '<@(_outputs)', '<(names_listfile)',
+          ],
+        },
+      ],
+    },
+  ],
+}
+
diff --git a/gyp/test/variables/filelist/update_golden b/gyp/test/variables/filelist/update_golden
new file mode 100755 (executable)
index 0000000..b4d489a
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+python ../../../gyp --debug variables --debug general --format gypd --depth . src/filelist.gyp > filelist.gyp.stdout
+cp -f src/filelist.gypd filelist.gypd.golden
diff --git a/gyp/test/variables/latelate/gyptest-latelate.py b/gyp/test/variables/latelate/gyptest-latelate.py
new file mode 100755 (executable)
index 0000000..2d77dfe
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that ^(latelate) style variables work.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('latelate.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('latelate.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable(
+    'program', chdir='relocate/src', stdout='program.cc\n')
+
+
+test.pass_test()
diff --git a/gyp/test/variables/latelate/src/latelate.gyp b/gyp/test/variables/latelate/src/latelate.gyp
new file mode 100644 (file)
index 0000000..312f376
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'target_conditions': [
+      ['has_lame==1', {
+        'sources/': [
+          ['exclude', 'lame'],
+        ],
+      }],
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'variables': {
+        'has_lame': 1,
+      },
+      'include_dirs': [
+        '<(SHARED_INTERMEDIATE_DIR)',
+      ],
+      'defines': [
+        'FOO="^(_sources)"',
+      ],
+      'sources': [
+        'program.cc',
+        'this_is_lame.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/variables/latelate/src/program.cc b/gyp/test/variables/latelate/src/program.cc
new file mode 100644 (file)
index 0000000..97c98ae
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+
+int main(void) {
+  printf(FOO "\n");
+  return 0;
+}
diff --git a/gyp/test/variables/variable-in-path/C1/hello.cc b/gyp/test/variables/variable-in-path/C1/hello.cc
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/variables/variable-in-path/gyptest-variable-in-path.py b/gyp/test/variables/variable-in-path/gyptest-variable-in-path.py
new file mode 100644 (file)
index 0000000..b73a279
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure <(CONFIGURATION_NAME) variable is correctly expanded.
+"""
+
+import TestGyp
+
+import sys
+
+test = TestGyp.TestGyp()
+test.set_configuration('C1')
+
+test.run_gyp('variable-in-path.gyp')
+test.build('variable-in-path.gyp', 'hello1')
+test.build('variable-in-path.gyp', 'hello2')
+
+
+test.pass_test()
diff --git a/gyp/test/variables/variable-in-path/variable-in-path.gyp b/gyp/test/variables/variable-in-path/variable-in-path.gyp
new file mode 100644 (file)
index 0000000..908d21e
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello1',
+      'type': 'executable',
+      'sources': [
+        '<(CONFIGURATION_NAME)/hello.cc',
+      ],
+    },
+    {
+      'target_name': 'hello2',
+      'type': 'executable',
+      'sources': [
+        './<(CONFIGURATION_NAME)/hello.cc',
+      ],
+    },
+  ],
+  'target_defaults': {
+    'default_configuration': 'C1',
+    'configurations': {
+      'C1': {
+      },
+      'C2': {
+      },
+    },
+  },
+}
diff --git a/gyp/test/win/asm-files/asm-files.gyp b/gyp/test/win/asm-files/asm-files.gyp
new file mode 100644 (file)
index 0000000..b1f132c
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'sources_with_asm',
+      'type': 'executable',
+      'sources': [
+        'hello.cc',
+        'b.s',
+        'c.S',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/asm-files/b.s b/gyp/test/win/asm-files/b.s
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/win/asm-files/c.S b/gyp/test/win/asm-files/c.S
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/win/asm-files/hello.cc b/gyp/test/win/asm-files/hello.cc
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/batch-file-action/batch-file-action.gyp b/gyp/test/win/batch-file-action/batch-file-action.gyp
new file mode 100644 (file)
index 0000000..e4db9af
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_batch',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'copy_to_output',
+          'inputs': ['infile'],
+          'outputs': ['outfile'],
+          'action': ['somecmd.bat', 'infile', 'outfile'],
+          'msvs_cygwin_shell': 0,
+        }
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/batch-file-action/infile b/gyp/test/win/batch-file-action/infile
new file mode 100644 (file)
index 0000000..3f9177e
--- /dev/null
@@ -0,0 +1 @@
+input
diff --git a/gyp/test/win/batch-file-action/somecmd.bat b/gyp/test/win/batch-file-action/somecmd.bat
new file mode 100644 (file)
index 0000000..d487753
--- /dev/null
@@ -0,0 +1,5 @@
+@echo off\r
+:: The redirs to nul are important. %2 can end up being an unterminated "'d\r
+:: string, so the remainder of the command line becomes the target file name,\r
+:: which in turn fails because it's a filename containing >, nul, etc.\r
+copy /y %1 %2 >nul 2>nul\r
diff --git a/gyp/test/win/command-quote/a.S b/gyp/test/win/command-quote/a.S
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/win/command-quote/bat with spaces.bat b/gyp/test/win/command-quote/bat with spaces.bat
new file mode 100644 (file)
index 0000000..dc3508f
--- /dev/null
@@ -0,0 +1,7 @@
+@echo off
+
+:: Copyright (c) 2012 Google Inc. All rights reserved.
+:: Use of this source code is governed by a BSD-style license that can be
+:: found in the LICENSE file.
+
+copy %1 %2
diff --git a/gyp/test/win/command-quote/command-quote.gyp b/gyp/test/win/command-quote/command-quote.gyp
new file mode 100644 (file)
index 0000000..faf7246
--- /dev/null
@@ -0,0 +1,79 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'msvs_cygwin_dirs': ['../../../../../<(DEPTH)/third_party/cygwin'],
+  },
+  'targets': [
+    {
+      'target_name': 'test_batch',
+      'type': 'none',
+      'rules': [
+      {
+        'rule_name': 'build_with_batch',
+        'msvs_cygwin_shell': 0,
+        'extension': 'S',
+        'outputs': ['output.obj'],
+        'action': ['call go.bat', '<(RULE_INPUT_PATH)', 'output.obj'],
+      },],
+      'sources': ['a.S'],
+    },
+    {
+      'target_name': 'test_call_separate',
+      'type': 'none',
+      'rules': [
+      {
+        'rule_name': 'build_with_batch2',
+        'msvs_cygwin_shell': 0,
+        'extension': 'S',
+        'outputs': ['output2.obj'],
+        'action': ['call', 'go.bat', '<(RULE_INPUT_PATH)', 'output2.obj'],
+      },],
+      'sources': ['a.S'],
+    },
+    {
+      'target_name': 'test_with_spaces',
+      'type': 'none',
+      'rules': [
+      {
+        'rule_name': 'build_with_batch3',
+        'msvs_cygwin_shell': 0,
+        'extension': 'S',
+        'outputs': ['output3.obj'],
+        'action': ['bat with spaces.bat', '<(RULE_INPUT_PATH)', 'output3.obj'],
+      },],
+      'sources': ['a.S'],
+    },
+    {
+      'target_name': 'test_with_double_quotes',
+      'type': 'none',
+      'rules': [
+      {
+        'rule_name': 'build_with_batch3',
+        'msvs_cygwin_shell': 1,
+        'extension': 'S',
+        'outputs': ['output4.obj'],
+        'arguments': ['-v'],
+        'action': ['python', '-c', 'import shutil; '
+          'shutil.copy("<(RULE_INPUT_PATH)", "output4.obj")'],
+      },],
+      'sources': ['a.S'],
+    },
+    {
+      'target_name': 'test_with_single_quotes',
+      'type': 'none',
+      'rules': [
+      {
+        'rule_name': 'build_with_batch3',
+        'msvs_cygwin_shell': 1,
+        'extension': 'S',
+        'outputs': ['output5.obj'],
+        'action': ['python', '-c', "import shutil; "
+          "shutil.copy('<(RULE_INPUT_PATH)', 'output5.obj')"],
+      },],
+      'sources': ['a.S'],
+    },
+  ]
+}
diff --git a/gyp/test/win/command-quote/go.bat b/gyp/test/win/command-quote/go.bat
new file mode 100644 (file)
index 0000000..dc3508f
--- /dev/null
@@ -0,0 +1,7 @@
+@echo off
+
+:: Copyright (c) 2012 Google Inc. All rights reserved.
+:: Use of this source code is governed by a BSD-style license that can be
+:: found in the LICENSE file.
+
+copy %1 %2
diff --git a/gyp/test/win/command-quote/subdir/and/another/in-subdir.gyp b/gyp/test/win/command-quote/subdir/and/another/in-subdir.gyp
new file mode 100644 (file)
index 0000000..3dff4c4
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_batch_depth',
+      'type': 'none',
+      'variables': {
+        # Taken from native_client/build/common.gypi. Seems unintentional (a
+        # string in a 1 element list)? But since it works on other generators,
+        # I guess it should work here too.
+        'filepath': [ 'call <(DEPTH)/../../../go.bat' ],
+      },
+      'rules': [
+      {
+        'rule_name': 'build_with_batch4',
+        'msvs_cygwin_shell': 0,
+        'extension': 'S',
+        'outputs': ['output4.obj'],
+        'action': ['<@(filepath)', '<(RULE_INPUT_PATH)', 'output4.obj'],
+      },],
+      'sources': ['<(DEPTH)\\..\\..\\..\\a.S'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/additional-include-dirs.cc b/gyp/test/win/compiler-flags/additional-include-dirs.cc
new file mode 100644 (file)
index 0000000..f1e11dd
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// No path qualification to test compiler include dir specification.
+#include "header.h"
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/additional-include-dirs.gyp b/gyp/test/win/compiler-flags/additional-include-dirs.gyp
new file mode 100644 (file)
index 0000000..42c7e84
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_incs',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'AdditionalIncludeDirectories': [
+            'subdir',
+          ],
+        }
+      },
+      'sources': ['additional-include-dirs.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/additional-options.cc b/gyp/test/win/compiler-flags/additional-options.cc
new file mode 100644 (file)
index 0000000..c79572b
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  // Generate a warning that will appear at level 4, but not level 1
+  // (truncation and unused local).
+  char c = 123456;
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/additional-options.gyp b/gyp/test/win/compiler-flags/additional-options.gyp
new file mode 100644 (file)
index 0000000..6a365a2
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_additional_none',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarningLevel': '4',
+          'WarnAsError': 'true',
+        }
+      },
+      'sources': ['additional-options.cc'],
+    },
+    {
+      'target_name': 'test_additional_one',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarningLevel': '4',
+          'WarnAsError': 'true',
+          'AdditionalOptions': [ '/W1' ],
+        }
+      },
+      'sources': ['additional-options.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/analysis.gyp b/gyp/test/win/compiler-flags/analysis.gyp
new file mode 100644 (file)
index 0000000..97e9422
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_analysis_on',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnablePREfast': 'true',
+          'WarnAsError': 'true',
+        },
+      },
+      'sources': ['uninit.cc'],
+    },
+    {
+      'target_name': 'test_analysis_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnablePREfast': 'false',
+          'WarnAsError': 'true',
+        },
+      },
+      'sources': ['uninit.cc'],
+    },
+    {
+      'target_name': 'test_analysis_unspec',
+      'type': 'executable',
+      'sources': ['uninit.cc'],
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarnAsError': 'true',
+        },
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/buffer-security-check.gyp b/gyp/test/win/compiler-flags/buffer-security-check.gyp
new file mode 100644 (file)
index 0000000..cc5a12b
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    # Turn debug information on so that we can see the name of the buffer
+    # security check cookie in the disassembly.
+    {
+      'target_name': 'test_bsc_unset',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+        },
+      },
+      'sources': ['buffer-security.cc'],
+    },
+    {
+      'target_name': 'test_bsc_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'BufferSecurityCheck': 'false',
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+        },
+      },
+      'sources': ['buffer-security.cc'],
+    },
+    {
+      'target_name': 'test_bsc_on',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'BufferSecurityCheck': 'true',
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+        },
+      },
+      'sources': ['buffer-security.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/buffer-security.cc b/gyp/test/win/compiler-flags/buffer-security.cc
new file mode 100644 (file)
index 0000000..e8a48a2
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <malloc.h>
+#include <string.h>
+
+int main() {
+  char* stuff = reinterpret_cast<char*>(_alloca(256));
+  strcpy(stuff, "blah");
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/character-set-mbcs.cc b/gyp/test/win/compiler-flags/character-set-mbcs.cc
new file mode 100644 (file)
index 0000000..3286304
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _MBCS
+#error
+#endif
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/character-set-unicode.cc b/gyp/test/win/compiler-flags/character-set-unicode.cc
new file mode 100644 (file)
index 0000000..32e6972
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _UNICODE
+#error
+#endif
+
+#ifndef UNICODE
+#error
+#endif
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/character-set.gyp b/gyp/test/win/compiler-flags/character-set.gyp
new file mode 100644 (file)
index 0000000..3dc4555
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_cs_notset',
+      'product_name': 'test_cs_notset',
+      'type': 'executable',
+      'msvs_configuration_attributes': {
+        'CharacterSet': '0'
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_cs_unicode',
+      'product_name': 'test_cs_unicode',
+      'type': 'executable',
+      'msvs_configuration_attributes': {
+        'CharacterSet': '1'
+      },
+      'sources': ['character-set-unicode.cc'],
+    },
+    {
+      'target_name': 'test_cs_mbcs',
+      'product_name': 'test_cs_mbcs',
+      'type': 'executable',
+      'msvs_configuration_attributes': {
+        'CharacterSet': '2'
+      },
+      'sources': ['character-set-mbcs.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/debug-format.gyp b/gyp/test/win/compiler-flags/debug-format.gyp
new file mode 100644 (file)
index 0000000..daaed23
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test-debug-format-off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '0'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test-debug-format-oldstyle',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '1'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test-debug-format-pdb',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test-debug-format-editcontinue',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '4'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/default-char-is-unsigned.cc b/gyp/test/win/compiler-flags/default-char-is-unsigned.cc
new file mode 100644 (file)
index 0000000..beeca2a
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+template <bool>
+struct CompileAssert {
+};
+
+#define COMPILE_ASSERT(expr, msg) \
+  typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+int main() {
+  COMPILE_ASSERT(char(-1) > 0, default_char_is_unsigned);
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/default-char-is-unsigned.gyp b/gyp/test/win/compiler-flags/default-char-is-unsigned.gyp
new file mode 100644 (file)
index 0000000..941e581
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'test_default_char_is_unsigned',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DefaultCharIsUnsigned': 'true',
+        },
+      },
+      'sources': [
+        'default-char-is-unsigned.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/win/compiler-flags/disable-specific-warnings.cc b/gyp/test/win/compiler-flags/disable-specific-warnings.cc
new file mode 100644 (file)
index 0000000..d312f5f
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  // Causes level 1 warning (C4700)
+  int i;
+  return i;
+}
diff --git a/gyp/test/win/compiler-flags/disable-specific-warnings.gyp b/gyp/test/win/compiler-flags/disable-specific-warnings.gyp
new file mode 100644 (file)
index 0000000..d81d694
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_disable_specific_warnings_set',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarnAsError': 'true',
+          'DisableSpecificWarnings': ['4700']
+        }
+      },
+      'sources': ['disable-specific-warnings.cc']
+    },
+    {
+      'target_name': 'test_disable_specific_warnings_unset',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarnAsError': 'true'
+        }
+      },
+      'sources': ['disable-specific-warnings.cc']
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/enable-enhanced-instruction-set.cc b/gyp/test/win/compiler-flags/enable-enhanced-instruction-set.cc
new file mode 100644 (file)
index 0000000..2491f16
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+static const char* GetArchOption() {
+#if _M_IX86_FP == 0
+  return "IA32";
+#elif _M_IX86_FP == 1
+  return "SSE";
+#elif _M_IX86_FP == 2
+#  if !defined(__AVX__)
+  return "SSE2";
+#  else
+  return "AVX";
+#  endif
+#else
+  return "UNSUPPORTED OPTION";
+#endif
+}
+
+int main() {
+  printf("/arch:%s\n", GetArchOption());
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/enable-enhanced-instruction-set.gyp b/gyp/test/win/compiler-flags/enable-enhanced-instruction-set.gyp
new file mode 100644 (file)
index 0000000..44d8ad3
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'sse_extensions',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableEnhancedInstructionSet': '1',  # StreamingSIMDExtensions
+        }
+      },
+      'sources': ['enable-enhanced-instruction-set.cc'],
+    },
+    {
+      'target_name': 'sse2_extensions',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableEnhancedInstructionSet': '2',  # StreamingSIMDExtensions2
+        }
+      },
+      'sources': ['enable-enhanced-instruction-set.cc'],
+    },
+  ],
+  'conditions': [
+    ['MSVS_VERSION[0:4]>"2010"', {
+      'targets': [
+        {
+          'target_name': 'avx_extensions',
+          'type': 'executable',
+          'msvs_settings': {
+            'VCCLCompilerTool': {
+              'EnableEnhancedInstructionSet': '3',  # AdvancedVectorExtensions
+            }
+          },
+          'sources': ['enable-enhanced-instruction-set.cc'],
+        },
+        {
+          'target_name': 'no_extensions',
+          'type': 'executable',
+          'msvs_settings': {
+            'VCCLCompilerTool': {
+              'EnableEnhancedInstructionSet': '4',  # NoExtensions
+            }
+          },
+          'sources': ['enable-enhanced-instruction-set.cc'],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/gyp/test/win/compiler-flags/exception-handling-on.cc b/gyp/test/win/compiler-flags/exception-handling-on.cc
new file mode 100644 (file)
index 0000000..5d9a3af
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <excpt.h>
+#include <stdlib.h>
+
+void fail() {
+   try {
+      int i = 0, j = 1;
+      j /= i;
+   } catch(...) {
+     exit(1);
+   }
+}
+
+int main() {
+   __try {
+      fail();
+   } __except(EXCEPTION_EXECUTE_HANDLER) {
+     return 2;
+   }
+   return 3;
+}
diff --git a/gyp/test/win/compiler-flags/exception-handling.gyp b/gyp/test/win/compiler-flags/exception-handling.gyp
new file mode 100644 (file)
index 0000000..c266768
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    # Optimization disabled so that the exception-causing code is not removed
+    # (divide by zero was getting optimized away in VS2010).
+    {
+      'target_name': 'test_eh_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'ExceptionHandling': '0',
+          'WarnAsError': 'true',
+          'Optimization': '0',
+        }
+      },
+      'sources': ['exception-handling-on.cc'],
+    },
+    {
+      'target_name': 'test_eh_s',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'ExceptionHandling': '1',
+          'WarnAsError': 'true',
+          'Optimization': '0',
+        }
+      },
+      'sources': ['exception-handling-on.cc'],
+    },
+    {
+      'target_name': 'test_eh_a',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'ExceptionHandling': '2',
+          'WarnAsError': 'true',
+          'Optimization': '0',
+        }
+      },
+      'sources': ['exception-handling-on.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/force-include-files-with-precompiled.cc b/gyp/test/win/compiler-flags/force-include-files-with-precompiled.cc
new file mode 100644 (file)
index 0000000..85cb0f3
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+int main() {
+  std::string s;
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/force-include-files.cc b/gyp/test/win/compiler-flags/force-include-files.cc
new file mode 100644 (file)
index 0000000..4a93de5
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  std::list<std::vector<std::string> > l;
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/force-include-files.gyp b/gyp/test/win/compiler-flags/force-include-files.gyp
new file mode 100644 (file)
index 0000000..2031546
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'test_force_include_files',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'ForcedIncludeFiles': ['string', 'vector', 'list'],
+        },
+      },
+      'sources': [
+        'force-include-files.cc',
+      ],
+    },
+    {
+      'target_name': 'test_force_include_with_precompiled',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'ForcedIncludeFiles': ['string'],
+        },
+      },
+      'msvs_precompiled_header': 'stdio.h',
+      'msvs_precompiled_source': 'precomp.cc',
+      'msvs_disabled_warnings': [ 4530, ],
+      'sources': [
+        'force-include-files-with-precompiled.cc',
+        'precomp.cc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/win/compiler-flags/function-level-linking.cc b/gyp/test/win/compiler-flags/function-level-linking.cc
new file mode 100644 (file)
index 0000000..4952272
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int comdat_function() {
+  return 1;
+}
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/function-level-linking.gyp b/gyp/test/win/compiler-flags/function-level-linking.gyp
new file mode 100644 (file)
index 0000000..5858586
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_fll_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableFunctionLevelLinking': 'false'
+        }
+      },
+      'sources': ['function-level-linking.cc'],
+    },
+    {
+      'target_name': 'test_fll_on',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableFunctionLevelLinking': 'true',
+        }
+      },
+      'sources': ['function-level-linking.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/hello.cc b/gyp/test/win/compiler-flags/hello.cc
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/optimizations.gyp b/gyp/test/win/compiler-flags/optimizations.gyp
new file mode 100644 (file)
index 0000000..e63096f
--- /dev/null
@@ -0,0 +1,207 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_opt_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'Optimization': '0'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_lev_size',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'Optimization': '1'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_lev_speed',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'Optimization': '2'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_lev_max',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'Optimization': '3'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_unset',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_fpo',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'OmitFramePointers': 'true'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_fpo_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'OmitFramePointers': 'false'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_intrinsic',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableIntrinsicFunctions': 'true'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_intrinsic_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableIntrinsicFunctions': 'false'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_inline_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'InlineFunctionExpansion': '0'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_inline_manual',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'InlineFunctionExpansion': '1'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_inline_auto',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'InlineFunctionExpansion': '2'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_neither',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'FavorSizeOrSpeed': '0'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_speed',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'FavorSizeOrSpeed': '1'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_size',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'FavorSizeOrSpeed': '2'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_wpo',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WholeProgramOptimization': 'true'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_sp',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'StringPooling': 'true'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_sp_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'StringPooling': 'false'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_fso',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableFiberSafeOptimizations': 'true'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_opt_fso_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableFiberSafeOptimizations': 'false'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/pdbname-override.gyp b/gyp/test/win/compiler-flags/pdbname-override.gyp
new file mode 100644 (file)
index 0000000..dad20e0
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_pdbname',
+      'type': 'executable',
+      'sources': [
+        'hello.cc',
+        'pdbname.cc',
+      ],
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+          'ProgramDataBaseFileName': '<(PRODUCT_DIR)/compiler_generated.pdb',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'ProgramDatabaseFile': '<(PRODUCT_DIR)/linker_generated.pdb',
+        },
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/pdbname.cc b/gyp/test/win/compiler-flags/pdbname.cc
new file mode 100644 (file)
index 0000000..0fe05d5
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int some_function() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/pdbname.gyp b/gyp/test/win/compiler-flags/pdbname.gyp
new file mode 100644 (file)
index 0000000..8fcf754
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_pdbname',
+      'type': 'executable',
+      'sources': [
+        'hello.cc',
+        'pdbname.cc',
+      ],
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+        },
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/precomp.cc b/gyp/test/win/compiler-flags/precomp.cc
new file mode 100644 (file)
index 0000000..d16bac8
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <stdio.h>
diff --git a/gyp/test/win/compiler-flags/rtti-on.cc b/gyp/test/win/compiler-flags/rtti-on.cc
new file mode 100644 (file)
index 0000000..2d3ad03
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _CPPRTTI
+#error
+#endif
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/rtti.gyp b/gyp/test/win/compiler-flags/rtti.gyp
new file mode 100644 (file)
index 0000000..704cd58
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_rtti_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'RuntimeTypeInfo': 'false',
+          'WarnAsError': 'true'
+        }
+      },
+      'sources': ['rtti-on.cc'],
+    },
+    {
+      'target_name': 'test_rtti_on',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'RuntimeTypeInfo': 'true',
+          'WarnAsError': 'true'
+        }
+      },
+      'sources': ['rtti-on.cc'],
+    },
+    {
+      'target_name': 'test_rtti_unset',
+      'type': 'executable',
+      'msvs_settings': {
+      },
+      'sources': ['rtti-on.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/runtime-checks.cc b/gyp/test/win/compiler-flags/runtime-checks.cc
new file mode 100644 (file)
index 0000000..fdb811d
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef __MSVC_RUNTIME_CHECKS
+#error
+#endif
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/runtime-checks.gyp b/gyp/test/win/compiler-flags/runtime-checks.gyp
new file mode 100644 (file)
index 0000000..8ea3092
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_brc_none',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'Optimization': '0',
+        }
+      },
+      'sources': ['runtime-checks.cc'],
+    },
+    {
+      'target_name': 'test_brc_1',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'Optimization': '0',
+          'BasicRuntimeChecks': '3'
+        }
+      },
+      'sources': ['runtime-checks.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/runtime-library-md.cc b/gyp/test/win/compiler-flags/runtime-library-md.cc
new file mode 100644 (file)
index 0000000..87c8302
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _MT
+#error
+#endif
+
+#ifdef _DEBUG
+#error
+#endif
+
+#ifndef _DLL
+#error
+#endif
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/runtime-library-mdd.cc b/gyp/test/win/compiler-flags/runtime-library-mdd.cc
new file mode 100644 (file)
index 0000000..9f175e4
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _MT
+#error
+#endif
+
+#ifndef _DEBUG
+#error
+#endif
+
+#ifndef _DLL
+#error
+#endif
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/runtime-library-mt.cc b/gyp/test/win/compiler-flags/runtime-library-mt.cc
new file mode 100644 (file)
index 0000000..27e62b6
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _MT
+#error
+#endif
+
+#ifdef _DEBUG
+#error
+#endif
+
+#ifdef _DLL
+#error
+#endif
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/runtime-library-mtd.cc b/gyp/test/win/compiler-flags/runtime-library-mtd.cc
new file mode 100644 (file)
index 0000000..a9921db
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _MT
+#error
+#endif
+
+#ifndef _DEBUG
+#error
+#endif
+
+#ifdef _DLL
+#error
+#endif
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/runtime-library.gyp b/gyp/test/win/compiler-flags/runtime-library.gyp
new file mode 100644 (file)
index 0000000..04afc39
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_rl_md',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'RuntimeLibrary': '2'
+        }
+      },
+      'sources': ['runtime-library-md.cc'],
+    },
+    {
+      'target_name': 'test_rl_mdd',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'RuntimeLibrary': '3'
+        }
+      },
+      'sources': ['runtime-library-mdd.cc'],
+    },
+    {
+      'target_name': 'test_rl_mt',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'RuntimeLibrary': '0'
+        }
+      },
+      'sources': ['runtime-library-mt.cc'],
+    },
+    {
+      'target_name': 'test_rl_mtd',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'RuntimeLibrary': '1'
+        }
+      },
+      'sources': ['runtime-library-mtd.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/subdir/header.h b/gyp/test/win/compiler-flags/subdir/header.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type.gyp b/gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type.gyp
new file mode 100644 (file)
index 0000000..456fe04
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'test_treat_wchar_t_as_built_in_type_negative',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'TreatWChar_tAsBuiltInType': 'false',
+        },
+      },
+      'sources': [
+        'treat-wchar-t-as-built-in-type1.cc',
+      ],
+    },
+    {
+      'target_name': 'test_treat_wchar_t_as_built_in_type_positive',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'TreatWChar_tAsBuiltInType': 'true',
+        },
+      },
+      'sources': [
+        'treat-wchar-t-as-built-in-type2.cc',
+      ],
+    },
+
+  ],
+}
diff --git a/gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type1.cc b/gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type1.cc
new file mode 100644 (file)
index 0000000..fc1ed0b
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef _NATIVE_WCHAR_T_DEFINED
+#error
+#endif
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type2.cc b/gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type2.cc
new file mode 100644 (file)
index 0000000..28ab94f
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _NATIVE_WCHAR_T_DEFINED
+#error
+#endif
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/uninit.cc b/gyp/test/win/compiler-flags/uninit.cc
new file mode 100644 (file)
index 0000000..a9d5f5d
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Should trigger C6001: using uninitialized memory <variable> for |i|.
+int f(bool b) {
+  int i;
+  if (b)
+    i = 0;
+  return i;
+}
+
+int main() {}
diff --git a/gyp/test/win/compiler-flags/warning-as-error.cc b/gyp/test/win/compiler-flags/warning-as-error.cc
new file mode 100644 (file)
index 0000000..fd2130a
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  // Cause a warning, even at /W1
+  int export;
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/warning-as-error.gyp b/gyp/test/win/compiler-flags/warning-as-error.gyp
new file mode 100644 (file)
index 0000000..d71f261
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_warn_as_error_false',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarnAsError': 'false'
+        }
+      },
+      'sources': ['warning-as-error.cc']
+    },
+    {
+      'target_name': 'test_warn_as_error_true',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarnAsError': 'true'
+        }
+      },
+      'sources': ['warning-as-error.cc']
+    },
+    {
+      'target_name': 'test_warn_as_error_unset',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+        }
+      },
+      'sources': ['warning-as-error.cc']
+    },
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/warning-level.gyp b/gyp/test/win/compiler-flags/warning-level.gyp
new file mode 100644 (file)
index 0000000..2297aa7
--- /dev/null
@@ -0,0 +1,115 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    # Level 1
+    {
+      'target_name': 'test_wl1_fail',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarningLevel': '1',
+          'WarnAsError': 'true',
+        }
+      },
+      'sources': ['warning-level1.cc'],
+    },
+    {
+      'target_name': 'test_wl1_pass',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarningLevel': '1',
+          'WarnAsError': 'true',
+        }
+      },
+      'sources': ['warning-level2.cc'],
+    },
+
+    # Level 2
+    {
+      'target_name': 'test_wl2_fail',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarningLevel': '2',
+          'WarnAsError': 'true',
+        }
+      },
+      'sources': ['warning-level2.cc'],
+    },
+    {
+      'target_name': 'test_wl2_pass',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarningLevel': '2',
+          'WarnAsError': 'true',
+        }
+      },
+      'sources': ['warning-level3.cc'],
+    },
+
+    # Level 3
+    {
+      'target_name': 'test_wl3_fail',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarningLevel': '3',
+          'WarnAsError': 'true',
+        }
+      },
+      'sources': ['warning-level3.cc'],
+    },
+    {
+      'target_name': 'test_wl3_pass',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarningLevel': '3',
+          'WarnAsError': 'true',
+        }
+      },
+      'sources': ['warning-level4.cc'],
+    },
+
+
+    # Level 4
+    {
+      'target_name': 'test_wl4_fail',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarningLevel': '4',
+          'WarnAsError': 'true',
+        }
+      },
+      'sources': ['warning-level4.cc'],
+    },
+
+    # Default level
+    {
+      'target_name': 'test_def_fail',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarnAsError': 'true',
+        }
+      },
+      'sources': ['warning-level1.cc'],
+    },
+    {
+      'target_name': 'test_def_pass',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+        }
+      },
+      'sources': ['warning-level2.cc'],
+    },
+
+  ]
+}
diff --git a/gyp/test/win/compiler-flags/warning-level1.cc b/gyp/test/win/compiler-flags/warning-level1.cc
new file mode 100644 (file)
index 0000000..119578d
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  int export; // Cause a level 1 warning (C4237).
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/warning-level2.cc b/gyp/test/win/compiler-flags/warning-level2.cc
new file mode 100644 (file)
index 0000000..9a26703
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int f(int x) {
+  return 0;
+}
+
+int main() {
+  double x = 10.1;
+  // Cause a level 2 warning (C4243).
+  return f(x);
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/warning-level3.cc b/gyp/test/win/compiler-flags/warning-level3.cc
new file mode 100644 (file)
index 0000000..e0a9f3c
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Cause a level 3 warning (C4359).
+struct __declspec(align(8)) C8 { __int64 i; };
+struct __declspec(align(4)) C4 { C8 m8; };
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/compiler-flags/warning-level4.cc b/gyp/test/win/compiler-flags/warning-level4.cc
new file mode 100644 (file)
index 0000000..48a4fb7
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  const int i = -1;
+  // Cause a level 4 warning (C4245).
+  unsigned int j = i;
+  return 0;
+}
diff --git a/gyp/test/win/generator-output-different-drive/gyptest-generator-output-different-drive.py b/gyp/test/win/generator-output-different-drive/gyptest-generator-output-different-drive.py
new file mode 100644 (file)
index 0000000..8c8c365
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test that the generator output can be written to a different drive on Windows.
+"""
+
+import os
+import TestGyp
+import string
+import subprocess
+import sys
+
+
+if sys.platform == 'win32':
+  import win32api
+
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  def GetFirstFreeDriveLetter():
+    """ Returns the first unused Windows drive letter in [A, Z] """
+    all_letters = [c for c in string.uppercase]
+    in_use = win32api.GetLogicalDriveStrings()
+    free = list(set(all_letters) - set(in_use))
+    return free[0]
+
+  output_dir = os.path.join('different-drive', 'output')
+  if not os.path.isdir(os.path.abspath(output_dir)):
+    os.makedirs(os.path.abspath(output_dir))
+  output_drive = GetFirstFreeDriveLetter()
+  subprocess.call(['subst', '%c:' % output_drive, os.path.abspath(output_dir)])
+  try:
+    test.run_gyp('prog.gyp', '--generator-output=%s' % (
+        os.path.join(output_drive, 'output')))
+    test.build('prog.gyp', test.ALL, chdir=os.path.join(output_drive, 'output'))
+    test.built_file_must_exist('program', chdir=os.path.join(output_drive,
+                                                             'output'),
+                               type=test.EXECUTABLE)
+    test.pass_test()
+  finally:
+    subprocess.call(['subst', '%c:' % output_drive, '/D'])
diff --git a/gyp/test/win/generator-output-different-drive/prog.c b/gyp/test/win/generator-output-different-drive/prog.c
new file mode 100644 (file)
index 0000000..7937f5d
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+int main(void) {
+  printf("Hello from prog.c\n");
+  return 0;
+}
diff --git a/gyp/test/win/generator-output-different-drive/prog.gyp b/gyp/test/win/generator-output-different-drive/prog.gyp
new file mode 100644 (file)
index 0000000..92f53e5
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'sources': [
+        'prog.c',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/win/gyptest-asm-files.py b/gyp/test/win/gyptest-asm-files.py
new file mode 100644 (file)
index 0000000..007b52e
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure .s files aren't passed to cl.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'asm-files'
+  test.run_gyp('asm-files.gyp', chdir=CHDIR)
+  # The compiler will error out if it's passed the .s files, so just make sure
+  # the build succeeds. The compiler doesn't directly support building
+  # assembler files on Windows, they have to be built explicitly with a
+  # third-party tool.
+  test.build('asm-files.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-additional-include-dirs.py b/gyp/test/win/gyptest-cl-additional-include-dirs.py
new file mode 100644 (file)
index 0000000..1fabfa9
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure additional include dirs are extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('additional-include-dirs.gyp', chdir=CHDIR)
+  test.build('additional-include-dirs.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-additional-options.py b/gyp/test/win/gyptest-cl-additional-options.py
new file mode 100644 (file)
index 0000000..e9aea10
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure additional manual compiler flags are extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('additional-options.gyp', chdir=CHDIR)
+
+  # Warning level not overidden, must fail.
+  test.build('additional-options.gyp', 'test_additional_none', chdir=CHDIR,
+      status=1)
+
+  # Warning level is overridden, must succeed.
+  test.build('additional-options.gyp', 'test_additional_one', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-analysis.py b/gyp/test/win/gyptest-cl-analysis.py
new file mode 100644 (file)
index 0000000..7b3b989
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure PREfast (code analysis) setting is extracted properly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if (sys.platform == 'win32' and
+    int(os.environ.get('GYP_MSVS_VERSION', 0)) >= 2012):
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('analysis.gyp', chdir=CHDIR)
+
+  # Analysis enabled, should fail.
+  test.build('analysis.gyp', 'test_analysis_on', chdir=CHDIR, status=1)
+
+  # Analysis not enabled, or unspecified, should pass.
+  test.build('analysis.gyp', 'test_analysis_off', chdir=CHDIR)
+  test.build('analysis.gyp', 'test_analysis_unspec', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-buffer-security-check.py b/gyp/test/win/gyptest-cl-buffer-security-check.py
new file mode 100644 (file)
index 0000000..e22869c
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure buffer security check setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('buffer-security-check.gyp', chdir=CHDIR)
+  test.build('buffer-security-check.gyp', chdir=CHDIR)
+
+  def GetDisassemblyOfMain(exe):
+    # The standard library uses buffer security checks independent of our
+    # buffer security settings, so we extract just our code (i.e. main()) to
+    # check against.
+    full_path = test.built_file_path(exe, chdir=CHDIR)
+    output = test.run_dumpbin('/disasm', full_path)
+    result = []
+    in_main = False
+    for line in output.splitlines():
+      if line == '_main:':
+        in_main = True
+      elif in_main:
+        # Disassembly of next function starts.
+        if line.startswith('_'):
+          break
+        result.append(line)
+    return '\n'.join(result)
+
+  # Buffer security checks are on by default, make sure security_cookie
+  # appears in the disassembly of our code.
+  if 'security_cookie' not in GetDisassemblyOfMain('test_bsc_unset.exe'):
+    test.fail_test()
+
+  # Explicitly on.
+  if 'security_cookie' not in GetDisassemblyOfMain('test_bsc_on.exe'):
+    test.fail_test()
+
+  # Explicitly off, shouldn't be a reference to the security cookie.
+  if 'security_cookie' in GetDisassemblyOfMain('test_bsc_off.exe'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-character-set.py b/gyp/test/win/gyptest-cl-character-set.py
new file mode 100644 (file)
index 0000000..7fabb67
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure character set setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('character-set.gyp', chdir=CHDIR)
+  test.build('character-set.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-debug-format.py b/gyp/test/win/gyptest-cl-debug-format.py
new file mode 100644 (file)
index 0000000..6c68a61
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure debug format settings are extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('debug-format.gyp', chdir=CHDIR)
+
+  # While there's ways to via .pdb contents, the .pdb doesn't include
+  # which style the debug information was created from, so we resort to just
+  # verifying the flags are correct on the command line.
+
+  ninja_file = test.built_file_path('obj/test-debug-format-off.ninja',
+      chdir=CHDIR)
+  test.must_not_contain(ninja_file, '/Z7')
+  test.must_not_contain(ninja_file, '/Zi')
+  test.must_not_contain(ninja_file, '/ZI')
+
+  ninja_file = test.built_file_path('obj/test-debug-format-oldstyle.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/Z7')
+
+  ninja_file = test.built_file_path('obj/test-debug-format-pdb.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/Zi')
+
+  ninja_file = test.built_file_path('obj/test-debug-format-editcontinue.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/ZI')
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-default-char-is-unsigned.py b/gyp/test/win/gyptest-cl-default-char-is-unsigned.py
new file mode 100644 (file)
index 0000000..d20f674
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure DefaultCharIsUnsigned option is functional.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('default-char-is-unsigned.gyp', chdir=CHDIR)
+  test.build('default-char-is-unsigned.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-disable-specific-warnings.py b/gyp/test/win/gyptest-cl-disable-specific-warnings.py
new file mode 100644 (file)
index 0000000..cb253af
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure disable specific warnings is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('disable-specific-warnings.gyp', chdir=CHDIR)
+
+  # The source file contains a warning, so if WarnAsError is true and
+  # DisableSpecificWarnings for the warning in question is set, then the build
+  # should succeed, otherwise it must fail.
+
+  test.build('disable-specific-warnings.gyp',
+             'test_disable_specific_warnings_set',
+             chdir=CHDIR)
+  test.build('disable-specific-warnings.gyp',
+             'test_disable_specific_warnings_unset',
+             chdir=CHDIR, status=1)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-enable-enhanced-instruction-set.py b/gyp/test/win/gyptest-cl-enable-enhanced-instruction-set.py
new file mode 100644 (file)
index 0000000..5ee4cdd
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test VCCLCompilerTool EnableEnhancedInstructionSet setting.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp()
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('enable-enhanced-instruction-set.gyp', chdir=CHDIR)
+
+  test.build('enable-enhanced-instruction-set.gyp', test.ALL, chdir=CHDIR)
+
+  test.run_built_executable('sse_extensions', chdir=CHDIR,
+                            stdout='/arch:SSE\n')
+  test.run_built_executable('sse2_extensions', chdir=CHDIR,
+                            stdout='/arch:SSE2\n')
+
+  # /arch:AVX introduced in VS2010, but MSBuild support lagged until 2012.
+  if os.path.exists(test.built_file_path('avx_extensions')):
+    test.run_built_executable('no_extensions', chdir=CHDIR,
+                              stdout='/arch:AVX\n')
+
+  # /arch:IA32 introduced in VS2012.
+  if os.path.exists(test.built_file_path('no_extensions')):
+    test.run_built_executable('no_extensions', chdir=CHDIR,
+                              stdout='/arch:IA32\n')
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-exception-handling.py b/gyp/test/win/gyptest-cl-exception-handling.py
new file mode 100644 (file)
index 0000000..5738a54
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure exception handling settings are extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('exception-handling.gyp', chdir=CHDIR)
+
+  # Must fail.
+  test.build('exception-handling.gyp', 'test_eh_off', chdir=CHDIR,
+      status=1)
+
+  # Must succeed.
+  test.build('exception-handling.gyp', 'test_eh_s', chdir=CHDIR)
+  test.build('exception-handling.gyp', 'test_eh_a', chdir=CHDIR)
+
+  # Error code must be 1 if EHa, and 2 if EHsc.
+  test.run_built_executable('test_eh_a', chdir=CHDIR, status=1)
+  test.run_built_executable('test_eh_s', chdir=CHDIR, status=2)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-force-include-files.py b/gyp/test/win/gyptest-cl-force-include-files.py
new file mode 100644 (file)
index 0000000..b73b8bd
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure ForcedIncludeFiles option is functional.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('force-include-files.gyp', chdir=CHDIR)
+  test.build('force-include-files.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-function-level-linking.py b/gyp/test/win/gyptest-cl-function-level-linking.py
new file mode 100644 (file)
index 0000000..17c29e2
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure function-level linking setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('function-level-linking.gyp', chdir=CHDIR)
+  test.build('function-level-linking.gyp', test.ALL, chdir=CHDIR)
+
+  def CheckForSectionString(binary, search_for, should_exist):
+    output = test.run_dumpbin('/headers', binary)
+    if should_exist and search_for not in output:
+      print 'Did not find "%s" in %s' % (search_for, binary)
+      test.fail_test()
+    elif not should_exist and search_for in output:
+      print 'Found "%s" in %s (and shouldn\'t have)' % (search_for, binary)
+      test.fail_test()
+
+  def Object(proj, obj):
+    sep = '.' if test.format == 'ninja' else '\\'
+    return 'obj\\%s%s%s' % (proj, sep, obj)
+
+  look_for = '''COMDAT; sym= "int __cdecl comdat_function'''
+
+  # When function level linking is on, the functions should be listed as
+  # separate comdat entries.
+
+  CheckForSectionString(
+      test.built_file_path(Object('test_fll_on', 'function-level-linking.obj'),
+                           chdir=CHDIR),
+      look_for,
+      should_exist=True)
+
+  CheckForSectionString(
+      test.built_file_path(Object('test_fll_off', 'function-level-linking.obj'),
+                           chdir=CHDIR),
+      look_for,
+      should_exist=False)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-optimizations.py b/gyp/test/win/gyptest-cl-optimizations.py
new file mode 100644 (file)
index 0000000..31341f7
--- /dev/null
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure optimization settings are extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('optimizations.gyp', chdir=CHDIR)
+
+  # It's hard to map flags to output contents in a non-fragile way (especially
+  # handling both 2008/2010), so just verify the correct ninja command line
+  # contents.
+
+  ninja_file = test.built_file_path('obj/test_opt_off.ninja', chdir=CHDIR)
+  test.must_contain(ninja_file, 'cflags = /Od')
+
+  ninja_file = test.built_file_path('obj/test_opt_lev_size.ninja', chdir=CHDIR)
+  test.must_contain(ninja_file, 'cflags = /O1')
+
+  ninja_file = test.built_file_path('obj/test_opt_lev_speed.ninja', chdir=CHDIR)
+  test.must_contain(ninja_file, 'cflags = /O2')
+
+  ninja_file = test.built_file_path('obj/test_opt_lev_max.ninja', chdir=CHDIR)
+  test.must_contain(ninja_file, 'cflags = /Ox')
+
+  ninja_file = test.built_file_path('obj/test_opt_unset.ninja', chdir=CHDIR)
+  test.must_not_contain(ninja_file, '/Od')
+  test.must_not_contain(ninja_file, '/O1')
+  test.must_not_contain(ninja_file, '/Ox')
+  # Set by default if none specified.
+  test.must_contain(ninja_file, '/O2')
+
+  ninja_file = test.built_file_path('obj/test_opt_fpo.ninja', chdir=CHDIR)
+  test.must_contain(ninja_file, '/Oy')
+  test.must_not_contain(ninja_file, '/Oy-')
+
+  ninja_file = test.built_file_path('obj/test_opt_fpo_off.ninja', chdir=CHDIR)
+  test.must_contain(ninja_file, '/Oy-')
+
+  ninja_file = test.built_file_path('obj/test_opt_intrinsic.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/Oi')
+  test.must_not_contain(ninja_file, '/Oi-')
+
+  ninja_file = test.built_file_path('obj/test_opt_intrinsic_off.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/Oi-')
+
+  ninja_file = test.built_file_path('obj/test_opt_inline_off.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/Ob0')
+
+  ninja_file = test.built_file_path('obj/test_opt_inline_manual.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/Ob1')
+
+  ninja_file = test.built_file_path('obj/test_opt_inline_auto.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/Ob2')
+
+  ninja_file = test.built_file_path('obj/test_opt_neither.ninja',
+      chdir=CHDIR)
+  test.must_not_contain(ninja_file, '/Os')
+  test.must_not_contain(ninja_file, '/Ot')
+
+  ninja_file = test.built_file_path('obj/test_opt_size.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/Os')
+
+  ninja_file = test.built_file_path('obj/test_opt_speed.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/Ot')
+
+  ninja_file = test.built_file_path('obj/test_opt_wpo.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/GL')
+
+  ninja_file = test.built_file_path('obj/test_opt_sp.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/GF')
+
+  ninja_file = test.built_file_path('obj/test_opt_sp_off.ninja',
+      chdir=CHDIR)
+  test.must_not_contain(ninja_file, '/GF')
+
+  ninja_file = test.built_file_path('obj/test_opt_fso.ninja',
+      chdir=CHDIR)
+  test.must_contain(ninja_file, '/GT')
+
+  ninja_file = test.built_file_path('obj/test_opt_fso_off.ninja',
+      chdir=CHDIR)
+  test.must_not_contain(ninja_file, '/GT')
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-pdbname-override.py b/gyp/test/win/gyptest-cl-pdbname-override.py
new file mode 100644 (file)
index 0000000..da9b49a
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure pdb is named as expected (shared between .cc files).
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp()
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('pdbname-override.gyp', chdir=CHDIR)
+  test.build('pdbname-override.gyp', test.ALL, chdir=CHDIR)
+
+  # Confirm that the pdb generated by the compiler was renamed (and we also
+  # have the linker generated one).
+  test.built_file_must_exist('compiler_generated.pdb', chdir=CHDIR)
+  test.built_file_must_exist('linker_generated.pdb', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-pdbname.py b/gyp/test/win/gyptest-cl-pdbname.py
new file mode 100644 (file)
index 0000000..f09ac23
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure pdb is named as expected (shared between .cc files).
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('pdbname.gyp', chdir=CHDIR)
+  test.build('pdbname.gyp', test.ALL, chdir=CHDIR)
+
+  # Confirm that the default behaviour is to name the .pdb per-target (rather
+  # than per .cc file).
+  test.built_file_must_exist('obj/test_pdbname.cc.pdb', chdir=CHDIR)
+
+  # Confirm that there should be a .pdb alongside the executable.
+  test.built_file_must_exist('test_pdbname.exe', chdir=CHDIR)
+  test.built_file_must_exist('test_pdbname.exe.pdb', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-rtti.py b/gyp/test/win/gyptest-cl-rtti.py
new file mode 100644 (file)
index 0000000..d49a094
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure RTTI setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('rtti.gyp', chdir=CHDIR)
+
+  # Must fail.
+  test.build('rtti.gyp', 'test_rtti_off', chdir=CHDIR, status=1)
+
+  # Must succeed.
+  test.build('rtti.gyp', 'test_rtti_on', chdir=CHDIR)
+
+  # Must succeed.
+  test.build('rtti.gyp', 'test_rtti_unset', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-runtime-checks.py b/gyp/test/win/gyptest-cl-runtime-checks.py
new file mode 100644 (file)
index 0000000..4fd529f
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure RTC setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('runtime-checks.gyp', chdir=CHDIR)
+
+  # Runtime checks disabled, should fail.
+  test.build('runtime-checks.gyp', 'test_brc_none', chdir=CHDIR, status=1)
+
+  # Runtime checks enabled, should pass.
+  test.build('runtime-checks.gyp', 'test_brc_1', chdir=CHDIR)
+
+  # TODO(scottmg): There are other less frequently used/partial options, but
+  # it's not clear how to verify them, so ignore for now.
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-runtime-library.py b/gyp/test/win/gyptest-cl-runtime-library.py
new file mode 100644 (file)
index 0000000..53c1492
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure runtime C library setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('runtime-library.gyp', chdir=CHDIR)
+  test.build('runtime-library.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-treat-wchar-t-as-built-in-type.py b/gyp/test/win/gyptest-cl-treat-wchar-t-as-built-in-type.py
new file mode 100644 (file)
index 0000000..ca35fb5
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure TreatWChar_tAsBuiltInType option is functional.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('treat-wchar-t-as-built-in-type.gyp', chdir=CHDIR)
+  test.build('treat-wchar-t-as-built-in-type.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-warning-as-error.py b/gyp/test/win/gyptest-cl-warning-as-error.py
new file mode 100644 (file)
index 0000000..d4ef1b3
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure warning-as-error is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('warning-as-error.gyp', chdir=CHDIR)
+
+  # The source file contains a warning, so if WarnAsError is false (or
+  # default, which is also false), then the build should succeed, otherwise it
+  # must fail.
+
+  test.build('warning-as-error.gyp', 'test_warn_as_error_false', chdir=CHDIR)
+  test.build('warning-as-error.gyp', 'test_warn_as_error_unset', chdir=CHDIR)
+  test.build('warning-as-error.gyp', 'test_warn_as_error_true', chdir=CHDIR,
+    status=1)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-cl-warning-level.py b/gyp/test/win/gyptest-cl-warning-level.py
new file mode 100644 (file)
index 0000000..62a5b39
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure warning level is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'compiler-flags'
+  test.run_gyp('warning-level.gyp', chdir=CHDIR)
+
+  # A separate target for each warning level: one pass (compiling a file
+  # containing a warning that's above the specified level); and one fail
+  # (compiling a file at the specified level). No pass for 4 of course,
+  # because it would have to have no warnings. The default warning level is
+  # equivalent to level 1.
+
+  test.build('warning-level.gyp', 'test_wl1_fail', chdir=CHDIR, status=1)
+  test.build('warning-level.gyp', 'test_wl1_pass', chdir=CHDIR)
+
+  test.build('warning-level.gyp', 'test_wl2_fail', chdir=CHDIR, status=1)
+  test.build('warning-level.gyp', 'test_wl2_pass', chdir=CHDIR)
+
+  test.build('warning-level.gyp', 'test_wl3_fail', chdir=CHDIR, status=1)
+  test.build('warning-level.gyp', 'test_wl3_pass', chdir=CHDIR)
+
+  test.build('warning-level.gyp', 'test_wl4_fail', chdir=CHDIR, status=1)
+
+  test.build('warning-level.gyp', 'test_def_fail', chdir=CHDIR, status=1)
+  test.build('warning-level.gyp', 'test_def_pass', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-command-quote.py b/gyp/test/win/gyptest-command-quote.py
new file mode 100644 (file)
index 0000000..652b05b
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+
+Make sure the program in a command can be a called batch file, or an
+application in the path. Specifically, this means not quoting something like
+"call x.bat", lest the shell look for a program named "call x.bat", rather
+than calling "x.bat".
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+  CHDIR = 'command-quote'
+  test.run_gyp('command-quote.gyp', chdir=CHDIR)
+
+  test.build('command-quote.gyp', 'test_batch', chdir=CHDIR)
+  test.build('command-quote.gyp', 'test_call_separate', chdir=CHDIR)
+  test.build('command-quote.gyp', 'test_with_double_quotes', chdir=CHDIR)
+  test.build('command-quote.gyp', 'test_with_single_quotes', chdir=CHDIR)
+
+  # We confirm that this fails because other generators don't handle spaces in
+  # inputs so it's preferable to not have it work here.
+  test.build('command-quote.gyp', 'test_with_spaces', chdir=CHDIR, status=1)
+
+  CHDIR = 'command-quote/subdir/and/another'
+  test.run_gyp('in-subdir.gyp', chdir=CHDIR)
+  test.build('in-subdir.gyp', 'test_batch_depth', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-lib-ltcg.py b/gyp/test/win/gyptest-lib-ltcg.py
new file mode 100644 (file)
index 0000000..d1d7bad
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure LTCG setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'lib-flags'
+  test.run_gyp('ltcg.gyp', chdir=CHDIR)
+  test.build('ltcg.gyp', test.ALL, chdir=CHDIR)
+  test.must_not_contain_any_line(test.stdout(), ['restarting link with /LTCG'])
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-additional-deps.py b/gyp/test/win/gyptest-link-additional-deps.py
new file mode 100644 (file)
index 0000000..62c5736
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure additional library dependencies are handled.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('additional-deps.gyp', chdir=CHDIR)
+  test.build('additional-deps.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-additional-options.py b/gyp/test/win/gyptest-link-additional-options.py
new file mode 100644 (file)
index 0000000..7e57ae4
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure additional options are handled.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('additional-options.gyp', chdir=CHDIR)
+  test.build('additional-options.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-aslr.py b/gyp/test/win/gyptest-link-aslr.py
new file mode 100644 (file)
index 0000000..e765017
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure aslr setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('aslr.gyp', chdir=CHDIR)
+  test.build('aslr.gyp', test.ALL, chdir=CHDIR)
+
+  def HasDynamicBase(exe):
+    full_path = test.built_file_path(exe, chdir=CHDIR)
+    output = test.run_dumpbin('/headers', full_path)
+    return '                   Dynamic base' in output
+
+  # Default is to be on.
+  if not HasDynamicBase('test_aslr_default.exe'):
+    test.fail_test()
+  if HasDynamicBase('test_aslr_no.exe'):
+    test.fail_test()
+  if not HasDynamicBase('test_aslr_yes.exe'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-base-address.py b/gyp/test/win/gyptest-link-base-address.py
new file mode 100644 (file)
index 0000000..f9a5e43
--- /dev/null
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+
+# Copyright 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure the base address setting is extracted properly.
+"""
+
+import TestGyp
+
+import re
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('base-address.gyp', chdir=CHDIR)
+  test.build('base-address.gyp', test.ALL, chdir=CHDIR)
+
+  def GetHeaders(exe):
+    full_path = test.built_file_path(exe, chdir=CHDIR)
+    return test.run_dumpbin('/headers', full_path)
+
+  # Extract the image base address from the headers output.
+  image_base_reg_ex = re.compile('.*\s+([0-9]+) image base.*', re.DOTALL)
+
+  exe_headers = GetHeaders('test_base_specified_exe.exe')
+  exe_match = image_base_reg_ex.match(exe_headers)
+
+  if not exe_match or not exe_match.group(1):
+    test.fail_test()
+  if exe_match.group(1) != '420000':
+    test.fail_test()
+
+  dll_headers = GetHeaders('test_base_specified_dll.dll')
+  dll_match = image_base_reg_ex.match(dll_headers)
+
+  if not dll_match or not dll_match.group(1):
+    test.fail_test()
+  if dll_match.group(1) != '10420000':
+    test.fail_test()
+
+  default_exe_headers = GetHeaders('test_base_default_exe.exe')
+  default_exe_match = image_base_reg_ex.match(default_exe_headers)
+
+  if not default_exe_match or not default_exe_match.group(1):
+    test.fail_test()
+  if default_exe_match.group(1) != '400000':
+    test.fail_test()
+
+  default_dll_headers = GetHeaders('test_base_default_dll.dll')
+  default_dll_match = image_base_reg_ex.match(default_dll_headers)
+
+  if not default_dll_match or not default_dll_match.group(1):
+    test.fail_test()
+  if default_dll_match.group(1) != '10000000':
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-debug-info.py b/gyp/test/win/gyptest-link-debug-info.py
new file mode 100644 (file)
index 0000000..33e8ac4
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure debug info setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('debug-info.gyp', chdir=CHDIR)
+  test.build('debug-info.gyp', test.ALL, chdir=CHDIR)
+
+  suffix = '.exe.pdb' if test.format == 'ninja' else '.pdb'
+  test.built_file_must_not_exist('test_debug_off%s' % suffix, chdir=CHDIR)
+  test.built_file_must_exist('test_debug_on%s' % suffix, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-default-libs.py b/gyp/test/win/gyptest-link-default-libs.py
new file mode 100644 (file)
index 0000000..5edf467
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure we include the default libs.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('no-default-libs.gyp', chdir=CHDIR)
+  test.build('no-default-libs.gyp', test.ALL, chdir=CHDIR, status=1)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-deffile.py b/gyp/test/win/gyptest-link-deffile.py
new file mode 100644 (file)
index 0000000..94df874
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure a .def file is handled in the link.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+
+  # Multiple .def files doesn't make any sense, should fail at generate time.
+  test.run_gyp('deffile-multiple.gyp', chdir=CHDIR, stderr=None, status=1)
+
+  test.run_gyp('deffile.gyp', chdir=CHDIR)
+  test.build('deffile.gyp', test.ALL, chdir=CHDIR)
+
+  def HasExport(binary, export):
+    full_path = test.built_file_path(binary, chdir=CHDIR)
+    output = test.run_dumpbin('/exports', full_path)
+    return export in output
+
+  # Make sure we only have the export when the .def file is in use.
+
+  if HasExport('test_deffile_dll_notexported.dll', 'AnExportedFunction'):
+    test.fail_test()
+  if not HasExport('test_deffile_dll_ok.dll', 'AnExportedFunction'):
+    test.fail_test()
+
+  if HasExport('test_deffile_exe_notexported.exe', 'AnExportedFunction'):
+    test.fail_test()
+  if not HasExport('test_deffile_exe_ok.exe', 'AnExportedFunction'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-defrelink.py b/gyp/test/win/gyptest-link-defrelink.py
new file mode 100644 (file)
index 0000000..7f2642f
--- /dev/null
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure a relink is performed when a .def file is touched.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  target = 'test_deffile_dll_ok'
+  def_contents = test.read('linker-flags/deffile.def')
+
+  # This first build makes sure everything is up to date.
+  test.run_gyp('deffile.gyp', chdir=CHDIR)
+  test.build('deffile.gyp', target, chdir=CHDIR)
+  test.up_to_date('deffile.gyp', target, chdir=CHDIR)
+
+  def HasExport(binary, export):
+    full_path = test.built_file_path(binary, chdir=CHDIR)
+    output = test.run_dumpbin('/exports', full_path)
+    return export in output
+
+  # Verify that only one function is exported.
+  if not HasExport('test_deffile_dll_ok.dll', 'AnExportedFunction'):
+    test.fail_test()
+  if HasExport('test_deffile_dll_ok.dll', 'AnotherExportedFunction'):
+    test.fail_test()
+
+  # Add AnotherExportedFunction to the def file, then rebuild.  If it doesn't
+  # relink the DLL, then the subsequent check for AnotherExportedFunction will
+  # fail.
+  new_def_contents = def_contents + "\n    AnotherExportedFunction"
+  test.write('linker-flags/deffile.def', new_def_contents)
+  test.build('deffile.gyp', target, chdir=CHDIR)
+  test.up_to_date('deffile.gyp', target, chdir=CHDIR)
+
+  if not HasExport('test_deffile_dll_ok.dll', 'AnExportedFunction'):
+    test.fail_test()
+  if not HasExport('test_deffile_dll_ok.dll', 'AnotherExportedFunction'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-delay-load-dlls.py b/gyp/test/win/gyptest-link-delay-load-dlls.py
new file mode 100644 (file)
index 0000000..3880247
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure delay load setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('delay-load-dlls.gyp', chdir=CHDIR)
+  test.build('delay-load-dlls.gyp', test.ALL, chdir=CHDIR)
+
+  prefix = 'contains the following delay load imports:'
+  shell32_look_for = prefix + '\r\n\r\n    SHELL32.dll'
+
+  output = test.run_dumpbin(
+      '/all', test.built_file_path('test_dld_none.exe', chdir=CHDIR))
+  if prefix in output:
+    test.fail_test()
+
+  output = test.run_dumpbin(
+      '/all', test.built_file_path('test_dld_shell32.exe', chdir=CHDIR))
+  if shell32_look_for not in output:
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-embed-manifest.py b/gyp/test/win/gyptest-link-embed-manifest.py
new file mode 100644 (file)
index 0000000..5b9d2c2
--- /dev/null
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Yandex LLC. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure manifests are embedded in binaries properly. Handling of
+AdditionalManifestFiles is tested too.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  import pywintypes
+  import win32api
+  import winerror
+
+  RT_MANIFEST = 24
+
+  class LoadLibrary(object):
+    """Context manager for loading and releasing binaries in Windows.
+    Yields the handle of the binary loaded."""
+    def __init__(self, path):
+      self._path = path
+      self._handle = None
+
+    def __enter__(self):
+      self._handle = win32api.LoadLibrary(self._path)
+      return self._handle
+
+    def __exit__(self, type, value, traceback):
+      win32api.FreeLibrary(self._handle)
+
+
+  def extract_manifest(path, resource_name):
+    """Reads manifest from |path| and returns it as a string.
+    Returns None is there is no such manifest."""
+    with LoadLibrary(path) as handle:
+      try:
+        return win32api.LoadResource(handle, RT_MANIFEST, resource_name)
+      except pywintypes.error as error:
+        if error.args[0] == winerror.ERROR_RESOURCE_DATA_NOT_FOUND:
+          return None
+        else:
+          raise
+
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+  CHDIR = 'linker-flags'
+  test.run_gyp('embed-manifest.gyp', chdir=CHDIR)
+  test.build('embed-manifest.gyp', test.ALL, chdir=CHDIR)
+
+  # The following binaries must contain a manifest embedded.
+  test.fail_test(not extract_manifest(test.built_file_path(
+    'test_manifest_exe.exe', chdir=CHDIR), 1))
+  test.fail_test(not extract_manifest(test.built_file_path(
+    'test_manifest_exe_inc.exe', chdir=CHDIR), 1))
+  test.fail_test(not extract_manifest(test.built_file_path(
+    'test_manifest_dll.dll', chdir=CHDIR), 2))
+  test.fail_test(not extract_manifest(test.built_file_path(
+    'test_manifest_dll_inc.dll', chdir=CHDIR), 2))
+
+  # Must contain the Win7 support GUID, but not the Vista one (from
+  # extra2.manifest).
+  test.fail_test(
+    '35138b9a-5d96-4fbd-8e2d-a2440225f93a' not in
+    extract_manifest(test.built_file_path('test_manifest_extra1.exe',
+                                            chdir=CHDIR), 1))
+  test.fail_test(
+    'e2011457-1546-43c5-a5fe-008deee3d3f0' in
+    extract_manifest(test.built_file_path('test_manifest_extra1.exe',
+                                            chdir=CHDIR), 1))
+  # Must contain both.
+  test.fail_test(
+    '35138b9a-5d96-4fbd-8e2d-a2440225f93a' not in
+    extract_manifest(test.built_file_path('test_manifest_extra2.exe',
+                                            chdir=CHDIR), 1))
+  test.fail_test(
+    'e2011457-1546-43c5-a5fe-008deee3d3f0' not in
+    extract_manifest(test.built_file_path('test_manifest_extra2.exe',
+                                            chdir=CHDIR), 1))
+
+  # Same as extra2, but using list syntax instead.
+  test.fail_test(
+    '35138b9a-5d96-4fbd-8e2d-a2440225f93a' not in
+    extract_manifest(test.built_file_path('test_manifest_extra_list.exe',
+                                          chdir=CHDIR), 1))
+  test.fail_test(
+    'e2011457-1546-43c5-a5fe-008deee3d3f0' not in
+    extract_manifest(test.built_file_path('test_manifest_extra_list.exe',
+                                          chdir=CHDIR), 1))
+
+  # Test that incremental linking doesn't force manifest embedding.
+  test.fail_test(extract_manifest(test.built_file_path(
+    'test_manifest_exe_inc_no_embed.exe', chdir=CHDIR), 1))
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-enable-uac.py b/gyp/test/win/gyptest-link-enable-uac.py
new file mode 100644 (file)
index 0000000..131e07e
--- /dev/null
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+# Copyright 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that embedding UAC information into the manifest works.
+"""
+
+import TestGyp
+
+import sys
+from xml.dom.minidom import parseString
+
+if sys.platform == 'win32':
+  import pywintypes
+  import win32api
+  import winerror
+
+  RT_MANIFEST = 24
+
+  class LoadLibrary(object):
+    """Context manager for loading and releasing binaries in Windows.
+    Yields the handle of the binary loaded."""
+    def __init__(self, path):
+      self._path = path
+      self._handle = None
+
+    def __enter__(self):
+      self._handle = win32api.LoadLibrary(self._path)
+      return self._handle
+
+    def __exit__(self, type, value, traceback):
+      win32api.FreeLibrary(self._handle)
+
+
+  def extract_manifest(path, resource_name):
+    """Reads manifest from |path| and returns it as a string.
+    Returns None is there is no such manifest."""
+    with LoadLibrary(path) as handle:
+      try:
+        return win32api.LoadResource(handle, RT_MANIFEST, resource_name)
+      except pywintypes.error as error:
+        if error.args[0] == winerror.ERROR_RESOURCE_DATA_NOT_FOUND:
+          return None
+        else:
+          raise
+
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+  CHDIR = 'linker-flags'
+  test.run_gyp('enable-uac.gyp', chdir=CHDIR)
+  test.build('enable-uac.gyp', test.ALL, chdir=CHDIR)
+
+  # The following binaries must contain a manifest embedded.
+  test.fail_test(not extract_manifest(test.built_file_path(
+    'enable_uac.exe', chdir=CHDIR), 1))
+  test.fail_test(not extract_manifest(test.built_file_path(
+    'enable_uac_no.exe', chdir=CHDIR), 1))
+  test.fail_test(not extract_manifest(test.built_file_path(
+    'enable_uac_admin.exe', chdir=CHDIR), 1))
+
+  # Verify that <requestedExecutionLevel level="asInvoker" uiAccess="false" />
+  # is present.
+  manifest = parseString(extract_manifest(
+      test.built_file_path('enable_uac.exe', chdir=CHDIR), 1))
+  execution_level = manifest.getElementsByTagName('requestedExecutionLevel')
+  test.fail_test(len(execution_level) != 1)
+  execution_level = execution_level[0].attributes
+  test.fail_test(not (
+      execution_level.has_key('level') and
+      execution_level.has_key('uiAccess') and
+      execution_level['level'].nodeValue == 'asInvoker' and
+      execution_level['uiAccess'].nodeValue == 'false'))
+
+  # Verify that <requestedExecutionLevel> is not in the menifest.
+  manifest = parseString(extract_manifest(
+      test.built_file_path('enable_uac_no.exe', chdir=CHDIR), 1))
+  execution_level = manifest.getElementsByTagName('requestedExecutionLevel')
+  test.fail_test(len(execution_level) != 0)
+
+  # Verify that <requestedExecutionLevel level="requireAdministrator"
+  # uiAccess="true" /> is present.
+  manifest = parseString(extract_manifest(
+      test.built_file_path('enable_uac_admin.exe', chdir=CHDIR), 1))
+  execution_level = manifest.getElementsByTagName('requestedExecutionLevel')
+  test.fail_test(len(execution_level) != 1)
+  execution_level = execution_level[0].attributes
+  test.fail_test(not (
+      execution_level.has_key('level') and
+      execution_level.has_key('uiAccess') and
+      execution_level['level'].nodeValue == 'requireAdministrator' and
+      execution_level['uiAccess'].nodeValue == 'true'))
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-entrypointsymbol.py b/gyp/test/win/gyptest-link-entrypointsymbol.py
new file mode 100644 (file)
index 0000000..e88174a
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure entrypointsymbol setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('entrypointsymbol.gyp', chdir=CHDIR)
+
+  test.build('entrypointsymbol.gyp', 'test_ok', chdir=CHDIR)
+  test.build('entrypointsymbol.gyp', 'test_fail', chdir=CHDIR, status=1)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-fixed-base.py b/gyp/test/win/gyptest-link-fixed-base.py
new file mode 100644 (file)
index 0000000..725a870
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure fixed base setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('fixed-base.gyp', chdir=CHDIR)
+  test.build('fixed-base.gyp', test.ALL, chdir=CHDIR)
+
+  def GetHeaders(exe):
+    full_path = test.built_file_path(exe, chdir=CHDIR)
+    return test.run_dumpbin('/headers', full_path)
+
+  # For exe, default is fixed, for dll, it's not fixed.
+  if 'Relocations stripped' not in GetHeaders('test_fixed_default_exe.exe'):
+    test.fail_test()
+  if 'Relocations stripped' in GetHeaders('test_fixed_default_dll.dll'):
+    test.fail_test()
+
+  # Explicitly not fixed.
+  if 'Relocations stripped' in GetHeaders('test_fixed_no.exe'):
+    test.fail_test()
+
+  # Explicitly fixed.
+  if 'Relocations stripped' not in GetHeaders('test_fixed_yes.exe'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-force-symbol-reference.py b/gyp/test/win/gyptest-link-force-symbol-reference.py
new file mode 100644 (file)
index 0000000..235e94f
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure ForceSymbolReference is translated properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('force-symbol-reference.gyp', chdir=CHDIR)
+  test.build('force-symbol-reference.gyp', test.ALL, chdir=CHDIR)
+
+  output = test.run_dumpbin(
+      '/disasm', test.built_file_path('test_force_reference.exe', chdir=CHDIR))
+  if '?x@@YAHXZ:' not in output or '?y@@YAHXZ:' not in output:
+    test.fail_test()
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-generate-manifest.py b/gyp/test/win/gyptest-link-generate-manifest.py
new file mode 100644 (file)
index 0000000..77c9228
--- /dev/null
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure we generate a manifest file when linking binaries, including
+handling AdditionalManifestFiles.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  import pywintypes
+  import win32api
+  import winerror
+
+  RT_MANIFEST = 24
+
+  class LoadLibrary(object):
+    """Context manager for loading and releasing binaries in Windows.
+    Yields the handle of the binary loaded."""
+    def __init__(self, path):
+      self._path = path
+      self._handle = None
+
+    def __enter__(self):
+      self._handle = win32api.LoadLibrary(self._path)
+      return self._handle
+
+    def __exit__(self, type, value, traceback):
+      win32api.FreeLibrary(self._handle)
+
+  def extract_manifest(path, resource_name):
+    """Reads manifest from |path| and returns it as a string.
+    Returns None is there is no such manifest."""
+    with LoadLibrary(path) as handle:
+      try:
+        return win32api.LoadResource(handle, RT_MANIFEST, resource_name)
+      except pywintypes.error as error:
+        if error.args[0] == winerror.ERROR_RESOURCE_DATA_NOT_FOUND:
+          return None
+        else:
+          raise
+
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('generate-manifest.gyp', chdir=CHDIR)
+  test.build('generate-manifest.gyp', test.ALL, chdir=CHDIR)
+
+  # Make sure that generation of .generated.manifest does not cause a relink.
+  test.run_gyp('generate-manifest.gyp', chdir=CHDIR)
+  test.up_to_date('generate-manifest.gyp', test.ALL, chdir=CHDIR)
+
+  def test_manifest(filename, generate_manifest, embedded_manifest,
+                    extra_manifest):
+    exe_file = test.built_file_path(filename, chdir=CHDIR)
+    if not generate_manifest:
+      test.must_not_exist(exe_file + '.manifest')
+      manifest = extract_manifest(exe_file, 1)
+      test.fail_test(manifest)
+      return
+    if embedded_manifest:
+      manifest = extract_manifest(exe_file, 1)
+      test.fail_test(not manifest)
+    else:
+      test.must_exist(exe_file + '.manifest')
+      manifest = test.read(exe_file + '.manifest')
+      test.fail_test(not manifest)
+      test.fail_test(extract_manifest(exe_file, 1))
+    if generate_manifest:
+      test.must_contain_any_line(manifest, 'requestedExecutionLevel')
+    if extra_manifest:
+      test.must_contain_any_line(manifest,
+                                 '35138b9a-5d96-4fbd-8e2d-a2440225f93a')
+      test.must_contain_any_line(manifest,
+                                 'e2011457-1546-43c5-a5fe-008deee3d3f0')
+
+  test_manifest('test_generate_manifest_true.exe',
+                generate_manifest=True,
+                embedded_manifest=False,
+                extra_manifest=False)
+  test_manifest('test_generate_manifest_false.exe',
+                generate_manifest=False,
+                embedded_manifest=False,
+                extra_manifest=False)
+  test_manifest('test_generate_manifest_default.exe',
+                generate_manifest=True,
+                embedded_manifest=False,
+                extra_manifest=False)
+  test_manifest('test_generate_manifest_true_as_embedded.exe',
+                generate_manifest=True,
+                embedded_manifest=True,
+                extra_manifest=False)
+  test_manifest('test_generate_manifest_false_as_embedded.exe',
+                generate_manifest=False,
+                embedded_manifest=True,
+                extra_manifest=False)
+  test_manifest('test_generate_manifest_default_as_embedded.exe',
+                generate_manifest=True,
+                embedded_manifest=True,
+                extra_manifest=False)
+  test_manifest('test_generate_manifest_true_with_extra_manifest.exe',
+                generate_manifest=True,
+                embedded_manifest=False,
+                extra_manifest=True)
+  test_manifest('test_generate_manifest_false_with_extra_manifest.exe',
+                generate_manifest=False,
+                embedded_manifest=False,
+                extra_manifest=True)
+  test_manifest('test_generate_manifest_true_with_extra_manifest_list.exe',
+                generate_manifest=True,
+                embedded_manifest=False,
+                extra_manifest=True)
+  test_manifest('test_generate_manifest_false_with_extra_manifest_list.exe',
+                generate_manifest=False,
+                embedded_manifest=False,
+                extra_manifest=True)
+  test_manifest('test_generate_manifest_default_embed_default.exe',
+                generate_manifest=True,
+                embedded_manifest=True,
+                extra_manifest=False)
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-incremental.py b/gyp/test/win/gyptest-link-incremental.py
new file mode 100644 (file)
index 0000000..e7184e1
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure incremental linking setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('incremental.gyp', chdir=CHDIR)
+  test.build('incremental.gyp', test.ALL, chdir=CHDIR)
+
+  def HasILTTables(exe):
+    full_path = test.built_file_path(exe, chdir=CHDIR)
+    output = test.run_dumpbin('/disasm', full_path)
+    return '@ILT+' in output
+
+  # Default or unset is to be on.
+  if not HasILTTables('test_incremental_unset.exe'):
+    test.fail_test()
+  if not HasILTTables('test_incremental_default.exe'):
+    test.fail_test()
+  if HasILTTables('test_incremental_no.exe'):
+    test.fail_test()
+  if not HasILTTables('test_incremental_yes.exe'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-large-address-aware.py b/gyp/test/win/gyptest-link-large-address-aware.py
new file mode 100644 (file)
index 0000000..ea433f2
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure largeaddressaware setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('large-address-aware.gyp', chdir=CHDIR)
+  test.build('large-address-aware.gyp', test.ALL, chdir=CHDIR)
+
+  def GetHeaders(exe):
+    return test.run_dumpbin('/headers', test.built_file_path(exe, chdir=CHDIR))
+
+  MARKER = 'Application can handle large (>2GB) addresses'
+
+  # Explicitly off.
+  if MARKER in GetHeaders('test_large_address_aware_no.exe'):
+    test.fail_test()
+
+  # Explicitly on.
+  if MARKER not in GetHeaders('test_large_address_aware_yes.exe'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-large-pdb.py b/gyp/test/win/gyptest-link-large-pdb.py
new file mode 100644 (file)
index 0000000..f91001c
--- /dev/null
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure msvs_large_pdb works correctly.
+"""
+
+import TestGyp
+
+import struct
+import sys
+
+
+CHDIR = 'large-pdb'
+
+
+def CheckImageAndPdb(test, image_basename, expected_page_size,
+                     pdb_basename=None):
+  if not pdb_basename:
+    pdb_basename = image_basename + '.pdb'
+  test.built_file_must_exist(image_basename, chdir=CHDIR)
+  test.built_file_must_exist(pdb_basename, chdir=CHDIR)
+
+  # We expect the PDB to have the given page size. For full details of the
+  # header look here: https://code.google.com/p/pdbparser/wiki/MSF_Format
+  # We read the little-endian 4-byte unsigned integer at position 32 of the
+  # file.
+  pdb_path = test.built_file_path(pdb_basename, chdir=CHDIR)
+  pdb_file = open(pdb_path, 'rb')
+  pdb_file.seek(32, 0)
+  page_size = struct.unpack('<I', pdb_file.read(4))[0]
+  if page_size != expected_page_size:
+    print "Expected page size of %d, got %d for PDB file `%s'." % (
+        expected_page_size, page_size, pdb_path)
+
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  test.run_gyp('large-pdb.gyp', chdir=CHDIR)
+
+  test.build('large-pdb.gyp', 'large_pdb_exe', chdir=CHDIR)
+  CheckImageAndPdb(test, 'large_pdb_exe.exe', 4096)
+
+  test.build('large-pdb.gyp', 'small_pdb_exe', chdir=CHDIR)
+  CheckImageAndPdb(test, 'small_pdb_exe.exe', 1024)
+
+  test.build('large-pdb.gyp', 'large_pdb_dll', chdir=CHDIR)
+  CheckImageAndPdb(test, 'large_pdb_dll.dll', 4096)
+
+  test.build('large-pdb.gyp', 'small_pdb_dll', chdir=CHDIR)
+  CheckImageAndPdb(test, 'small_pdb_dll.dll', 1024)
+
+  test.build('large-pdb.gyp', 'large_pdb_implicit_exe', chdir=CHDIR)
+  CheckImageAndPdb(test, 'large_pdb_implicit_exe.exe', 4096)
+
+  # This target has a different PDB name because it uses an
+  # 'msvs_large_pdb_path' variable.
+  test.build('large-pdb.gyp', 'large_pdb_variable_exe', chdir=CHDIR)
+  CheckImageAndPdb(test, 'large_pdb_variable_exe.exe', 4096,
+                   pdb_basename='foo.pdb')
+
+  # This target has a different output name because it uses 'product_name'.
+  test.build('large-pdb.gyp', 'large_pdb_product_exe', chdir=CHDIR)
+  CheckImageAndPdb(test, 'bar.exe', 4096)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-library-adjust.py b/gyp/test/win/gyptest-link-library-adjust.py
new file mode 100644 (file)
index 0000000..71d1c09
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure link_settings containing -lblah.lib is remapped to just blah.lib.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('library-adjust.gyp', chdir=CHDIR)
+  test.build('library-adjust.gyp', test.ALL, chdir=CHDIR)
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-library-directories.py b/gyp/test/win/gyptest-link-library-directories.py
new file mode 100644 (file)
index 0000000..8308e14
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure libpath is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+
+  # Build subdirectory library.
+  test.run_gyp('subdir/library.gyp', chdir=CHDIR)
+  test.build('subdir/library.gyp', test.ALL, chdir=CHDIR)
+
+  # And then try to link the main project against the library using only
+  # LIBPATH to find it.
+  test.run_gyp('library-directories.gyp', chdir=CHDIR)
+
+  # Without additional paths specified, should fail.
+  test.build('library-directories.gyp', 'test_libdirs_none', chdir=CHDIR,
+      status=1)
+
+  # With the additional library directory, should pass.
+  test.build('library-directories.gyp', 'test_libdirs_with', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-ltcg.py b/gyp/test/win/gyptest-link-ltcg.py
new file mode 100644 (file)
index 0000000..529e06e
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure LTCG is working properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('ltcg.gyp', chdir=CHDIR)
+
+  # Here we expect LTCG is able to inline functions beyond compile unit.
+  # Note: This marker is embedded in 'inline_test_main.cc'
+  INLINE_MARKER = '==== inlined ===='
+
+  # test 'LinkTimeCodeGenerationOptionDefault'
+  test.build('ltcg.gyp', 'test_ltcg_off', chdir=CHDIR)
+  test.run_built_executable('test_ltcg_off', chdir=CHDIR)
+  test.must_not_contain_any_line(test.stdout(), [INLINE_MARKER])
+
+  # test 'LinkTimeCodeGenerationOptionUse'
+  test.build('ltcg.gyp', 'test_ltcg_on', chdir=CHDIR)
+  test.must_contain_any_line(test.stdout(), ['Generating code'])
+  test.run_built_executable('test_ltcg_on', chdir=CHDIR)
+  test.must_contain_any_line(test.stdout(), [INLINE_MARKER])
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-mapfile.py b/gyp/test/win/gyptest-link-mapfile.py
new file mode 100644 (file)
index 0000000..00c1dea
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure mapfile settings are extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('mapfile.gyp', chdir=CHDIR)
+  test.build('mapfile.gyp', test.ALL, chdir=CHDIR)
+
+  map_file = test.built_file_path('test_mapfile_unset.map', chdir=CHDIR)
+  test.must_not_exist(map_file)
+
+  map_file = test.built_file_path('test_mapfile_generate.map', chdir=CHDIR)
+  test.must_exist(map_file)
+  test.must_contain(map_file, '?AnExportedFunction@@YAXXZ')
+  test.must_not_contain(map_file, 'void __cdecl AnExportedFunction(void)')
+
+  map_file = test.built_file_path('test_mapfile_generate_exports.map',
+          chdir=CHDIR)
+  test.must_exist(map_file)
+  test.must_contain(map_file, 'void __cdecl AnExportedFunction(void)')
+
+  map_file = test.built_file_path('test_mapfile_generate_filename.map',
+          chdir=CHDIR)
+  test.must_not_exist(map_file)
+
+  map_file = test.built_file_path('custom_file_name.map', chdir=CHDIR)
+  test.must_exist(map_file)
+  test.must_contain(map_file, '?AnExportedFunction@@YAXXZ')
+  test.must_not_contain(map_file, 'void __cdecl AnExportedFunction(void)')
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-nodefaultlib.py b/gyp/test/win/gyptest-link-nodefaultlib.py
new file mode 100644 (file)
index 0000000..f00760b
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure nodefaultlib setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('nodefaultlib.gyp', chdir=CHDIR)
+
+  test.build('nodefaultlib.gyp', 'test_ok', chdir=CHDIR)
+  test.build('nodefaultlib.gyp', 'test_fail', chdir=CHDIR, status=1)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-nxcompat.py b/gyp/test/win/gyptest-link-nxcompat.py
new file mode 100644 (file)
index 0000000..6600743
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure nxcompat setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('nxcompat.gyp', chdir=CHDIR)
+  test.build('nxcompat.gyp', test.ALL, chdir=CHDIR)
+
+  def GetHeaders(exe):
+    return test.run_dumpbin('/headers', test.built_file_path(exe, chdir=CHDIR))
+
+  # NXCOMPAT is on by default.
+  if 'NX compatible' not in GetHeaders('test_nxcompat_default.exe'):
+    test.fail_test()
+
+  # Explicitly off, should not be marked NX compatiable.
+  if 'NX compatible' in GetHeaders('test_nxcompat_no.exe'):
+    test.fail_test()
+
+  # Explicitly on.
+  if 'NX compatible' not in GetHeaders('test_nxcompat_yes.exe'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-opt-icf.py b/gyp/test/win/gyptest-link-opt-icf.py
new file mode 100644 (file)
index 0000000..3c48ef6
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure comdat folding optimization setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('opt-icf.gyp', chdir=CHDIR)
+  test.build('opt-icf.gyp', chdir=CHDIR)
+
+  # We're specifying /DEBUG so the default is to not merge identical
+  # functions, so all of the similar_functions should be preserved.
+  output = test.run_dumpbin(
+      '/disasm', test.built_file_path('test_opticf_default.exe', chdir=CHDIR))
+  if output.count('similar_function') != 6: # 3 definitions, 3 calls.
+    test.fail_test()
+
+  # Explicitly off, all functions preserved seperately.
+  output = test.run_dumpbin(
+      '/disasm', test.built_file_path('test_opticf_no.exe', chdir=CHDIR))
+  if output.count('similar_function') != 6: # 3 definitions, 3 calls.
+    test.fail_test()
+
+  # Explicitly on, all but one removed.
+  output = test.run_dumpbin(
+      '/disasm', test.built_file_path('test_opticf_yes.exe', chdir=CHDIR))
+  if output.count('similar_function') != 4: # 1 definition, 3 calls.
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-opt-ref.py b/gyp/test/win/gyptest-link-opt-ref.py
new file mode 100644 (file)
index 0000000..586b7af
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure reference optimization setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('opt-ref.gyp', chdir=CHDIR)
+  test.build('opt-ref.gyp', chdir=CHDIR)
+
+  # We're specifying /DEBUG so the default is to not remove unused functions.
+  output = test.run_dumpbin(
+      '/disasm', test.built_file_path('test_optref_default.exe', chdir=CHDIR))
+  if 'unused_function' not in output:
+    test.fail_test()
+
+  # Explicitly off, unused_function preserved.
+  output = test.run_dumpbin(
+      '/disasm', test.built_file_path('test_optref_no.exe', chdir=CHDIR))
+  if 'unused_function' not in output:
+    test.fail_test()
+
+  # Explicitly on, should be removed.
+  output = test.run_dumpbin(
+      '/disasm', test.built_file_path('test_optref_yes.exe', chdir=CHDIR))
+  if 'unused_function' in output:
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-ordering.py b/gyp/test/win/gyptest-link-ordering.py
new file mode 100644 (file)
index 0000000..a2527fa
--- /dev/null
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure the link order of object files is the same between msvs and ninja.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('link-ordering.gyp', chdir=CHDIR)
+  test.build('link-ordering.gyp', test.ALL, chdir=CHDIR)
+
+  def GetDisasm(exe):
+    full_path = test.built_file_path(exe, chdir=CHDIR)
+    # Get disassembly and drop int3 padding between functions.
+    return '\n'.join(
+        x for x in test.run_dumpbin('/disasm', full_path).splitlines()
+                   if 'CC' not in x)
+
+  # This is the full dump that we expect. The source files in the .gyp match
+  # this order which is what determines the ordering in the binary.
+
+  expected_disasm_basic = '''
+_mainCRTStartup:
+  00401000: B8 05 00 00 00     mov         eax,5
+  00401005: C3                 ret
+?z@@YAHXZ:
+  00401010: B8 03 00 00 00     mov         eax,3
+  00401015: C3                 ret
+?x@@YAHXZ:
+  00401020: B8 01 00 00 00     mov         eax,1
+  00401025: C3                 ret
+?y@@YAHXZ:
+  00401030: B8 02 00 00 00     mov         eax,2
+  00401035: C3                 ret
+_main:
+  00401040: 33 C0              xor         eax,eax
+  00401042: C3                 ret
+'''
+
+  if expected_disasm_basic not in GetDisasm('test_ordering_exe.exe'):
+    print GetDisasm('test_ordering_exe.exe')
+    test.fail_test()
+
+  # Similar to above. The VS generator handles subdirectories differently.
+
+  expected_disasm_subdirs = '''
+_mainCRTStartup:
+  00401000: B8 05 00 00 00     mov         eax,5
+  00401005: C3                 ret
+_main:
+  00401010: 33 C0              xor         eax,eax
+  00401012: C3                 ret
+?y@@YAHXZ:
+  00401020: B8 02 00 00 00     mov         eax,2
+  00401025: C3                 ret
+?z@@YAHXZ:
+  00401030: B8 03 00 00 00     mov         eax,3
+  00401035: C3                 ret
+'''
+
+  if expected_disasm_subdirs not in GetDisasm('test_ordering_subdirs.exe'):
+    print GetDisasm('test_ordering_subdirs.exe')
+    test.fail_test()
+
+  # Similar, but with directories mixed into folders (crt and main at the same
+  # level, but with a subdir in the middle).
+
+  expected_disasm_subdirs_mixed = '''
+_mainCRTStartup:
+  00401000: B8 05 00 00 00     mov         eax,5
+  00401005: C3                 ret
+?x@@YAHXZ:
+  00401010: B8 01 00 00 00     mov         eax,1
+  00401015: C3                 ret
+_main:
+  00401020: 33 C0              xor         eax,eax
+  00401022: C3                 ret
+?z@@YAHXZ:
+  00401030: B8 03 00 00 00     mov         eax,3
+  00401035: C3                 ret
+?y@@YAHXZ:
+  00401040: B8 02 00 00 00     mov         eax,2
+  00401045: C3                 ret
+'''
+
+  if (expected_disasm_subdirs_mixed not in
+      GetDisasm('test_ordering_subdirs_mixed.exe')):
+    print GetDisasm('test_ordering_subdirs_mixed.exe')
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-outputfile.py b/gyp/test/win/gyptest-link-outputfile.py
new file mode 100644 (file)
index 0000000..b98cdff
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure linker OutputFile setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('outputfile.gyp', chdir=CHDIR)
+  test.build('outputfile.gyp', test.ALL, chdir=CHDIR)
+
+  test.built_file_must_exist('blorp.exe', chdir=CHDIR)
+  test.built_file_must_exist('blorp.dll', chdir=CHDIR)
+  test.built_file_must_exist('subdir/blorp.exe', chdir=CHDIR)
+  test.built_file_must_exist('blorp.lib', chdir=CHDIR)
+  test.built_file_must_exist('subdir/blorp.lib', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-pdb-output.py b/gyp/test/win/gyptest-link-pdb-output.py
new file mode 100644 (file)
index 0000000..8080410
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Ensure that ninja includes the .pdb as an output file from linking.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+  CHDIR = 'linker-flags'
+  test.run_gyp('pdb-output.gyp', chdir=CHDIR)
+  # Note, building the pdbs rather than ALL or gyp target.
+  test.build('pdb-output.gyp', 'output_exe.pdb', chdir=CHDIR)
+  test.build('pdb-output.gyp', 'output_dll.pdb', chdir=CHDIR)
+
+  def FindFile(pdb):
+    full_path = test.built_file_path(pdb, chdir=CHDIR)
+    return os.path.isfile(full_path)
+
+  if not FindFile('output_exe.pdb'):
+    test.fail_test()
+  if not FindFile('output_dll.pdb'):
+    test.fail_test()
+
+  test.pass_test()
+
diff --git a/gyp/test/win/gyptest-link-pdb.py b/gyp/test/win/gyptest-link-pdb.py
new file mode 100644 (file)
index 0000000..26d744d
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that the 'ProgramDatabaseFile' attribute in VCLinker is extracted
+properly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+  CHDIR = 'linker-flags'
+  test.run_gyp('program-database.gyp', chdir=CHDIR)
+  test.build('program-database.gyp', test.ALL, chdir=CHDIR)
+
+  def FindFile(pdb):
+    full_path = test.built_file_path(pdb, chdir=CHDIR)
+    return os.path.isfile(full_path)
+
+  # Verify the specified PDB is created when ProgramDatabaseFile
+  # is provided.
+  if not FindFile('name_outdir.pdb'):
+    test.fail_test()
+  if not FindFile('name_proddir.pdb'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-pgo.py b/gyp/test/win/gyptest-link-pgo.py
new file mode 100644 (file)
index 0000000..d742047
--- /dev/null
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure PGO is working properly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('pgo.gyp', chdir=CHDIR)
+
+  def IsPGOAvailable():
+    """Returns true if the Visual Studio available here supports PGO."""
+    test.build('pgo.gyp', 'gen_linker_option', chdir=CHDIR)
+    tmpfile = test.read(test.built_file_path('linker_options.txt', chdir=CHDIR))
+    return any(line.find('PGOPTIMIZE') for line in tmpfile)
+
+  # Test generated build files look fine.
+  if test.format == 'ninja':
+    ninja = test.built_file_path('obj/test_pgo_instrument.ninja', chdir=CHDIR)
+    test.must_contain(ninja, '/LTCG:PGINSTRUMENT')
+    test.must_contain(ninja, 'test_pgo.pgd')
+    ninja = test.built_file_path('obj/test_pgo_optimize.ninja', chdir=CHDIR)
+    test.must_contain(ninja, '/LTCG:PGOPTIMIZE')
+    test.must_contain(ninja, 'test_pgo.pgd')
+    ninja = test.built_file_path('obj/test_pgo_update.ninja', chdir=CHDIR)
+    test.must_contain(ninja, '/LTCG:PGUPDATE')
+    test.must_contain(ninja, 'test_pgo.pgd')
+  elif test.format == 'msvs':
+    LTCG_FORMAT = '<LinkTimeCodeGeneration>%s</LinkTimeCodeGeneration>'
+    vcproj = test.workpath('linker-flags/test_pgo_instrument.vcxproj')
+    test.must_contain(vcproj, LTCG_FORMAT % 'PGInstrument')
+    test.must_contain(vcproj, 'test_pgo.pgd')
+    vcproj = test.workpath('linker-flags/test_pgo_optimize.vcxproj')
+    test.must_contain(vcproj, LTCG_FORMAT % 'PGOptimization')
+    test.must_contain(vcproj, 'test_pgo.pgd')
+    vcproj = test.workpath('linker-flags/test_pgo_update.vcxproj')
+    test.must_contain(vcproj, LTCG_FORMAT % 'PGUpdate')
+    test.must_contain(vcproj, 'test_pgo.pgd')
+
+  # When PGO is available, try building binaries with PGO.
+  if IsPGOAvailable():
+    pgd_path = test.built_file_path('test_pgo.pgd', chdir=CHDIR)
+
+    # Test if 'PGInstrument' generates PGD (Profile-Guided Database) file.
+    if os.path.exists(pgd_path):
+      test.unlink(pgd_path)
+    test.must_not_exist(pgd_path)
+    test.build('pgo.gyp', 'test_pgo_instrument', chdir=CHDIR)
+    test.must_exist(pgd_path)
+
+    # Test if 'PGOptimize' works well
+    test.build('pgo.gyp', 'test_pgo_optimize', chdir=CHDIR)
+    test.must_contain_any_line(test.stdout(), ['profiled functions'])
+
+    # Test if 'PGUpdate' works well
+    test.build('pgo.gyp', 'test_pgo_update', chdir=CHDIR)
+    # With 'PGUpdate', linker should not complain that sources are changed after
+    # the previous training run.
+    test.touch(test.workpath('linker-flags/inline_test_main.cc'))
+    test.unlink(test.built_file_path('test_pgo_update.exe', chdir=CHDIR))
+    test.build('pgo.gyp', 'test_pgo_update', chdir=CHDIR)
+    test.must_contain_any_line(test.stdout(), ['profiled functions'])
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-profile.py b/gyp/test/win/gyptest-link-profile.py
new file mode 100644 (file)
index 0000000..34fb58a
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that the 'Profile' attribute in VCLinker is extracted properly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+  CHDIR = 'linker-flags'
+  test.run_gyp('profile.gyp', chdir=CHDIR)
+  test.build('profile.gyp', test.ALL, chdir=CHDIR)
+
+  def GetSummary(exe):
+    full_path = test.built_file_path(exe, chdir=CHDIR)
+    return test.run_dumpbin(full_path)
+
+  # '.idata' section will be missing when /PROFILE is enabled.
+  if '.idata' in GetSummary('test_profile_true.exe'):
+    test.fail_test()
+
+  if not '.idata' in GetSummary('test_profile_false.exe'):
+    test.fail_test()
+
+  if not '.idata' in GetSummary('test_profile_default.exe'):
+    test.fail_test()
+
+  test.pass_test()
\ No newline at end of file
diff --git a/gyp/test/win/gyptest-link-restat-importlib.py b/gyp/test/win/gyptest-link-restat-importlib.py
new file mode 100644 (file)
index 0000000..76b5c3c
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure we don't cause unnecessary builds due to import libs appearing
+to be out of date.
+"""
+
+import TestGyp
+
+import os
+import sys
+import time
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  if not os.environ.get('ProgramFiles(x86)'):
+    # TODO(scottmg)
+    print 'Skipping test on x86, http://crbug.com/365833'
+    test.pass_test()
+
+  CHDIR = 'importlib'
+  test.run_gyp('importlib.gyp', chdir=CHDIR)
+  test.build('importlib.gyp', test.ALL, chdir=CHDIR)
+
+  # Delay briefly so that there's time for this touch not to have the
+  # timestamp as the previous run.
+  test.sleep()
+
+  # Touch the .cc file; the .dll will rebuild, but the import libs timestamp
+  # won't be updated.
+  test.touch('importlib/has-exports.cc')
+  test.build('importlib.gyp', 'test_importlib', chdir=CHDIR)
+
+  # This is the important part. The .dll above will relink and have an updated
+  # timestamp, however the import .libs timestamp won't be updated. So, we
+  # have to handle restating inputs in ninja so the final binary doesn't
+  # continually relink (due to thinking the .lib isn't up to date).
+  test.up_to_date('importlib.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-safeseh.py b/gyp/test/win/gyptest-link-safeseh.py
new file mode 100644 (file)
index 0000000..0d84009
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure safeseh setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('safeseh.gyp', chdir=CHDIR)
+  test.build('safeseh.gyp', test.ALL, chdir=CHDIR)
+
+  def HasSafeExceptionHandlers(exe):
+    full_path = test.built_file_path(exe, chdir=CHDIR)
+    output = test.run_dumpbin('/LOADCONFIG', full_path)
+    return '    Safe Exception Handler Table' in output
+
+  # From MSDN: http://msdn.microsoft.com/en-us/library/9a89h429.aspx
+  #   If /SAFESEH is not specified, the linker will produce an image with a
+  #   table of safe exceptions handlers if all modules are compatible with
+  #   the safe exception handling feature. If any modules were not
+  #   compatible with safe exception handling feature, the resulting image
+  #   will not contain a table of safe exception handlers.
+  if HasSafeExceptionHandlers('test_safeseh_default.exe'):
+    test.fail_test()
+  if HasSafeExceptionHandlers('test_safeseh_no.exe'):
+    test.fail_test()
+  if not HasSafeExceptionHandlers('test_safeseh_yes.exe'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-shard.py b/gyp/test/win/gyptest-link-shard.py
new file mode 100644 (file)
index 0000000..9af9328
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure msvs_shard works correctly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'shard'
+  test.run_gyp('shard.gyp', chdir=CHDIR)
+  test.build('shard.gyp', test.ALL, chdir=CHDIR)
+
+  test.built_file_must_exist('shard_0.lib', chdir=CHDIR)
+  test.built_file_must_exist('shard_1.lib', chdir=CHDIR)
+  test.built_file_must_exist('shard_2.lib', chdir=CHDIR)
+  test.built_file_must_exist('shard_3.lib', chdir=CHDIR)
+
+  test.run_gyp('shard_ref.gyp', chdir=CHDIR)
+  test.build('shard_ref.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-subsystem.py b/gyp/test/win/gyptest-link-subsystem.py
new file mode 100644 (file)
index 0000000..a94ba36
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure subsystem setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('subsystem.gyp', chdir=CHDIR)
+
+  test.build('subsystem.gyp', 'test_console_ok', chdir=CHDIR)
+  test.build('subsystem.gyp', 'test_console_fail', chdir=CHDIR, status=1)
+  test.build('subsystem.gyp', 'test_windows_ok', chdir=CHDIR)
+  test.build('subsystem.gyp', 'test_windows_fail', chdir=CHDIR, status=1)
+
+  test.build('subsystem.gyp', 'test_console_xp', chdir=CHDIR)
+  test.build('subsystem.gyp', 'test_windows_xp', chdir=CHDIR)
+  # Make sure we are targeting XP.
+  def GetHeaders(exe):
+    return test.run_dumpbin('/headers', test.built_file_path(exe, chdir=CHDIR))
+  if '5.01 subsystem version' not in GetHeaders('test_console_xp.exe'):
+    test.fail_test()
+  if '5.01 subsystem version' not in GetHeaders('test_windows_xp.exe'):
+    test.fail_test()
+
+  # TODO(scottmg): There are other subsystems (WinCE, etc.) that we don't use.
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-target-machine.py b/gyp/test/win/gyptest-link-target-machine.py
new file mode 100644 (file)
index 0000000..5a15f3f
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure TargetMachine setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('target-machine.gyp', chdir=CHDIR)
+  # The .cc file is compiled as x86 (the default), so the link/libs that are
+  # x64 need to fail.
+  test.build('target-machine.gyp', 'test_target_link_x86', chdir=CHDIR)
+  test.build(
+      'target-machine.gyp', 'test_target_link_x64', chdir=CHDIR, status=1)
+  test.build('target-machine.gyp', 'test_target_lib_x86', chdir=CHDIR)
+  test.build('target-machine.gyp', 'test_target_lib_x64', chdir=CHDIR, status=1)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-tsaware.py b/gyp/test/win/gyptest-link-tsaware.py
new file mode 100644 (file)
index 0000000..d34b3c2
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure tsaware setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('tsaware.gyp', chdir=CHDIR)
+  test.build('tsaware.gyp', test.ALL, chdir=CHDIR)
+
+  def GetHeaders(exe):
+    return test.run_dumpbin('/headers', test.built_file_path(exe, chdir=CHDIR))
+
+  # Explicitly off, should not be marked NX compatiable.
+  if 'Terminal Server Aware' in GetHeaders('test_tsaware_no.exe'):
+    test.fail_test()
+
+  # Explicitly on.
+  if 'Terminal Server Aware' not in GetHeaders('test_tsaware_yes.exe'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-uldi.py b/gyp/test/win/gyptest-link-uldi.py
new file mode 100644 (file)
index 0000000..62c5892
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure that when ULDI is on, we link .objs that make up .libs rather than
+the .libs themselves.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'uldi'
+  test.run_gyp('uldi.gyp', chdir=CHDIR)
+  # When linking with ULDI, the duplicated function from the lib will be an
+  # error.
+  test.build('uldi.gyp', 'final_uldi', chdir=CHDIR, status=1)
+  # And when in libs, the duplicated function will be silently dropped, so the
+  # build succeeds.
+  test.build('uldi.gyp', 'final_no_uldi', chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-unsupported-manifest.py b/gyp/test/win/gyptest-link-unsupported-manifest.py
new file mode 100644 (file)
index 0000000..8f7e12b
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure we error out if #pragma comments are used to modify manifests.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  # This assertion only applies to the ninja build.
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('unsupported-manifest.gyp', chdir=CHDIR)
+
+  # Just needs to fail to build.
+  test.build('unsupported-manifest.gyp',
+      'test_unsupported', chdir=CHDIR, status=1)
+  test.must_not_exist(test.built_file_path('test_unsupported.exe', chdir=CHDIR))
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-link-update-manifest.py b/gyp/test/win/gyptest-link-update-manifest.py
new file mode 100644 (file)
index 0000000..4f8b2b9
--- /dev/null
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure binary is relinked when manifest settings are changed.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+  import pywintypes
+  import win32api
+  import winerror
+
+  RT_MANIFEST = 24
+
+  class LoadLibrary(object):
+    """Context manager for loading and releasing binaries in Windows.
+    Yields the handle of the binary loaded."""
+    def __init__(self, path):
+      self._path = path
+      self._handle = None
+
+    def __enter__(self):
+      self._handle = win32api.LoadLibrary(self._path)
+      return self._handle
+
+    def __exit__(self, type, value, traceback):
+      win32api.FreeLibrary(self._handle)
+
+  def extract_manifest(path, resource_name):
+    """Reads manifest from |path| and returns it as a string.
+    Returns None is there is no such manifest."""
+    with LoadLibrary(path) as handle:
+      try:
+        return win32api.LoadResource(handle, RT_MANIFEST, resource_name)
+      except pywintypes.error as error:
+        if error.args[0] == winerror.ERROR_RESOURCE_DATA_NOT_FOUND:
+          return None
+        else:
+          raise
+
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+
+  gyp_template = '''
+{
+ 'targets': [
+    {
+      'target_name': 'test_update_manifest',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+          'UACExecutionLevel': '%(uac_execution_level)d',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+          'AdditionalManifestFiles': '%(additional_manifest_files)s',
+        },
+      },
+    },
+  ],
+}
+'''
+
+  gypfile = 'update-manifest.gyp'
+
+  def WriteAndUpdate(uac_execution_level, additional_manifest_files, do_build):
+    with open(os.path.join(CHDIR, gypfile), 'wb') as f:
+      f.write(gyp_template % {
+        'uac_execution_level': uac_execution_level,
+        'additional_manifest_files': additional_manifest_files,
+      })
+    test.run_gyp(gypfile, chdir=CHDIR)
+    if do_build:
+      test.build(gypfile, chdir=CHDIR)
+      exe_file = test.built_file_path('test_update_manifest.exe', chdir=CHDIR)
+      return extract_manifest(exe_file, 1)
+
+  manifest = WriteAndUpdate(0, '', True)
+  test.fail_test('asInvoker' not in manifest)
+  test.fail_test('35138b9a-5d96-4fbd-8e2d-a2440225f93a' in manifest)
+
+  # Make sure that updating .gyp and regenerating doesn't cause a rebuild.
+  WriteAndUpdate(0, '', False)
+  test.up_to_date(gypfile, test.ALL, chdir=CHDIR)
+
+  # But make sure that changing a manifest property does cause a relink.
+  manifest = WriteAndUpdate(2, '', True)
+  test.fail_test('requireAdministrator' not in manifest)
+
+  # Adding a manifest causes a rebuild.
+  manifest = WriteAndUpdate(2, 'extra.manifest', True)
+  test.fail_test('35138b9a-5d96-4fbd-8e2d-a2440225f93a' not in manifest)
diff --git a/gyp/test/win/gyptest-link-warnings-as-errors.py b/gyp/test/win/gyptest-link-warnings-as-errors.py
new file mode 100644 (file)
index 0000000..d6a6473
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure linker warnings-as-errors setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('warn-as-error.gyp', chdir=CHDIR)
+
+  test.build('warn-as-error.gyp', 'test_on', chdir=CHDIR, status=1)
+  test.build('warn-as-error.gyp', 'test_off', chdir=CHDIR)
+  test.build('warn-as-error.gyp', 'test_default', chdir=CHDIR)
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-long-command-line.py b/gyp/test/win/gyptest-long-command-line.py
new file mode 100644 (file)
index 0000000..8f8b7a3
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure long command lines work.
+"""
+
+import TestGyp
+
+import subprocess
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja', 'msvs'])
+
+  CHDIR = 'long-command-line'
+  test.run_gyp('long-command-line.gyp', chdir=CHDIR)
+  test.build('long-command-line.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-macro-projectname.py b/gyp/test/win/gyptest-macro-projectname.py
new file mode 100644 (file)
index 0000000..e411cc0
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure macro expansion of $(ProjectName) is handled.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'vs-macros'
+  test.run_gyp('projectname.gyp', chdir=CHDIR)
+  test.build('projectname.gyp', test.ALL, chdir=CHDIR)
+  test.built_file_must_exist('test_expansions_plus_something.exe', chdir=CHDIR)
+  test.built_file_must_exist(
+      'test_with_product_name_plus_something.exe', chdir=CHDIR)
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-macro-targetname.py b/gyp/test/win/gyptest-macro-targetname.py
new file mode 100644 (file)
index 0000000..b111801
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure macro expansion of $(TargetName) and $(TargetDir) are handled.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'vs-macros'
+  test.run_gyp('targetname.gyp', chdir=CHDIR)
+  test.build('targetname.gyp', test.ALL, chdir=CHDIR)
+  test.built_file_must_exist('test_targetname_plus_something1.exe',
+          chdir=CHDIR)
+  test.built_file_must_exist(
+          'prod_prefixtest_targetname_with_prefix_plus_something2.exe',
+          chdir=CHDIR)
+  test.built_file_must_exist('prod_name_plus_something3.exe', chdir=CHDIR)
+  test.built_file_must_exist('prod_prefixprod_name_plus_something4.exe',
+          chdir=CHDIR)
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-macro-vcinstalldir.py b/gyp/test/win/gyptest-macro-vcinstalldir.py
new file mode 100644 (file)
index 0000000..37396e1
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure macro expansion of $(VCInstallDir) is handled, and specifically
+always / terminated for compatibility.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'vs-macros'
+  test.run_gyp('vcinstalldir.gyp', chdir=CHDIR)
+  # This fails on VS because the trailing slash escapes the trailing quote.
+  test.build('vcinstalldir.gyp', 'test_slash_trailing', chdir=CHDIR, status=1)
+  test.build('vcinstalldir.gyp', 'test_slash_dir', chdir=CHDIR)
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-macros-containing-gyp.py b/gyp/test/win/gyptest-macros-containing-gyp.py
new file mode 100644 (file)
index 0000000..f6eaf63
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Handle VS macro expansion containing gyp variables.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'vs-macros'
+  test.run_gyp('containing-gyp.gyp', chdir=CHDIR)
+  test.build('containing-gyp.gyp', test.ALL, chdir=CHDIR)
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-macros-in-inputs-and-outputs.py b/gyp/test/win/gyptest-macros-in-inputs-and-outputs.py
new file mode 100644 (file)
index 0000000..3d6fa74
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Handle macro expansion in inputs and outputs of rules.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'vs-macros'
+  test.run_gyp('input-output-macros.gyp', chdir=CHDIR)
+
+  test.build('input-output-macros.gyp', 'test_expansions', chdir=CHDIR)
+
+  test.built_file_must_exist('stuff.blah.something',
+      content='Random data file.\nModified.',
+      chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-midl-excluded.py b/gyp/test/win/gyptest-midl-excluded.py
new file mode 100644 (file)
index 0000000..70059ab
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test that .idl files in actions and non-native rules are excluded.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'idl-excluded'
+  test.run_gyp('idl-excluded.gyp', chdir=CHDIR)
+  test.build('idl-excluded.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-midl-rules.py b/gyp/test/win/gyptest-midl-rules.py
new file mode 100644 (file)
index 0000000..591a507
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Handle default .idl build rules.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'idl-rules'
+  test.run_gyp('basic-idl.gyp', chdir=CHDIR)
+  for platform in ['Win32', 'x64']:
+    test.set_configuration('Debug|%s' % platform)
+    test.build('basic-idl.gyp', test.ALL, chdir=CHDIR)
+
+    # Make sure ninja win_tool.py filters out noisy lines.
+    if test.format == 'ninja' and 'Processing' in test.stdout():
+      test.fail_test()
+
+    test.pass_test()
diff --git a/gyp/test/win/gyptest-ml-safeseh.py b/gyp/test/win/gyptest-ml-safeseh.py
new file mode 100644 (file)
index 0000000..ec702b9
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure the /safeseh option can be passed to ml.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  CHDIR = 'ml-safeseh'
+  test.run_gyp('ml-safeseh.gyp', chdir=CHDIR)
+  test.build('ml-safeseh.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-quoting-commands.py b/gyp/test/win/gyptest-quoting-commands.py
new file mode 100644 (file)
index 0000000..b40f99f
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure batch files run as actions. Regression test for previously missing
+trailing quote on command line. cmd typically will implicitly insert a missing
+quote, but if the command ends in a quote, it will not insert another, so the
+command can sometimes become unterminated.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'batch-file-action'
+  test.run_gyp('batch-file-action.gyp', chdir=CHDIR)
+  test.build('batch-file-action.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-rc-build.py b/gyp/test/win/gyptest-rc-build.py
new file mode 100644 (file)
index 0000000..fd27290
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure we build and include .rc files.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'rc-build'
+  test.run_gyp('hello.gyp', chdir=CHDIR)
+  test.build('hello.gyp', test.ALL, chdir=CHDIR)
+  test.up_to_date('hello.gyp', 'resource_only_dll', chdir=CHDIR)
+  test.run_built_executable('with_resources', chdir=CHDIR, status=4)
+
+  test.pass_test()
diff --git a/gyp/test/win/gyptest-system-include.py b/gyp/test/win/gyptest-system-include.py
new file mode 100644 (file)
index 0000000..9a47d98
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Checks that msvs_system_include_dirs works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+  CHDIR = 'system-include'
+  test.run_gyp('test.gyp', chdir=CHDIR)
+  test.build('test.gyp', test.ALL, chdir=CHDIR)
+  test.pass_test()
diff --git a/gyp/test/win/idl-excluded/bad.idl b/gyp/test/win/idl-excluded/bad.idl
new file mode 100644 (file)
index 0000000..38554e9
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+This is a dummy .idl file that will trigger an error if it is not excluded from
+the build.
diff --git a/gyp/test/win/idl-excluded/copy-file.py b/gyp/test/win/idl-excluded/copy-file.py
new file mode 100644 (file)
index 0000000..5a5feae
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import sys
+
+contents = open(sys.argv[1], 'r').read()
+open(sys.argv[2], 'wb').write(contents)
+
+sys.exit(0)
diff --git a/gyp/test/win/idl-excluded/idl-excluded.gyp b/gyp/test/win/idl-excluded/idl-excluded.gyp
new file mode 100644 (file)
index 0000000..972b7de
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'exclude_with_action',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'actions': [{
+        'action_name': 'copy_action',
+        'inputs': [
+          'copy-file.py',
+          'bad.idl',
+        ],
+        'outputs': [
+          '<(INTERMEDIATE_DIR)/bad.idl',
+        ],
+        'action': [
+          'python', '<@(_inputs)', '<@(_outputs)',
+        ],
+      }],
+    },
+    {
+      'target_name': 'exclude_with_rule',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'sources': [
+        'bad.idl',
+      ],
+      'rules': [{
+        'rule_name': 'copy_rule',
+        'extension': 'idl',
+        'inputs': [
+          'copy-file.py',
+        ],
+        'outputs': [
+          '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).idl',
+        ],
+        'action': [
+          'python', '<@(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+        ],
+      }],
+    },
+    {
+      'target_name': 'program',
+      'type': 'executable',
+      'sources': [
+        'program.cc',
+      ],
+      'dependencies': [
+        'exclude_with_action',
+        'exclude_with_rule',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/win/idl-excluded/program.cc b/gyp/test/win/idl-excluded/program.cc
new file mode 100644 (file)
index 0000000..9dc3c94
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/idl-rules/Window.idl b/gyp/test/win/idl-rules/Window.idl
new file mode 100644 (file)
index 0000000..d8ea01b
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+    WillBeGarbageCollected,
+] interface Window {
+    void alert();
+};
diff --git a/gyp/test/win/idl-rules/basic-idl.gyp b/gyp/test/win/idl-rules/basic-idl.gyp
new file mode 100644 (file)
index 0000000..b74622a
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'midl_out_dir': '<(SHARED_INTERMEDIATE_DIR)',
+  },
+  'target_defaults': {
+    'configurations': {
+      'Debug': {
+        'msvs_configuration_platform': 'Win32',
+      },
+      'Debug_x64': {
+        'inherit_from': ['Debug'],
+        'msvs_configuration_platform': 'x64',
+      },
+    },
+  },
+  'targets': [
+    {
+      'target_name': 'idl_test',
+      'type': 'executable',
+      'sources': [
+        'history_indexer.idl',
+        '<(midl_out_dir)/history_indexer.h',
+        '<(midl_out_dir)/history_indexer_i.c',
+        'history_indexer_user.cc',
+      ],
+      'libraries': ['ole32.lib'],
+      'include_dirs': [
+        '<(midl_out_dir)',
+      ],
+      'msvs_settings': {
+        'VCMIDLTool': {
+          'OutputDirectory': '<(midl_out_dir)',
+          'HeaderFileName': '<(RULE_INPUT_ROOT).h',
+         },
+      },
+    },
+    {
+      'target_name': 'idl_explicit_action',
+      'type': 'none',
+      'sources': [
+        'Window.idl',
+      ],
+      'actions': [{
+        'action_name': 'blink_idl',
+        'explicit_idl_action': 1,
+        'msvs_cygwin_shell': 0,
+        'inputs': [
+          'Window.idl',
+          'idl_compiler.py',
+        ],
+        'outputs': [
+          'Window.cpp',
+          'Window.h',
+        ],
+        'action': [
+          'python',
+          'idl_compiler.py',
+          'Window.idl',
+        ],
+      }],
+    },
+  ],
+}
diff --git a/gyp/test/win/idl-rules/history_indexer.idl b/gyp/test/win/idl-rules/history_indexer.idl
new file mode 100644 (file)
index 0000000..e866ce6
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.\r
+// Use of this source code is governed by a BSD-style license that can be\r
+// found in the LICENSE file.\r
+\r
+import "oaidl.idl";\r
+import "ocidl.idl";\r
+\r
+[\r
+  object,\r
+  uuid(9C1100DD-51D4-4827-AE9F-3B8FAC4AED72),\r
+  oleautomation,\r
+  nonextensible,\r
+  pointer_default(unique)\r
+]\r
+interface IChromeHistoryIndexer : IUnknown {\r
+  HRESULT SomeFunction([in] VARIANT begin_time, [in] VARIANT end_time);\r
+};\r
diff --git a/gyp/test/win/idl-rules/history_indexer_user.cc b/gyp/test/win/idl-rules/history_indexer_user.cc
new file mode 100644 (file)
index 0000000..071a9ff
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "history_indexer.h"
+
+// Use the thing in the IDL.
+int main() {
+  IChromeHistoryIndexer** indexer = 0;
+  IID fake_iid;
+  CoCreateInstance(fake_iid, NULL, CLSCTX_INPROC,
+                   __uuidof(IChromeHistoryIndexer),
+                   reinterpret_cast<void**>(indexer));
+  return 0;
+}
diff --git a/gyp/test/win/idl-rules/idl_compiler.py b/gyp/test/win/idl-rules/idl_compiler.py
new file mode 100644 (file)
index 0000000..a12b274
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# mock, just outputs empty .h/.cpp files
+
+import os
+import sys
+
+if len(sys.argv) == 2:
+  basename, ext = os.path.splitext(sys.argv[1])
+  with open('%s.h' % basename, 'w') as f:
+    f.write('// %s.h\n' % basename)
+  with open('%s.cpp' % basename, 'w') as f:
+    f.write('// %s.cpp\n' % basename)
diff --git a/gyp/test/win/importlib/has-exports.cc b/gyp/test/win/importlib/has-exports.cc
new file mode 100644 (file)
index 0000000..3f62d6c
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+__declspec(dllexport) void some_function() {
+}
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/importlib/hello.cc b/gyp/test/win/importlib/hello.cc
new file mode 100644 (file)
index 0000000..66ff68c
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+__declspec(dllimport) void some_function();
+
+int main() {
+  some_function();
+}
diff --git a/gyp/test/win/importlib/importlib.gyp b/gyp/test/win/importlib/importlib.gyp
new file mode 100644 (file)
index 0000000..ab15b18
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_importlib',
+      'type': 'shared_library',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkIncremental': '2',
+        }
+      },
+      'sources': ['has-exports.cc'],
+    },
+
+    {
+      'target_name': 'test_linkagainst',
+      'type': 'executable',
+      'dependencies': ['test_importlib'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkIncremental': '2',
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/large-pdb/dllmain.cc b/gyp/test/win/large-pdb/dllmain.cc
new file mode 100644 (file)
index 0000000..1487562
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved) {
+  return TRUE;
+}
diff --git a/gyp/test/win/large-pdb/large-pdb.gyp b/gyp/test/win/large-pdb/large-pdb.gyp
new file mode 100644 (file)
index 0000000..2a241a5
--- /dev/null
@@ -0,0 +1,98 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'large_pdb_exe',
+      'type': 'executable',
+      'msvs_large_pdb': 1,
+      'sources': [
+        'main.cc',
+      ],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'ProgramDatabaseFile': '<(PRODUCT_DIR)/large_pdb_exe.exe.pdb',
+        },
+      },
+    },
+    {
+      'target_name': 'small_pdb_exe',
+      'type': 'executable',
+      'msvs_large_pdb': 0,
+      'sources': [
+        'main.cc',
+      ],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'ProgramDatabaseFile': '<(PRODUCT_DIR)/small_pdb_exe.exe.pdb',
+        },
+      },
+    },
+    {
+      'target_name': 'large_pdb_dll',
+      'type': 'shared_library',
+      'msvs_large_pdb': 1,
+      'sources': [
+        'dllmain.cc',
+      ],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'ProgramDatabaseFile': '<(PRODUCT_DIR)/large_pdb_dll.dll.pdb',
+        },
+      },
+    },
+    {
+      'target_name': 'small_pdb_dll',
+      'type': 'shared_library',
+      'msvs_large_pdb': 0,
+      'sources': [
+        'dllmain.cc',
+      ],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'ProgramDatabaseFile': '<(PRODUCT_DIR)/small_pdb_dll.dll.pdb',
+        },
+      },
+    },
+    {
+      'target_name': 'large_pdb_implicit_exe',
+      'type': 'executable',
+      'msvs_large_pdb': 1,
+      'sources': [
+        'main.cc',
+      ],
+      # No PDB file is specified. However, the msvs_large_pdb mechanism should
+      # default to the appropriate <(PRODUCT_DIR)/<(TARGET_NAME).exe.pdb.
+    },
+    {
+      'target_name': 'large_pdb_variable_exe',
+      'type': 'executable',
+      'msvs_large_pdb': 1,
+      'sources': [
+        'main.cc',
+      ],
+      # No PDB file is specified. However, the msvs_large_pdb_path variable
+      # explicitly sets one.
+      'variables': {
+        'msvs_large_pdb_path': '<(PRODUCT_DIR)/foo.pdb',
+      },
+    },
+    {
+      'target_name': 'large_pdb_product_exe',
+      'product_name': 'bar',
+      'type': 'executable',
+      'msvs_large_pdb': 1,
+      'sources': [
+        'main.cc',
+      ],
+      # No PDB file is specified. However, we've specified a product name so
+      # it should use <(PRODUCT_DIR)/bar.exe.pdb.
+    },
+  ]
+}
diff --git a/gyp/test/win/large-pdb/main.cc b/gyp/test/win/large-pdb/main.cc
new file mode 100644 (file)
index 0000000..c3da8e9
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main(void) {
+  return 0;
+}
diff --git a/gyp/test/win/lib-flags/answer.cc b/gyp/test/win/lib-flags/answer.cc
new file mode 100644 (file)
index 0000000..a6ffa16
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "answer.h"
+
+int answer() {
+  return 42;
+}
diff --git a/gyp/test/win/lib-flags/answer.h b/gyp/test/win/lib-flags/answer.h
new file mode 100644 (file)
index 0000000..82312d5
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int answer();
\ No newline at end of file
diff --git a/gyp/test/win/lib-flags/ltcg.gyp b/gyp/test/win/lib-flags/ltcg.gyp
new file mode 100644 (file)
index 0000000..c183107
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'lib_answer',
+      'type': 'static_library',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WholeProgramOptimization': 'true',  # /GL
+        },
+        'VCLibrarianTool': {
+          'LinkTimeCodeGeneration': 'true',    # /LTCG
+        },
+      },
+      'sources': ['answer.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/a/x.cc b/gyp/test/win/linker-flags/a/x.cc
new file mode 100644 (file)
index 0000000..f5f763b
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int x() {
+  return 1;
+}
diff --git a/gyp/test/win/linker-flags/a/z.cc b/gyp/test/win/linker-flags/a/z.cc
new file mode 100644 (file)
index 0000000..8a43501
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int z() {
+  return 3;
+}
diff --git a/gyp/test/win/linker-flags/additional-deps.cc b/gyp/test/win/linker-flags/additional-deps.cc
new file mode 100644 (file)
index 0000000..7dfb589
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <winsock2.h>
+
+int main() {
+  WSAStartup(0, 0);
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/additional-deps.gyp b/gyp/test/win/linker-flags/additional-deps.gyp
new file mode 100644 (file)
index 0000000..55afe64
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_deps_none',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_deps_few',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'AdditionalDependencies': [
+            'wininet.lib',
+            'ws2_32.lib',
+          ]
+        }
+      },
+      'sources': ['additional-deps.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/additional-options.gyp b/gyp/test/win/linker-flags/additional-options.gyp
new file mode 100644 (file)
index 0000000..cab3994
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.\r
+# Use of this source code is governed by a BSD-style license that can be\r
+# found in the LICENSE file.\r
+\r
+{\r
+ 'targets': [\r
+    {\r
+      'target_name': 'test_additional_none',\r
+      'type': 'executable',\r
+      'msvs_settings': {\r
+        'VCLinkerTool': {\r
+        }\r
+      },\r
+      'sources': ['hello.cc'],\r
+    },\r
+    {\r
+      'target_name': 'test_additional_few',\r
+      'type': 'executable',\r
+      'msvs_settings': {\r
+        'VCLinkerTool': {\r
+          'AdditionalOptions': [\r
+            '/dynamicbase:no',\r
+          ]\r
+        }\r
+      },\r
+      'sources': ['hello.cc'],\r
+    },\r
+  ]\r
+}\r
diff --git a/gyp/test/win/linker-flags/aslr.gyp b/gyp/test/win/linker-flags/aslr.gyp
new file mode 100644 (file)
index 0000000..b3aefd5
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_aslr_default',
+      'type': 'executable',
+      'msvs_settings': {
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_aslr_no',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'RandomizedBaseAddress': '1',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_aslr_yes',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'RandomizedBaseAddress': '2',
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/b/y.cc b/gyp/test/win/linker-flags/b/y.cc
new file mode 100644 (file)
index 0000000..bd88411
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int y() {
+  return 2;
+}
diff --git a/gyp/test/win/linker-flags/base-address.gyp b/gyp/test/win/linker-flags/base-address.gyp
new file mode 100644 (file)
index 0000000..873ebfe
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_base_specified_exe',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'BaseAddress': '0x00420000',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_base_specified_dll',
+      'type': 'shared_library',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'BaseAddress': '0x10420000',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_base_default_exe',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_base_default_dll',
+      'type': 'shared_library',
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/debug-info.gyp b/gyp/test/win/linker-flags/debug-info.gyp
new file mode 100644 (file)
index 0000000..d47d0ec
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_debug_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'false'
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_debug_on',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true'
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/deffile-multiple.gyp b/gyp/test/win/linker-flags/deffile-multiple.gyp
new file mode 100644 (file)
index 0000000..c74a9af
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_deffile_multiple_fail',
+      'type': 'shared_library',
+      'sources': [
+          'deffile.cc',
+          'deffile.def',
+          'deffile2.def',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/deffile.cc b/gyp/test/win/linker-flags/deffile.cc
new file mode 100644 (file)
index 0000000..fa203b3
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+void AnExportedFunction() {
+}
+
+void AnotherExportedFunction() {
+}
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/deffile.def b/gyp/test/win/linker-flags/deffile.def
new file mode 100644 (file)
index 0000000..ba9d399
--- /dev/null
@@ -0,0 +1,8 @@
+; Copyright (c) 2012 Google Inc. All rights reserved.
+; Use of this source code is governed by a BSD-style license that can be
+; found in the LICENSE file.
+
+LIBRARY test_deffile_ok
+
+EXPORTS
+        AnExportedFunction
diff --git a/gyp/test/win/linker-flags/deffile.gyp b/gyp/test/win/linker-flags/deffile.gyp
new file mode 100644 (file)
index 0000000..7b241d5
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_deffile_dll_ok',
+      'type': 'shared_library',
+      'sources': [
+          'deffile.cc',
+          'deffile.def',
+      ],
+    },
+    {
+      'target_name': 'test_deffile_dll_notexported',
+      'type': 'shared_library',
+      'sources': [
+          'deffile.cc',
+      ],
+    },
+    {
+      'target_name': 'test_deffile_exe_ok',
+      'type': 'executable',
+      'sources': [
+          'deffile.cc',
+          'deffile.def',
+      ],
+    },
+    {
+      'target_name': 'test_deffile_exe_notexported',
+      'type': 'executable',
+      'sources': [
+          'deffile.cc',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/delay-load-dlls.gyp b/gyp/test/win/linker-flags/delay-load-dlls.gyp
new file mode 100644 (file)
index 0000000..671cbaa
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_dld_none',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+        }
+      },
+      'sources': ['delay-load.cc'],
+      'libraries': [
+        'delayimp.lib',
+        'shell32.lib',
+      ],
+    },
+    {
+      'target_name': 'test_dld_shell32',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'DelayLoadDLLs': ['shell32.dll']
+        }
+      },
+      'sources': ['delay-load.cc'],
+      'libraries': [
+        'delayimp.lib',
+        'shell32.lib',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/delay-load.cc b/gyp/test/win/linker-flags/delay-load.cc
new file mode 100644 (file)
index 0000000..2be34aa
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <shlobj.h>
+
+int main() {
+  SHCreateDirectory(0, 0);
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/embed-manifest.gyp b/gyp/test/win/linker-flags/embed-manifest.gyp
new file mode 100644 (file)
index 0000000..fefb2f5
--- /dev/null
@@ -0,0 +1,109 @@
+# Copyright (c) 2013 Yandex LLC. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'test_manifest_exe',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkIncremental': '1',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+        }
+      },
+    },
+    {
+      'target_name': 'test_manifest_dll',
+      'type': 'loadable_module',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkIncremental': '1',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+        }
+      },
+    },
+    {
+      'target_name': 'test_manifest_extra1',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+          'AdditionalManifestFiles': 'extra.manifest',
+        }
+      },
+    },
+    {
+      'target_name': 'test_manifest_extra2',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+          'AdditionalManifestFiles': 'extra.manifest;extra2.manifest',
+        }
+      },
+    },
+    {
+      'target_name': 'test_manifest_extra_list',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+          'AdditionalManifestFiles': [
+            'extra.manifest',
+            'extra2.manifest'
+          ],
+        }
+      },
+    },
+    {
+      'target_name': 'test_manifest_dll_inc',
+      'type': 'loadable_module',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkIncremental': '2',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+        }
+      },
+    },
+    {
+      'target_name': 'test_manifest_exe_inc',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkIncremental': '2',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+        }
+      },
+    },
+    {
+      'target_name': 'test_manifest_exe_inc_no_embed',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkIncremental': '2',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'false',
+        }
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/enable-uac.gyp b/gyp/test/win/linker-flags/enable-uac.gyp
new file mode 100644 (file)
index 0000000..4e58c86
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'enable_uac',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+        }
+      },
+    },
+    {
+      'target_name': 'enable_uac_no',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'false',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+        }
+      },
+    },
+    {
+      'target_name': 'enable_uac_admin',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'UACExecutionLevel': 2,
+          'UACUIAccess': 'true',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+        }
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/entrypointsymbol.cc b/gyp/test/win/linker-flags/entrypointsymbol.cc
new file mode 100644 (file)
index 0000000..b567bc8
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The entry point specified by link.exe /ENTRY option.
+extern "C" void MainEntryPoint() {
+}
+
+// Still needed because the linker checks for existence of one of main, wmain,
+// WinMain, or wMain to offer informative diagnositics.
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/entrypointsymbol.gyp b/gyp/test/win/linker-flags/entrypointsymbol.gyp
new file mode 100644 (file)
index 0000000..7f2c142
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_ok',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EntryPointSymbol': 'MainEntryPoint',
+        }
+      },
+      'sources': ['entrypointsymbol.cc'],
+    },
+    {
+      'target_name': 'test_fail',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EntryPointSymbol': 'MainEntryPoint',
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/extra.manifest b/gyp/test/win/linker-flags/extra.manifest
new file mode 100644 (file)
index 0000000..2e436dc
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+\r
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\r
+    <application>\r
+      <!--This Id value indicates the application supports Windows 7 functionality-->\r
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\r
+    </application>\r
+  </compatibility>\r
+  \r
+</assembly>\r
diff --git a/gyp/test/win/linker-flags/extra2.manifest b/gyp/test/win/linker-flags/extra2.manifest
new file mode 100644 (file)
index 0000000..bfb570c
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+\r
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\r
+    <application>\r
+      <!--This Id value indicates the application supports Windows Vista functionality -->\r
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>\r
+    </application>\r
+  </compatibility>\r
+  \r
+</assembly>\r
diff --git a/gyp/test/win/linker-flags/fixed-base.gyp b/gyp/test/win/linker-flags/fixed-base.gyp
new file mode 100644 (file)
index 0000000..cc2982e
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    # Disable DYNAMICBASE for these tests because it implies/doesn't imply
+    # FIXED in certain cases so it complicates the test for FIXED.
+    {
+      'target_name': 'test_fixed_default_exe',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'RandomizedBaseAddress': '1',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_fixed_default_dll',
+      'type': 'shared_library',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'RandomizedBaseAddress': '1',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_fixed_no',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'FixedBaseAddress': '1',
+          'RandomizedBaseAddress': '1',
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_fixed_yes',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'FixedBaseAddress': '2',
+          'RandomizedBaseAddress': '1',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/force-symbol-reference.gyp b/gyp/test/win/linker-flags/force-symbol-reference.gyp
new file mode 100644 (file)
index 0000000..d6d02a6
--- /dev/null
@@ -0,0 +1,39 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.\r
+# Use of this source code is governed by a BSD-style license that can be\r
+# found in the LICENSE file.\r
+\r
+{\r
+ 'targets': [\r
+    {\r
+      'target_name': 'test_force_reference_lib',\r
+      'type': 'static_library',\r
+      'sources': ['x.cc', 'y.cc'],\r
+    },\r
+    {\r
+      'target_name': 'test_force_reference',\r
+      'type': 'executable',\r
+      # Turn on debug info to get symbols in disasm for the test code, and\r
+      # turn on opt:ref to drop unused symbols to make sure we wouldn't\r
+      # otherwise have the symbols.\r
+      'msvs_settings': {\r
+        'VCCLCompilerTool': {\r
+          'DebugInformationFormat': '3',\r
+        },\r
+        'VCLinkerTool': {\r
+          'GenerateDebugInformation': 'true',\r
+          'AdditionalOptions': [\r
+            '/OPT:REF',\r
+          ],\r
+          'ForceSymbolReferences': [\r
+            '?x@@YAHXZ',\r
+            '?y@@YAHXZ',\r
+          ],\r
+        },\r
+      },\r
+      'sources': ['hello.cc'],\r
+      'dependencies': [\r
+        'test_force_reference_lib',\r
+      ],\r
+    },\r
+  ]\r
+}\r
diff --git a/gyp/test/win/linker-flags/generate-manifest.gyp b/gyp/test/win/linker-flags/generate-manifest.gyp
new file mode 100644 (file)
index 0000000..34a68d1
--- /dev/null
@@ -0,0 +1,166 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_generate_manifest_true',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+          'GenerateManifest': 'true',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'false',
+        },
+      },
+    },
+    {
+      'target_name': 'test_generate_manifest_false',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+          'GenerateManifest': 'false',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'false',
+        },
+      },
+    },
+    {
+      'target_name': 'test_generate_manifest_default',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'false',
+        },
+      },
+    },
+    {
+      'target_name': 'test_generate_manifest_true_as_embedded',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+          'GenerateManifest': 'true',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+        },
+      },
+    },
+    {
+      'target_name': 'test_generate_manifest_false_as_embedded',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+          'GenerateManifest': 'false',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+        },
+      },
+    },
+    {
+      'target_name': 'test_generate_manifest_default_as_embedded',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'true',
+        },
+      },
+    },
+    {
+      'target_name': 'test_generate_manifest_true_with_extra_manifest',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+          'GenerateManifest': 'true',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'false',
+          'AdditionalManifestFiles': 'extra.manifest;extra2.manifest',
+        },
+      },
+    },
+    {
+      'target_name': 'test_generate_manifest_false_with_extra_manifest',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+          'GenerateManifest': 'false',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'false',
+          'AdditionalManifestFiles': 'extra.manifest;extra2.manifest',
+        },
+      },
+    },
+    {
+      'target_name': 'test_generate_manifest_true_with_extra_manifest_list',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+          'GenerateManifest': 'true',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'false',
+          'AdditionalManifestFiles': [
+            'extra.manifest',
+            'extra2.manifest',
+          ],
+        },
+      },
+    },
+    {
+      'target_name': 'test_generate_manifest_false_with_extra_manifest_list',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+          'GenerateManifest': 'false',
+        },
+        'VCManifestTool': {
+          'EmbedManifest': 'false',
+          'AdditionalManifestFiles': [
+            'extra.manifest',
+            'extra2.manifest',
+          ],
+        },
+      },
+    },
+    {
+      'target_name': 'test_generate_manifest_default_embed_default',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'EnableUAC': 'true',
+        },
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/hello.cc b/gyp/test/win/linker-flags/hello.cc
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/incremental.gyp b/gyp/test/win/linker-flags/incremental.gyp
new file mode 100644 (file)
index 0000000..59f3103
--- /dev/null
@@ -0,0 +1,65 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    # Turn on debug information so the incremental linking tables have a
+    # visible symbolic name in the disassembly.
+    {
+      'target_name': 'test_incremental_unset',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_incremental_default',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'LinkIncremental': '0',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_incremental_no',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'LinkIncremental': '1',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_incremental_yes',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'LinkIncremental': '2',
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/inline_test.cc b/gyp/test/win/linker-flags/inline_test.cc
new file mode 100644 (file)
index 0000000..a9f177e
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "inline_test.h"
+
+#include <intrin.h>
+#pragma intrinsic(_ReturnAddress)
+
+bool IsFunctionInlined(void* caller_return_address) {
+  return _ReturnAddress() == caller_return_address;
+}
diff --git a/gyp/test/win/linker-flags/inline_test.h b/gyp/test/win/linker-flags/inline_test.h
new file mode 100644 (file)
index 0000000..117913c
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+bool IsFunctionInlined(void* current_return_address);
diff --git a/gyp/test/win/linker-flags/inline_test_main.cc b/gyp/test/win/linker-flags/inline_test_main.cc
new file mode 100644 (file)
index 0000000..23cafe8
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "inline_test.h"
+
+#include <intrin.h>
+#include <stdio.h>
+
+#pragma intrinsic(_ReturnAddress)
+
+int main() {
+  if (IsFunctionInlined(_ReturnAddress()))
+    puts("==== inlined ====\n");
+}
diff --git a/gyp/test/win/linker-flags/large-address-aware.gyp b/gyp/test/win/linker-flags/large-address-aware.gyp
new file mode 100644 (file)
index 0000000..fa56d37
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_large_address_aware_no',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LargeAddressAware': '1',
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_large_address_aware_yes',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LargeAddressAware': '2',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/library-adjust.cc b/gyp/test/win/linker-flags/library-adjust.cc
new file mode 100644 (file)
index 0000000..7dfb589
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <winsock2.h>
+
+int main() {
+  WSAStartup(0, 0);
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/library-adjust.gyp b/gyp/test/win/linker-flags/library-adjust.gyp
new file mode 100644 (file)
index 0000000..10e9996
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_adjust',
+      'type': 'executable',
+      'libraries': [
+        '-lws2_32.lib'
+      ],
+      'sources': ['library-adjust.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/library-directories-define.cc b/gyp/test/win/linker-flags/library-directories-define.cc
new file mode 100644 (file)
index 0000000..211ef06
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int library_function() {
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/library-directories-reference.cc b/gyp/test/win/linker-flags/library-directories-reference.cc
new file mode 100644 (file)
index 0000000..3350978
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern int library_function();
+
+int main() {
+  library_function();
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/library-directories.gyp b/gyp/test/win/linker-flags/library-directories.gyp
new file mode 100644 (file)
index 0000000..25395d6
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_libdirs_none',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'AdditionalDependencies': [
+            'test_lib.lib',
+          ],
+        },
+      },
+      'sources': ['library-directories-reference.cc'],
+    },
+    {
+      'target_name': 'test_libdirs_with',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          # NOTE: Don't use this for general dependencies between gyp
+          # libraries (use 'dependencies' instead). This is done here only for
+          # testing.
+          #
+          # This setting should only be used to depend on third party prebuilt
+          # libraries that are stored as binaries at a known location.
+          'AdditionalLibraryDirectories': [
+            '<(DEPTH)/out/Default/obj/subdir', # ninja style
+            '<(DEPTH)/subdir/Default/lib', # msvs style
+          ],
+          'AdditionalDependencies': [
+            'test_lib.lib',
+          ],
+        },
+      },
+      'sources': ['library-directories-reference.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/link-ordering.gyp b/gyp/test/win/linker-flags/link-ordering.gyp
new file mode 100644 (file)
index 0000000..66f4430
--- /dev/null
@@ -0,0 +1,95 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_ordering_exe',
+      'type': 'executable',
+      # These are so the names of the functions appear in the disassembly.
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+          'Optimization': '2',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'LinkIncremental': '1',
+          'GenerateManifest': 'false',
+          # Minimize the disassembly to just our code.
+          'AdditionalOptions': [
+            '/NODEFAULTLIB',
+          ],
+        },
+      },
+      'sources': [
+        # Explicitly sorted the same way as the disassembly in the test .py.
+        'main-crt.c',
+        'z.cc',
+        'x.cc',
+        'y.cc',
+        'hello.cc',
+      ],
+    },
+
+    {
+      'target_name': 'test_ordering_subdirs',
+      'type': 'executable',
+      # These are so the names of the functions appear in the disassembly.
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+          'Optimization': '2',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'LinkIncremental': '1',
+          'GenerateManifest': 'false',
+          # Minimize the disassembly to just our code.
+          'AdditionalOptions': [
+            '/NODEFAULTLIB',
+          ],
+        },
+      },
+      'sources': [
+        # Explicitly sorted the same way as the disassembly in the test .py.
+        'main-crt.c',
+        'hello.cc',
+        'b/y.cc',
+        'a/z.cc',
+      ],
+    },
+
+
+    {
+      'target_name': 'test_ordering_subdirs_mixed',
+      'type': 'executable',
+      # These are so the names of the functions appear in the disassembly.
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+          'Optimization': '2',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'LinkIncremental': '1',
+          'GenerateManifest': 'false',
+          # Minimize the disassembly to just our code.
+          'AdditionalOptions': [
+            '/NODEFAULTLIB',
+          ],
+        },
+      },
+      'sources': [
+        # Explicitly sorted the same way as the disassembly in the test .py.
+        'main-crt.c',
+        'a/x.cc',
+        'hello.cc',
+        'a/z.cc',
+        'y.cc',
+      ],
+    },
+
+  ]
+}
diff --git a/gyp/test/win/linker-flags/link-warning.cc b/gyp/test/win/linker-flags/link-warning.cc
new file mode 100644 (file)
index 0000000..4b34277
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This will cause LNK4254.
+#pragma comment(linker, "/merge:.data=.text")
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/ltcg.gyp b/gyp/test/win/linker-flags/ltcg.gyp
new file mode 100644 (file)
index 0000000..ddb0d9b
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'test_ltcg_off',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WholeProgramOptimization': 'false',
+        },
+        'VCLinkerTool': {
+          'LinkTimeCodeGeneration': '0',
+        },
+      },
+      'sources': [
+        'inline_test.h',
+        'inline_test.cc',
+        'inline_test_main.cc',
+      ],
+    },
+    {
+      'target_name': 'test_ltcg_on',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WholeProgramOptimization': 'true',  # /GL
+        },
+        'VCLinkerTool': {
+          'LinkTimeCodeGeneration': '1',       # /LTCG
+        },
+      },
+      'sources': [
+        'inline_test.h',
+        'inline_test.cc',
+        'inline_test_main.cc',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/main-crt.c b/gyp/test/win/linker-flags/main-crt.c
new file mode 100644 (file)
index 0000000..bdc80c5
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Stub so we can link with /NODEFAULTLIB when checking disasm.
+int mainCRTStartup() {
+  return 5;
+}
diff --git a/gyp/test/win/linker-flags/manifest-in-comment.cc b/gyp/test/win/linker-flags/manifest-in-comment.cc
new file mode 100644 (file)
index 0000000..ae54ae5
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma comment(linker,                                                  \
+                "\"/manifestdependency:type='Win32' "                    \
+                "name='Test.Research.SampleAssembly' version='6.0.0.0' " \
+                "processorArchitecture='X86' "                           \
+                "publicKeyToken='0000000000000000' language='*'\"")
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/mapfile.cc b/gyp/test/win/linker-flags/mapfile.cc
new file mode 100644 (file)
index 0000000..cebccb2
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+__declspec(dllexport)
+void AnExportedFunction() {
+    // We need an exported function to verify that /MAPINFO:EXPORTS works.
+}
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/mapfile.gyp b/gyp/test/win/linker-flags/mapfile.gyp
new file mode 100644 (file)
index 0000000..14206fe
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_mapfile_unset',
+      'type': 'executable',
+      'sources': ['mapfile.cc'],
+    },
+    {
+      'target_name': 'test_mapfile_generate',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'GenerateMapFile': 'true',
+        },
+      },
+      'sources': ['mapfile.cc'],
+    },
+    {
+      'target_name': 'test_mapfile_generate_exports',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'GenerateMapFile': 'true',
+          'MapExports': 'true',
+        },
+      },
+      'sources': ['mapfile.cc'],
+    },
+    {
+      'target_name': 'test_mapfile_generate_filename',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'GenerateMapFile': 'true',
+          'MapFileName': '<(PRODUCT_DIR)/custom_file_name.map',
+        },
+      },
+      'sources': ['mapfile.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/no-default-libs.cc b/gyp/test/win/linker-flags/no-default-libs.cc
new file mode 100644 (file)
index 0000000..e306846
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Reference something in kernel32.dll. This will fail to link, verifying that
+// GYP provides no default import library configuration.
+// Note that we don't include Windows.h, as that will result in generating
+// linker directives in the object file through #pragma comment(lib, ...).
+typedef short BOOL;
+
+extern "C" __declspec(dllimport)
+BOOL CopyFileW(const wchar_t*, const wchar_t*, BOOL);
+
+
+int main() {
+  CopyFileW(0, 0, 0); // kernel32
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/no-default-libs.gyp b/gyp/test/win/linker-flags/no-default-libs.gyp
new file mode 100644 (file)
index 0000000..77838ce
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_default',
+      'type': 'executable',
+      'sources': ['no-default-libs.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/nodefaultlib.cc b/gyp/test/win/linker-flags/nodefaultlib.cc
new file mode 100644 (file)
index 0000000..24b6eca
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Include entry point function that's excluded by removing C runtime libraries.
+extern "C" void mainCRTStartup() {
+}
+
+// Still needed because the linker checks for existence of one of main, wmain,
+// WinMain, or wMain to offer informative diagnositics.
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/nodefaultlib.gyp b/gyp/test/win/linker-flags/nodefaultlib.gyp
new file mode 100644 (file)
index 0000000..4fb452a
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_ok',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'IgnoreDefaultLibraryNames':
+              ['libcmtd.lib', 'libcmt.lib', 'msvcrt.lib', 'msvcrtd.lib'],
+        }
+      },
+      'sources': ['nodefaultlib.cc'],
+    },
+    {
+      'target_name': 'test_fail',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'IgnoreDefaultLibraryNames':
+              ['libcmtd.lib', 'libcmt.lib', 'msvcrt.lib', 'msvcrtd.lib'],
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/nxcompat.gyp b/gyp/test/win/linker-flags/nxcompat.gyp
new file mode 100644 (file)
index 0000000..fa4118c
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_nxcompat_default',
+      'type': 'executable',
+      'msvs_settings': {
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_nxcompat_no',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'DataExecutionPrevention': '1',
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_nxcompat_yes',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'DataExecutionPrevention': '2',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/opt-icf.cc b/gyp/test/win/linker-flags/opt-icf.cc
new file mode 100644 (file)
index 0000000..1f12156
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+void similar_function0(char* x) {
+  while (*x) {
+    ++x;
+  }
+}
+
+void similar_function1(char* p) {
+  while (*p) {
+    ++p;
+  }
+}
+
+void similar_function2(char* q) {
+  while (*q) {
+    ++q;
+  }
+}
+
+int main() {
+  char* x = "hello";
+  similar_function0(x);
+  similar_function1(x);
+  similar_function2(x);
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/opt-icf.gyp b/gyp/test/win/linker-flags/opt-icf.gyp
new file mode 100644 (file)
index 0000000..effe802
--- /dev/null
@@ -0,0 +1,63 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    # Have to turn on function level linking here to get the function packaged
+    # as a COMDAT so that it's eligible for merging. Also turn on debug
+    # information so that the symbol names for the code appear in the dump.
+    # Finally, specify non-incremental linking so that there's not a bunch of
+    # extra "similar_function"s in the output (the ILT jump table).
+    {
+      'target_name': 'test_opticf_default',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableFunctionLevelLinking': 'true',
+          'DebugInformationFormat': '3',
+          'Optimization': '0',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'LinkIncremental': '1',
+        },
+      },
+      'sources': ['opt-icf.cc'],
+    },
+    {
+      'target_name': 'test_opticf_no',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableFunctionLevelLinking': 'true',
+          'DebugInformationFormat': '3',
+          'Optimization': '0',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'EnableCOMDATFolding': '1',
+          'LinkIncremental': '1',
+        },
+      },
+      'sources': ['opt-icf.cc'],
+    },
+    {
+      'target_name': 'test_opticf_yes',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableFunctionLevelLinking': 'true',
+          'DebugInformationFormat': '3',
+          'Optimization': '0',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'EnableCOMDATFolding': '2',
+          'LinkIncremental': '1',
+        },
+      },
+      'sources': ['opt-icf.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/opt-ref.cc b/gyp/test/win/linker-flags/opt-ref.cc
new file mode 100644 (file)
index 0000000..afaa328
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int unused_function() {
+  return 0;
+}
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/opt-ref.gyp b/gyp/test/win/linker-flags/opt-ref.gyp
new file mode 100644 (file)
index 0000000..69d0281
--- /dev/null
@@ -0,0 +1,56 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    # Have to turn on function level linking here to get the function packaged
+    # as a COMDAT so that it's eligible for optimizing away. Also turn on
+    # debug information so that the symbol names for the code appear in the
+    # dump (so we can verify if they are included in the final exe).
+    {
+      'target_name': 'test_optref_default',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableFunctionLevelLinking': 'true',
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+        },
+      },
+      'sources': ['opt-ref.cc'],
+    },
+    {
+      'target_name': 'test_optref_no',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableFunctionLevelLinking': 'true',
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'OptimizeReferences': '1',
+        },
+      },
+      'sources': ['opt-ref.cc'],
+    },
+    {
+      'target_name': 'test_optref_yes',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'EnableFunctionLevelLinking': 'true',
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'OptimizeReferences': '2',
+        },
+      },
+      'sources': ['opt-ref.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/outputfile.gyp b/gyp/test/win/linker-flags/outputfile.gyp
new file mode 100644 (file)
index 0000000..1022ec2
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_output_exe',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '$(OutDir)\\blorp.exe'
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_output_exe2',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '$(OutDir)\\subdir\\blorp.exe'
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_output_dll',
+      'type': 'shared_library',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '$(OutDir)\\blorp.dll'
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_output_lib',
+      'type': 'static_library',
+      'msvs_settings': {
+        'VCLibrarianTool': {
+          'OutputFile': '$(OutDir)\\blorp.lib'
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_output_lib2',
+      'type': 'static_library',
+      'msvs_settings': {
+        'VCLibrarianTool': {
+          'OutputFile': '$(OutDir)\\subdir\\blorp.lib'
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/pdb-output.gyp b/gyp/test/win/linker-flags/pdb-output.gyp
new file mode 100644 (file)
index 0000000..21d3cd7
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_pdb_output_exe',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3'
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'ProgramDatabaseFile': 'output_exe.pdb',
+        },
+      },
+    },
+    {
+      'target_name': 'test_pdb_output_dll',
+      'type': 'shared_library',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3'
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'ProgramDatabaseFile': 'output_dll.pdb',
+        },
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/pgo.gyp b/gyp/test/win/linker-flags/pgo.gyp
new file mode 100644 (file)
index 0000000..da32639
--- /dev/null
@@ -0,0 +1,143 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'pgd_basename': 'test_pgo',
+  },
+  'targets': [
+    # In the PGO (Profile-Guided Optimization) build flow, we need to build the
+    # target binary multiple times. To implement this flow with gyp, here we
+    # define multiple 'executable' targets, each of which represents one build
+    # particular build/profile stage. On tricky part to do this is that these
+    # 'executable' targets should share the code itself so that profile data
+    # can be reused among these 'executable' files. In other words, the only
+    # differences among below 'executable' targets are:
+    #   1) PGO (Profile-Guided Optimization) database, and
+    #   2) linker options.
+    # The following static library contains all the logic including entry point.
+    # Basically we don't need to rebuild this target once we enter profiling
+    # phase of PGO.
+    {
+      'target_name': 'test_pgo_main',
+      'type': 'static_library',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WholeProgramOptimization': 'true',  # /GL
+        },
+        'VCLibrarianTool': {
+          'LinkTimeCodeGeneration': 'true',
+        },
+      },
+      'link_settings': {
+        'msvs_settings': {
+          'VCLinkerTool': {
+            'ProfileGuidedDatabase': '$(OutDir)\\<(pgd_basename).pgd',
+            'TargetMachine': '1',  # x86 - 32
+            'SubSystem': '1',      # /SUBSYSTEM:CONSOLE\r
+            # Tell ninja generator not to pass /ManifestFile:<filename> option
+            # to the linker, because it causes LNK1268 error in PGO biuld.
+            'GenerateManifest': 'false',
+            # We need to specify 'libcmt.lib' here so that the linker can pick
+            # up a valid entry point.
+            'AdditionalDependencies': [
+              'libcmt.lib',
+            ],
+          },
+        },
+      },
+      'sources': [
+        'inline_test.h',
+        'inline_test.cc',
+        'inline_test_main.cc',
+      ],
+    },
+    {
+      'target_name': 'test_pgo_instrument',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkTimeCodeGeneration': '2',
+        },
+      },
+      'dependencies': [
+        'test_pgo_main',
+      ],
+    },
+    {
+      'target_name': 'gen_profile_guided_database',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'actions': [
+        {
+          'action_name': 'action_main',
+          'inputs': [],
+          'outputs': [
+            '$(OutDir)\\<(pgd_basename).pgd',
+          ],
+          'action': [
+            'python', 'update_pgd.py',
+            '--vcbindir', '$(VCInstallDir)bin',
+            '--exe', '$(OutDir)\\test_pgo_instrument.exe',
+            '--pgd', '$(OutDir)\\<(pgd_basename).pgd',
+          ],
+        },
+      ],
+      'dependencies': [
+        'test_pgo_instrument',
+      ],
+    },
+    {
+      'target_name': 'test_pgo_optimize',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkTimeCodeGeneration': '3',
+        },
+      },
+      'sources': [
+        '$(OutDir)\\<(pgd_basename).pgd',
+      ],
+      'dependencies': [
+        'test_pgo_main',
+        'gen_profile_guided_database',
+      ],
+    },
+    {
+      'target_name': 'test_pgo_update',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'LinkTimeCodeGeneration': '4',
+        },
+      },
+      'sources': [
+        '$(OutDir)\\<(pgd_basename).pgd',
+      ],
+      'dependencies': [
+        'test_pgo_main',
+      ],
+    },
+    # A helper target to dump link.exe's command line options. We can use the
+    # output to determine if PGO (Profile-Guided Optimization) is available on
+    # the test environment.
+    {
+      'target_name': 'gen_linker_option',
+      'type': 'none',
+      'msvs_cygwin_shell': 0,
+      'actions': [
+        {
+          'action_name': 'action_main',
+          'inputs': [],
+          'outputs': [
+            '$(OutDir)\\linker_options.txt',
+          ],
+          'action': [
+            'cmd.exe', '/c link.exe > $(OutDir)\\linker_options.txt & exit 0',
+          ],
+        },
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/profile.gyp b/gyp/test/win/linker-flags/profile.gyp
new file mode 100644 (file)
index 0000000..d60a700
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    # Verify that 'Profile' option correctly makes it to LINK steup in Ninja
+    {
+      'target_name': 'test_profile_true',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3'
+        },
+        'VCLinkerTool': {
+          'Profile': 'true',
+          'GenerateDebugInformation': 'true',
+        },
+      },
+    },
+    {
+      'target_name': 'test_profile_false',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3'
+        },
+        'VCLinkerTool': {
+          'Profile': 'false',
+          'GenerateDebugInformation': 'true',
+        },
+      },
+    },
+    {
+      'target_name': 'test_profile_default',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3'
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+        },
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/program-database.gyp b/gyp/test/win/linker-flags/program-database.gyp
new file mode 100644 (file)
index 0000000..6e60ac0
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    # Verify that 'ProgramDatabaseFile' option correctly makes it to LINK
+    # step in Ninja.
+    {
+      # Verify that VC macros and windows paths work correctly.
+      'target_name': 'test_pdb_outdir',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3'
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'ProgramDatabaseFile': '$(OutDir)\\name_outdir.pdb',
+        },
+      },
+    },
+    {
+      # Verify that GYP macros and POSIX paths work correctly.
+      'target_name': 'test_pdb_proddir',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3'
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+          'ProgramDatabaseFile': '<(PRODUCT_DIR)/name_proddir.pdb',
+        },
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/safeseh.gyp b/gyp/test/win/linker-flags/safeseh.gyp
new file mode 100644 (file)
index 0000000..6103620
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_safeseh_default',
+      'type': 'executable',
+      'msvs_settings': {
+      },
+      'sources': [
+        'safeseh_hello.cc',
+        'safeseh_zero.asm',
+      ],
+    },
+    {
+      'target_name': 'test_safeseh_no',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'ImageHasSafeExceptionHandlers': 'false',
+        },
+      },
+      'sources': [
+        'safeseh_hello.cc',
+        'safeseh_zero.asm',
+      ],
+    },
+    {
+      'target_name': 'test_safeseh_yes',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'ImageHasSafeExceptionHandlers': 'true',
+        },
+        'MASM': {
+          'UseSafeExceptionHandlers': 'true',
+        },
+      },
+      'sources': [
+        'safeseh_hello.cc',
+        'safeseh_zero.asm',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/safeseh_hello.cc b/gyp/test/win/linker-flags/safeseh_hello.cc
new file mode 100644 (file)
index 0000000..6141300
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern "C" {
+int zero(void);
+}
+
+int main() {
+  return zero();
+}
diff --git a/gyp/test/win/linker-flags/safeseh_zero.asm b/gyp/test/win/linker-flags/safeseh_zero.asm
new file mode 100644 (file)
index 0000000..62da0df
--- /dev/null
@@ -0,0 +1,10 @@
+.MODEL FLAT, C
+.CODE
+
+PUBLIC  zero
+zero    PROC
+        xor     eax, eax
+        ret     0
+zero    ENDP
+
+END
diff --git a/gyp/test/win/linker-flags/subdir/library.gyp b/gyp/test/win/linker-flags/subdir/library.gyp
new file mode 100644 (file)
index 0000000..519577f
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.\r
+# Use of this source code is governed by a BSD-style license that can be\r
+# found in the LICENSE file.\r
+\r
+{\r
+ 'targets': [\r
+    {\r
+      'target_name': 'test_lib',\r
+      'type': 'static_library',\r
+      'sources': ['../library-directories-define.cc'],\r
+    },\r
+  ]\r
+}\r
diff --git a/gyp/test/win/linker-flags/subsystem-windows.cc b/gyp/test/win/linker-flags/subsystem-windows.cc
new file mode 100644 (file)
index 0000000..ac99da8
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
+  return 0;
+}
diff --git a/gyp/test/win/linker-flags/subsystem.gyp b/gyp/test/win/linker-flags/subsystem.gyp
new file mode 100644 (file)
index 0000000..63f072a
--- /dev/null
@@ -0,0 +1,70 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_console_ok',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'SubSystem': '1'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_console_fail',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'SubSystem': '1'
+        }
+      },
+      'sources': ['subsystem-windows.cc'],
+    },
+    {
+      'target_name': 'test_windows_ok',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'SubSystem': '2'
+        }
+      },
+      'sources': ['subsystem-windows.cc'],
+    },
+    {
+      'target_name': 'test_windows_fail',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'SubSystem': '2'
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_console_xp',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'SubSystem': '1',
+          'MinimumRequiredVersion': '5.01',  # XP.
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_windows_xp',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'SubSystem': '2',
+          'MinimumRequiredVersion': '5.01',  # XP.
+        }
+      },
+      'sources': ['subsystem-windows.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/target-machine.gyp b/gyp/test/win/linker-flags/target-machine.gyp
new file mode 100644 (file)
index 0000000..3027192
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_target_link_x86',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'TargetMachine': '1',
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_target_link_x64',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'TargetMachine': '17',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_target_lib_x86',
+      'type': 'static_library',
+      'msvs_settings': {
+        'VCLibrarianTool': {
+          'TargetMachine': '1',
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_target_lib_x64',
+      'type': 'static_library',
+      'msvs_settings': {
+        'VCLibrarianTool': {
+          'TargetMachine': '17',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/tsaware.gyp b/gyp/test/win/linker-flags/tsaware.gyp
new file mode 100644 (file)
index 0000000..7ffc742
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_tsaware_no',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'TerminalServerAware': '1',
+        }
+      },
+      'sources': ['hello.cc'],
+    },
+    {
+      'target_name': 'test_tsaware_yes',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'TerminalServerAware': '2',
+        },
+      },
+      'sources': ['hello.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/linker-flags/unsupported-manifest.gyp b/gyp/test/win/linker-flags/unsupported-manifest.gyp
new file mode 100644 (file)
index 0000000..5549e7c
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_unsupported',
+      'type': 'executable',
+      'sources': ['manifest-in-comment.cc'],
+    },
+  ],
+}
diff --git a/gyp/test/win/linker-flags/update_pgd.py b/gyp/test/win/linker-flags/update_pgd.py
new file mode 100644 (file)
index 0000000..34f56ee
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from optparse import OptionParser
+import glob
+import os
+import subprocess
+
+parser = OptionParser()
+parser.add_option('--exe', dest='exe')
+parser.add_option('--vcbindir', dest='vcbindir')
+parser.add_option('--pgd', dest='pgd')
+(options, args) = parser.parse_args()
+
+# Instrumented binaries fail to run unless the Visual C++'s bin dir is included
+# in the PATH environment variable.
+os.environ['PATH'] = os.environ['PATH'] + os.pathsep + options.vcbindir
+
+# Run Instrumented binary.  The profile will be recorded into *.pgc file.
+subprocess.call([options.exe])
+
+# Merge *.pgc files into a *.pgd (Profile-Guided Database) file.
+subprocess.call(['pgomgr', '/merge', options.pgd])
+
+# *.pgc files are no longer necessary. Clear all of them.
+pgd_file = os.path.abspath(options.pgd)
+pgd_dir = os.path.dirname(pgd_file)
+(pgd_basename, _) = os.path.splitext(os.path.basename(pgd_file))
+pgc_filepattern = os.path.join(pgd_dir, '%s!*.pgc' % pgd_basename)
+pgc_files= glob.glob(pgc_filepattern)\r
+for pgc_file in pgc_files:\r
+  os.unlink(pgc_file)\r
diff --git a/gyp/test/win/linker-flags/warn-as-error.gyp b/gyp/test/win/linker-flags/warn-as-error.gyp
new file mode 100644 (file)
index 0000000..83c67e9
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.\r
+# Use of this source code is governed by a BSD-style license that can be\r
+# found in the LICENSE file.\r
+\r
+{\r
+ 'targets': [\r
+    {\r
+      'target_name': 'test_on',\r
+      'type': 'executable',\r
+      'msvs_settings': {\r
+        'VCLinkerTool': {\r
+          'TreatLinkerWarningAsErrors': 'true',\r
+        }\r
+      },\r
+      'sources': ['link-warning.cc'],\r
+    },\r
+    {\r
+      'target_name': 'test_off',\r
+      'type': 'executable',\r
+      'msvs_settings': {\r
+        'VCLinkerTool': {\r
+          'TreatLinkerWarningAsErrors': 'false',\r
+        }\r
+      },\r
+      'sources': ['link-warning.cc'],\r
+    },\r
+    {\r
+      'target_name': 'test_default',\r
+      'type': 'executable',\r
+      'sources': ['link-warning.cc'],\r
+    },\r
+  ]\r
+}\r
diff --git a/gyp/test/win/linker-flags/x.cc b/gyp/test/win/linker-flags/x.cc
new file mode 100644 (file)
index 0000000..f5f763b
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int x() {
+  return 1;
+}
diff --git a/gyp/test/win/linker-flags/y.cc b/gyp/test/win/linker-flags/y.cc
new file mode 100644 (file)
index 0000000..bd88411
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int y() {
+  return 2;
+}
diff --git a/gyp/test/win/linker-flags/z.cc b/gyp/test/win/linker-flags/z.cc
new file mode 100644 (file)
index 0000000..8a43501
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int z() {
+  return 3;
+}
diff --git a/gyp/test/win/long-command-line/function.cc b/gyp/test/win/long-command-line/function.cc
new file mode 100644 (file)
index 0000000..af44b2c
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int func() {
+  return 0;
+}
diff --git a/gyp/test/win/long-command-line/hello.cc b/gyp/test/win/long-command-line/hello.cc
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/long-command-line/long-command-line.gyp b/gyp/test/win/long-command-line/long-command-line.gyp
new file mode 100644 (file)
index 0000000..964c94f
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'longexe',
+      'type': 'executable',
+      'msvs_settings': {
+        # Use this as a simple way to get a long command.
+        'VCCLCompilerTool': {
+          'AdditionalOptions': '/nologo ' * 8000,
+        },
+        'VCLinkerTool': {
+          'AdditionalOptions': '/nologo ' * 8000,
+        },
+      },
+      'sources': [
+        'hello.cc',
+      ],
+    },
+    {
+      'target_name': 'longlib',
+      'type': 'static_library',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'AdditionalOptions': '/nologo ' * 8000,
+        },
+        'VCLibrarianTool': {
+          'AdditionalOptions': '/nologo ' * 8000,
+        },
+      },
+      'sources': [
+        'function.cc',
+      ],
+    },
+    {
+      'target_name': 'longdll',
+      'type': 'shared_library',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'AdditionalOptions': '/nologo ' * 8000,
+        },
+        'VCLinkerTool': {
+          'AdditionalOptions': '/nologo ' * 8000,
+        },
+      },
+      'sources': [
+        'hello.cc',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/ml-safeseh/a.asm b/gyp/test/win/ml-safeseh/a.asm
new file mode 100644 (file)
index 0000000..62da0df
--- /dev/null
@@ -0,0 +1,10 @@
+.MODEL FLAT, C
+.CODE
+
+PUBLIC  zero
+zero    PROC
+        xor     eax, eax
+        ret     0
+zero    ENDP
+
+END
diff --git a/gyp/test/win/ml-safeseh/hello.cc b/gyp/test/win/ml-safeseh/hello.cc
new file mode 100644 (file)
index 0000000..6141300
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern "C" {
+int zero(void);
+}
+
+int main() {
+  return zero();
+}
diff --git a/gyp/test/win/ml-safeseh/ml-safeseh.gyp b/gyp/test/win/ml-safeseh/ml-safeseh.gyp
new file mode 100644 (file)
index 0000000..bf8618f
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'ml_safeseh',
+      'type': 'executable',
+      'sources': [
+        'hello.cc',
+        'a.asm',
+      ],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'ImageHasSafeExceptionHandlers': 'true',
+        },
+        'MASM': {
+          'UseSafeExceptionHandlers': 'true',
+        },
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/precompiled/gyptest-all.py b/gyp/test/win/precompiled/gyptest-all.py
new file mode 100644 (file)
index 0000000..9fb5e62
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that precompiled headers can be specified.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+    test = TestGyp.TestGyp(formats=['msvs', 'ninja'], workdir='workarea_all')
+    test.run_gyp('hello.gyp')
+    test.build('hello.gyp', 'hello')
+    test.run_built_executable('hello', stdout="Hello, world!\nHello, two!\n")
+    test.up_to_date('hello.gyp', test.ALL)
+    test.pass_test()
diff --git a/gyp/test/win/precompiled/hello.c b/gyp/test/win/precompiled/hello.c
new file mode 100644 (file)
index 0000000..ffb47bf
--- /dev/null
@@ -0,0 +1,14 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+// Note the abscence of a stdio.h include.  This will be inserted because of the
+// precompiled header.
+
+extern int hello2();
+
+int main(void) {
+  printf("Hello, world!\n");
+  hello2();
+  return 0;
+}
diff --git a/gyp/test/win/precompiled/hello.gyp b/gyp/test/win/precompiled/hello.gyp
new file mode 100644 (file)
index 0000000..5f82c53
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'hello',
+      'type': 'executable',
+      'sources': [
+        'hello.c',
+        'hello2.c',
+        'precomp.c',
+      ],
+      'msvs_precompiled_header': 'stdio.h',
+      'msvs_precompiled_source': 'precomp.c',
+
+      # Required so that the printf actually causes a build failure
+      # if the pch isn't included.
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'WarningLevel': '3',
+          'WarnAsError': 'true',
+        },
+      },
+    },
+  ],
+}
diff --git a/gyp/test/win/precompiled/hello2.c b/gyp/test/win/precompiled/hello2.c
new file mode 100644 (file)
index 0000000..d6d5311
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+// Unlike hello.c, this file specifies the headers.
+
+#include <windows.h>
+#include <stdio.h>
+
+int hello2() {
+  printf("Hello, two!\n");
+  return 0;
+}
diff --git a/gyp/test/win/precompiled/precomp.c b/gyp/test/win/precompiled/precomp.c
new file mode 100644 (file)
index 0000000..517c61a
--- /dev/null
@@ -0,0 +1,8 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+// The precompiled header does not have to be the first one in the file.
+
+#include <windows.h>
+#include <stdio.h>
diff --git a/gyp/test/win/rc-build/Resource.h b/gyp/test/win/rc-build/Resource.h
new file mode 100644 (file)
index 0000000..137acf3
--- /dev/null
@@ -0,0 +1,26 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by hello.rc\r
+//\r
+\r
+#define IDS_APP_TITLE                  103\r
+\r
+#define IDR_MAINFRAME                  128\r
+#define IDI_HELLO                      107\r
+#define IDI_SMALL                              108\r
+#define IDC_HELLO                      109\r
+#ifndef IDC_STATIC\r
+#define IDC_STATIC                             -1\r
+#endif\r
+// Next default values for new objects\r
+//\r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+\r
+#define _APS_NO_MFC                                    130\r
+#define _APS_NEXT_RESOURCE_VALUE       129\r
+#define _APS_NEXT_COMMAND_VALUE                32771\r
+#define _APS_NEXT_CONTROL_VALUE                1000\r
+#define _APS_NEXT_SYMED_VALUE          110\r
+#endif\r
+#endif\r
diff --git a/gyp/test/win/rc-build/hello.cpp b/gyp/test/win/rc-build/hello.cpp
new file mode 100644 (file)
index 0000000..f552ca1
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.\r
+// Use of this source code is governed by a BSD-style license that can be\r
+// found in the LICENSE file.\r
+\r
+#define WIN32_LEAN_AND_MEAN\r
+#include <windows.h>\r
+#include <tchar.h>\r
+\r
+#include "resource.h"\r
+\r
+#define MAX_LOADSTRING 100\r
+\r
+TCHAR szTitle[MAX_LOADSTRING];\r
+TCHAR szWindowClass[MAX_LOADSTRING];\r
+\r
+int APIENTRY _tWinMain(\r
+    HINSTANCE hInstance,\r
+    HINSTANCE hPrevInstance,\r
+    LPTSTR    lpCmdLine,\r
+    int       nCmdShow) {\r
+  // Make sure we can load some resources.\r
+  int count = 0;\r
+  LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);\r
+  if (szTitle[0] != 0) ++count;\r
+  LoadString(hInstance, IDC_HELLO, szWindowClass, MAX_LOADSTRING);\r
+  if (szWindowClass[0] != 0) ++count;\r
+  if (LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SMALL)) != NULL) ++count;\r
+  if (LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HELLO)) != NULL) ++count;\r
+  return count;\r
+}\r
diff --git a/gyp/test/win/rc-build/hello.gyp b/gyp/test/win/rc-build/hello.gyp
new file mode 100644 (file)
index 0000000..3a66357
--- /dev/null
@@ -0,0 +1,92 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'with_resources',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+        },
+        'VCResourceCompilerTool': {
+          'Culture' : '1033',
+        },
+      },
+      'sources': [
+        'hello.cpp',
+        'hello.rc',
+      ],
+      'libraries': [
+        'kernel32.lib',
+        'user32.lib',
+      ],
+    },
+    {
+      'target_name': 'with_resources_subdir',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+        },
+        'VCResourceCompilerTool': {
+          'Culture' : '1033',
+        },
+      },
+      'sources': [
+        'hello.cpp',
+        'subdir/hello2.rc',
+      ],
+      'libraries': [
+        'kernel32.lib',
+        'user32.lib',
+      ],
+    },
+    {
+      'target_name': 'with_include_subdir',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'DebugInformationFormat': '3',
+        },
+        'VCLinkerTool': {
+          'GenerateDebugInformation': 'true',
+        },
+        'VCResourceCompilerTool': {
+          'Culture' : '1033',
+        },
+      },
+      'resource_include_dirs': [
+        '$(ProjectDir)\\subdir',
+      ],
+      'sources': [
+        'hello.cpp',
+        'hello3.rc',
+      ],
+      'libraries': [
+        'kernel32.lib',
+        'user32.lib',
+      ],
+    },
+    {
+      'target_name': 'resource_only_dll',
+      'type': 'shared_library',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'ResourceOnlyDLL': 'true',
+        },
+      },
+      'sources': [
+        'hello.rc',
+      ],
+    },
+  ],
+}
diff --git a/gyp/test/win/rc-build/hello.h b/gyp/test/win/rc-build/hello.h
new file mode 100644 (file)
index 0000000..e60f2eb
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once\r
+\r
+#include "resource.h"\r
diff --git a/gyp/test/win/rc-build/hello.ico b/gyp/test/win/rc-build/hello.ico
new file mode 100644 (file)
index 0000000..d551aa3
Binary files /dev/null and b/gyp/test/win/rc-build/hello.ico differ
diff --git a/gyp/test/win/rc-build/hello.rc b/gyp/test/win/rc-build/hello.rc
new file mode 100644 (file)
index 0000000..c9a7af6
--- /dev/null
@@ -0,0 +1,86 @@
+//Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#ifndef APSTUDIO_INVOKED\r
+#include "targetver.h"\r
+#endif\r
+#define APSTUDIO_HIDDEN_SYMBOLS\r
+#include "windows.h"\r
+#undef APSTUDIO_HIDDEN_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(932)\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Icon\r
+//\r
+\r
+// Icon with lowest ID value placed first to ensure application icon\r
+// remains consistent on all systems.\r
+\r
+IDI_HELLO       ICON         "hello.ico"\r
+IDI_SMALL               ICON         "small.ico"\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+1 TEXTINCLUDE\r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE\r
+BEGIN\r
+       "#ifndef APSTUDIO_INVOKED\r\n"\r
+    "#include ""targetver.h""\r\n"\r
+    "#endif\r\n"\r
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"\r
+    "#include ""windows.h""\r\n"\r
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE\r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE\r
+BEGIN\r
+   IDC_HELLO   "HELLO"\r
+   IDS_APP_TITLE       "hello"\r
+END\r
+\r
+#endif\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
diff --git a/gyp/test/win/rc-build/hello3.rc b/gyp/test/win/rc-build/hello3.rc
new file mode 100644 (file)
index 0000000..c74dede
--- /dev/null
@@ -0,0 +1,87 @@
+//Microsoft Visual C++ generated resource script.\r
+//\r
+#include "include.h"\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#ifndef APSTUDIO_INVOKED\r
+#include "targetver.h"\r
+#endif\r
+#define APSTUDIO_HIDDEN_SYMBOLS\r
+#include "windows.h"\r
+#undef APSTUDIO_HIDDEN_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(932)\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Icon\r
+//\r
+\r
+// Icon with lowest ID value placed first to ensure application icon\r
+// remains consistent on all systems.\r
+\r
+IDI_HELLO       ICON         "hello.ico"\r
+IDI_SMALL               ICON         "small.ico"\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+1 TEXTINCLUDE\r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE\r
+BEGIN\r
+       "#ifndef APSTUDIO_INVOKED\r\n"\r
+    "#include ""targetver.h""\r\n"\r
+    "#endif\r\n"\r
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"\r
+    "#include ""windows.h""\r\n"\r
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE\r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE\r
+BEGIN\r
+   IDC_HELLO   "HELLO"\r
+   IDS_APP_TITLE       "hello"\r
+END\r
+\r
+#endif\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
diff --git a/gyp/test/win/rc-build/small.ico b/gyp/test/win/rc-build/small.ico
new file mode 100644 (file)
index 0000000..d551aa3
Binary files /dev/null and b/gyp/test/win/rc-build/small.ico differ
diff --git a/gyp/test/win/rc-build/subdir/hello2.rc b/gyp/test/win/rc-build/subdir/hello2.rc
new file mode 100644 (file)
index 0000000..4c8eab1
--- /dev/null
@@ -0,0 +1,87 @@
+//Microsoft Visual C++ generated resource script.\r
+//\r
+#include "subdir/include.h"\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#ifndef APSTUDIO_INVOKED\r
+#include "targetver.h"\r
+#endif\r
+#define APSTUDIO_HIDDEN_SYMBOLS\r
+#include "windows.h"\r
+#undef APSTUDIO_HIDDEN_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(932)\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Icon\r
+//\r
+\r
+// Icon with lowest ID value placed first to ensure application icon\r
+// remains consistent on all systems.\r
+\r
+IDI_HELLO       ICON         "hello.ico"\r
+IDI_SMALL               ICON         "small.ico"\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+1 TEXTINCLUDE\r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE\r
+BEGIN\r
+       "#ifndef APSTUDIO_INVOKED\r\n"\r
+    "#include ""targetver.h""\r\n"\r
+    "#endif\r\n"\r
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"\r
+    "#include ""windows.h""\r\n"\r
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE\r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE\r
+BEGIN\r
+   IDC_HELLO   "HELLO"\r
+   IDS_APP_TITLE       "hello"\r
+END\r
+\r
+#endif\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
diff --git a/gyp/test/win/rc-build/subdir/include.h b/gyp/test/win/rc-build/subdir/include.h
new file mode 100644 (file)
index 0000000..f15c48b
--- /dev/null
@@ -0,0 +1 @@
+// Just exists to make sure it can be included.\r
diff --git a/gyp/test/win/rc-build/targetver.h b/gyp/test/win/rc-build/targetver.h
new file mode 100644 (file)
index 0000000..f583181
--- /dev/null
@@ -0,0 +1,24 @@
+#pragma once\r
+\r
+// The following macros define the minimum required platform.  The minimum required platform\r
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run \r
+// your application.  The macros work by enabling all features available on platform versions up to and \r
+// including the version specified.\r
+\r
+// Modify the following defines if you have to target a platform prior to the ones specified below.\r
+// Refer to MSDN for the latest info on corresponding values for different platforms.\r
+#ifndef WINVER                          // Specifies that the minimum required platform is Windows Vista.\r
+#define WINVER 0x0600           // Change this to the appropriate value to target other versions of Windows.\r
+#endif\r
+\r
+#ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.\r
+#define _WIN32_WINNT 0x0600     // Change this to the appropriate value to target other versions of Windows.\r
+#endif\r
+\r
+#ifndef _WIN32_WINDOWS          // Specifies that the minimum required platform is Windows 98.\r
+#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.\r
+#endif\r
+\r
+#ifndef _WIN32_IE                       // Specifies that the minimum required platform is Internet Explorer 7.0.\r
+#define _WIN32_IE 0x0700        // Change this to the appropriate value to target other versions of IE.\r
+#endif\r
diff --git a/gyp/test/win/shard/hello.cc b/gyp/test/win/shard/hello.cc
new file mode 100644 (file)
index 0000000..a9dce62
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/shard/hello1.cc b/gyp/test/win/shard/hello1.cc
new file mode 100644 (file)
index 0000000..0eccf28
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int f1() {
+  return 0;
+}
diff --git a/gyp/test/win/shard/hello2.cc b/gyp/test/win/shard/hello2.cc
new file mode 100644 (file)
index 0000000..23fcb54
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int f2() {
+  return 0;
+}
diff --git a/gyp/test/win/shard/hello3.cc b/gyp/test/win/shard/hello3.cc
new file mode 100644 (file)
index 0000000..a72e2ef
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int f3() {
+  return 0;
+}
diff --git a/gyp/test/win/shard/hello4.cc b/gyp/test/win/shard/hello4.cc
new file mode 100644 (file)
index 0000000..a94df19
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int f4() {
+  return 0;
+}
diff --git a/gyp/test/win/shard/shard.gyp b/gyp/test/win/shard/shard.gyp
new file mode 100644 (file)
index 0000000..eac45fc
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'shard',
+      'type': 'static_library',
+      'msvs_shard': 4,
+      'sources': [
+        'hello1.cc',
+        'hello2.cc',
+        'hello3.cc',
+        'hello4.cc',
+      ],
+      'product_dir': '<(PRODUCT_DIR)',
+    },
+    {
+      'target_name': 'refs_to_shard',
+      'type': 'executable',
+      'dependencies': [
+        # Make sure references are correctly updated.
+        'shard',
+      ],
+      'sources': [
+        'hello.cc',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/shard/shard_ref.gyp b/gyp/test/win/shard/shard_ref.gyp
new file mode 100644 (file)
index 0000000..3ec8d76
--- /dev/null
@@ -0,0 +1,41 @@
+# Copyright 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'refs_to_shard_external_lib',
+      'type': 'static_library',
+      'dependencies': [
+        # Make sure references in other files are updated correctly.
+        'shard.gyp:shard',
+      ],
+      'sources': [
+        'hello.cc',
+      ],
+    },
+    {
+      'target_name': 'refs_to_shard_external_exe',
+      'type': 'executable',
+      'dependencies': [
+        # Make sure references in other files are updated correctly.
+        'shard.gyp:shard',
+      ],
+      'sources': [
+        'hello.cc',
+      ],
+    },
+    {
+      'target_name': 'refs_to_shard_external_dll',
+      'type': 'shared_library',
+      'dependencies': [
+        # Make sure references in other files are updated correctly.
+        'shard.gyp:shard',
+      ],
+      'sources': [
+        'hello.cc',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/system-include/bar/header.h b/gyp/test/win/system-include/bar/header.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/win/system-include/common/commonheader.h b/gyp/test/win/system-include/common/commonheader.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/win/system-include/foo/header.h b/gyp/test/win/system-include/foo/header.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/win/system-include/main.cc b/gyp/test/win/system-include/main.cc
new file mode 100644 (file)
index 0000000..b04ea8a
--- /dev/null
@@ -0,0 +1,4 @@
+#include <commonheader.h>
+#include <header.h>
+
+int main() {}
diff --git a/gyp/test/win/system-include/test.gyp b/gyp/test/win/system-include/test.gyp
new file mode 100644 (file)
index 0000000..07f2636
--- /dev/null
@@ -0,0 +1,26 @@
+{
+  'target_defaults': {
+    'msvs_settings': {
+      'VCCLCompilerTool': {
+        'WarningLevel': '4',
+        'WarnAsError': 'true',
+      },
+    },
+    'msvs_system_include_dirs': [
+      '$(ProjectName)',  # Different for each target
+      'common',  # Same for all targets
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'executable',
+      'sources': [ 'main.cc', ],
+    },
+    {
+      'target_name': 'bar',
+      'type': 'executable',
+      'sources': [ 'main.cc', ],
+    },
+  ],
+}
diff --git a/gyp/test/win/uldi/a.cc b/gyp/test/win/uldi/a.cc
new file mode 100644 (file)
index 0000000..0fe05d5
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int some_function() {
+  return 0;
+}
diff --git a/gyp/test/win/uldi/b.cc b/gyp/test/win/uldi/b.cc
new file mode 100644 (file)
index 0000000..0fe05d5
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int some_function() {
+  return 0;
+}
diff --git a/gyp/test/win/uldi/main.cc b/gyp/test/win/uldi/main.cc
new file mode 100644 (file)
index 0000000..81b46d8
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern int some_function();
+
+int main() {
+  some_function();
+  return 0;
+}
diff --git a/gyp/test/win/uldi/uldi.gyp b/gyp/test/win/uldi/uldi.gyp
new file mode 100644 (file)
index 0000000..c32f5e0
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'lib1',
+      'type': 'static_library',
+      'sources': ['a.cc'],
+    },
+    {
+      'target_name': 'final_uldi',
+      'type': 'executable',
+      'dependencies': [
+        'lib1',
+        'lib2',
+      ],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'UseLibraryDependencyInputs': 'true'
+        },
+      },
+      'sources': ['main.cc'],
+    },
+    {
+      'target_name': 'final_no_uldi',
+      'type': 'executable',
+      'dependencies': [
+        'lib1',
+        'lib2',
+      ],
+      'sources': ['main.cc'],
+    },
+    {
+      'target_name': 'lib2',
+      'type': 'static_library',
+      # b.cc has the same named function as a.cc, but don't use the same name
+      # so that the .obj will have a different name. If the obj file has the
+      # same name, the linker will discard the obj file, invalidating the
+      # test.
+      'sources': ['b.cc'],
+    },
+  ]
+}
diff --git a/gyp/test/win/vs-macros/as.py b/gyp/test/win/vs-macros/as.py
new file mode 100644 (file)
index 0000000..e0bc3ae
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from optparse import OptionParser
+
+parser = OptionParser()
+parser.add_option('-a', dest='platform')
+parser.add_option('-o', dest='output')
+parser.add_option('-p', dest='path')
+(options, args) = parser.parse_args()
+
+f = open(options.output, 'w')
+print >>f, 'options', options
+print >>f, 'args', args
+f.close()
diff --git a/gyp/test/win/vs-macros/containing-gyp.gyp b/gyp/test/win/vs-macros/containing-gyp.gyp
new file mode 100644 (file)
index 0000000..c07b639
--- /dev/null
@@ -0,0 +1,39 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_expansions',
+      'msvs_cygwin_shell': 0,
+      'type': 'none',
+      'rules': [
+        {
+          'rule_name': 'assembler (gnu-compatible)',
+          'msvs_cygwin_shell': 0,
+          'msvs_quote_cmd': 0,
+          'extension': 'S',
+          'inputs': [
+            'as.py',
+          ],
+          'outputs': [
+            '$(IntDir)/$(InputName).obj',
+          ],
+          'action':
+            ['python',
+              'as.py',
+              '-a', '$(PlatformName)',
+              '-o', '$(IntDir)/$(InputName).obj',
+              '-p', '<(DEPTH)',
+              '$(InputPath)'],
+          'message': 'Building assembly language file $(InputPath)',
+          'process_outputs_as_sources': 1,
+        },
+      ],
+      'sources': [
+        'input.S',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/vs-macros/do_stuff.py b/gyp/test/win/vs-macros/do_stuff.py
new file mode 100644 (file)
index 0000000..4669d31
--- /dev/null
@@ -0,0 +1,8 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+input = open(sys.argv[1], "r").read()
+open(sys.argv[2], "w").write(input + "Modified.")
diff --git a/gyp/test/win/vs-macros/hello.cc b/gyp/test/win/vs-macros/hello.cc
new file mode 100644 (file)
index 0000000..1711567
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+  return 0;
+}
diff --git a/gyp/test/win/vs-macros/input-output-macros.gyp b/gyp/test/win/vs-macros/input-output-macros.gyp
new file mode 100644 (file)
index 0000000..b4520f8
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_expansions',
+      'msvs_cygwin_shell': 0,
+      'type': 'none',
+      'rules': [
+        {
+          'rule_name': 'generate_file',
+          'extension': 'blah',
+          'inputs': [
+            'do_stuff.py',
+          ],
+          'outputs': [
+            '$(OutDir)\\<(RULE_INPUT_NAME).something',
+          ],
+          'action': ['python',
+                     'do_stuff.py',
+                     '<(RULE_INPUT_PATH)',
+                     '$(OutDir)\\<(RULE_INPUT_NAME).something',],
+        },
+      ],
+      'sources': [
+        'stuff.blah',
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/vs-macros/input.S b/gyp/test/win/vs-macros/input.S
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gyp/test/win/vs-macros/projectname.gyp b/gyp/test/win/vs-macros/projectname.gyp
new file mode 100644 (file)
index 0000000..625a177
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_expansions',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '$(OutDir)\\$(ProjectName)_plus_something.exe',
+        },
+      },
+    },
+    {
+      'target_name': 'test_with_product_name',
+      'product_name': 'prod_name',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '$(OutDir)\\$(ProjectName)_plus_something.exe',
+        },
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/vs-macros/stuff.blah b/gyp/test/win/vs-macros/stuff.blah
new file mode 100644 (file)
index 0000000..d438b4a
--- /dev/null
@@ -0,0 +1 @@
+Random data file.
diff --git a/gyp/test/win/vs-macros/targetname.gyp b/gyp/test/win/vs-macros/targetname.gyp
new file mode 100644 (file)
index 0000000..a53d3c0
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_targetname',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '$(TargetDir)\\$(TargetName)_plus_something1.exe',
+        },
+      },
+    },
+    {
+      'target_name': 'test_targetname_with_prefix',
+      'product_prefix': 'prod_prefix',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '$(TargetDir)\\$(TargetName)_plus_something2.exe',
+        },
+      },
+    },
+    {
+      'target_name': 'test_targetname_with_prodname',
+      'product_name': 'prod_name',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '$(TargetDir)\\$(TargetName)_plus_something3.exe',
+        },
+      },
+    },
+    {
+      'target_name': 'test_targetname_with_prodname_with_prefix',
+      'product_name': 'prod_name',
+      'product_prefix': 'prod_prefix',
+      'type': 'executable',
+      'sources': ['hello.cc'],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'OutputFile': '$(TargetDir)\\$(TargetName)_plus_something4.exe',
+        },
+      },
+    },
+  ]
+}
diff --git a/gyp/test/win/vs-macros/test_exists.py b/gyp/test/win/vs-macros/test_exists.py
new file mode 100644 (file)
index 0000000..f5c90ad
--- /dev/null
@@ -0,0 +1,10 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+
+if not os.path.exists(sys.argv[1]):
+  raise
+open(sys.argv[2], 'w').close()
diff --git a/gyp/test/win/vs-macros/vcinstalldir.gyp b/gyp/test/win/vs-macros/vcinstalldir.gyp
new file mode 100644 (file)
index 0000000..3763a4e
--- /dev/null
@@ -0,0 +1,41 @@
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_slash_trailing',
+      'type': 'none',
+      'msvs_cygwin_shell': '0',
+      'actions': [
+        {
+          'action_name': 'root',
+          'inputs': [],
+          'outputs': ['out1'],
+          'action': ['python', 'test_exists.py', '$(VCInstallDir)', 'out1']
+        },
+      ],
+    },
+    {
+      'target_name': 'test_slash_dir',
+      'type': 'none',
+      'msvs_cygwin_shell': '0',
+      'actions': [
+        {
+          'action_name': 'bin',
+          'inputs': [],
+          'outputs': ['out2'],
+          'action': ['python', 'test_exists.py', '$(VCInstallDir)bin', 'out2'],
+        },
+        {
+          'action_name': 'compiler',
+          'inputs': [],
+          'outputs': ['out3'],
+          'action': [
+              'python', 'test_exists.py', '$(VCInstallDir)bin\\cl.exe', 'out3'],
+        },
+      ],
+    },
+  ]
+}
diff --git a/gyp/test/win/win-tool/copies_readonly_files.gyp b/gyp/test/win/win-tool/copies_readonly_files.gyp
new file mode 100644 (file)
index 0000000..3cd7e69
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  'targets': [
+    {
+      'target_name': 'foo',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/dest',
+          'files': [
+            'read-only-file',
+          ],
+        },
+      ],
+    },  # target: foo
+
+    {
+      'target_name': 'bar',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/dest',
+          'files': [
+            'subdir/',
+          ],
+        },
+      ],
+    },  # target: bar
+  ],
+}
diff --git a/gyp/test/win/win-tool/gyptest-win-tool-handles-readonly-files.py b/gyp/test/win/win-tool/gyptest-win-tool-handles-readonly-files.py
new file mode 100644 (file)
index 0000000..951b952
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure overwriting read-only files works as expected (via win-tool).
+"""
+
+import TestGyp
+
+import filecmp
+import os
+import stat
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  # First, create the source files.
+  os.makedirs('subdir')
+  read_only_files = ['read-only-file', 'subdir/A', 'subdir/B', 'subdir/C']
+  for f in read_only_files:
+    test.write(f, 'source_contents')
+    test.chmod(f, stat.S_IREAD)
+    if os.access(f, os.W_OK):
+      test.fail_test()
+
+  # Second, create the read-only destination files. Note that we are creating
+  # them where the ninja and win-tool will try to copy them to, in order to test
+  # that copies overwrite the files.
+  os.makedirs(test.built_file_path('dest/subdir'))
+  for f in read_only_files:
+    f = os.path.join('dest', f)
+    test.write(test.built_file_path(f), 'SHOULD BE OVERWRITTEN')
+    test.chmod(test.built_file_path(f), stat.S_IREAD)
+    # Ensure not writable.
+    if os.access(test.built_file_path(f), os.W_OK):
+      test.fail_test()
+
+  test.run_gyp('copies_readonly_files.gyp')
+  test.build('copies_readonly_files.gyp')
+
+  # Check the destination files were overwritten by ninja.
+  for f in read_only_files:
+    f = os.path.join('dest', f)
+    test.must_contain(test.built_file_path(f), 'source_contents')
+
+  # This will fail if the files are not the same mode or contents.
+  for f in read_only_files:
+    if not filecmp.cmp(f, test.built_file_path(os.path.join('dest', f))):
+      test.fail_test()
+
+  test.pass_test()
diff --git a/gyp/tools/README b/gyp/tools/README
new file mode 100644 (file)
index 0000000..712e4ef
--- /dev/null
@@ -0,0 +1,15 @@
+pretty_vcproj:
+  Usage: pretty_vcproj.py "c:\path\to\vcproj.vcproj" [key1=value1] [key2=value2]
+
+  They key/value pair are used to resolve vsprops name.
+
+  For example, if I want to diff the base.vcproj project:
+
+  pretty_vcproj.py z:\dev\src-chrome\src\base\build\base.vcproj "$(SolutionDir)=z:\dev\src-chrome\src\chrome\\" "$(CHROMIUM_BUILD)=" "$(CHROME_BUILD_TYPE)=" > orignal.txt
+  pretty_vcproj.py z:\dev\src-chrome\src\base\base_gyp.vcproj "$(SolutionDir)=z:\dev\src-chrome\src\chrome\\" "$(CHROMIUM_BUILD)=" "$(CHROME_BUILD_TYPE)=" > gyp.txt
+
+  And you can use your favorite diff tool to see the changes.
+
+  Note: In the case of base.vcproj, the original vcproj is one level up the generated one.
+        I suggest you do a search and replace for '"..\' and replace it with '"' in original.txt
+        before you perform the diff.
\ No newline at end of file
diff --git a/gyp/tools/Xcode/README b/gyp/tools/Xcode/README
new file mode 100644 (file)
index 0000000..2492a2c
--- /dev/null
@@ -0,0 +1,5 @@
+Specifications contains syntax formatters for Xcode 3. These do not appear to be supported yet on Xcode 4. To use these with Xcode 3 please install both the gyp.pbfilespec and gyp.xclangspec files in
+
+~/Library/Application Support/Developer/Shared/Xcode/Specifications/
+
+and restart Xcode.
\ No newline at end of file
diff --git a/gyp/tools/Xcode/Specifications/gyp.pbfilespec b/gyp/tools/Xcode/Specifications/gyp.pbfilespec
new file mode 100644 (file)
index 0000000..85e2e26
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+       gyp.pbfilespec
+       GYP source file spec for Xcode 3
+
+       There is not much documentation available regarding the format
+       of .pbfilespec files. As a starting point, see for instance the
+       outdated documentation at:
+       http://maxao.free.fr/xcode-plugin-interface/specifications.html
+       and the files in:
+       /Developer/Library/PrivateFrameworks/XcodeEdit.framework/Versions/A/Resources/
+
+       Place this file in directory:
+       ~/Library/Application Support/Developer/Shared/Xcode/Specifications/
+*/
+
+(
+       {
+               Identifier = sourcecode.gyp;
+               BasedOn = sourcecode;
+               Name = "GYP Files";
+               Extensions = ("gyp", "gypi");
+               MIMETypes = ("text/gyp");
+               Language = "xcode.lang.gyp";
+               IsTextFile = YES;
+               IsSourceFile = YES;
+       }
+)
diff --git a/gyp/tools/Xcode/Specifications/gyp.xclangspec b/gyp/tools/Xcode/Specifications/gyp.xclangspec
new file mode 100644 (file)
index 0000000..3b3506d
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+       Copyright (c) 2011 Google Inc. All rights reserved.
+       Use of this source code is governed by a BSD-style license that can be
+       found in the LICENSE file.
+       
+       gyp.xclangspec
+       GYP language specification for Xcode 3
+
+       There is not much documentation available regarding the format
+       of .xclangspec files. As a starting point, see for instance the
+       outdated documentation at:
+       http://maxao.free.fr/xcode-plugin-interface/specifications.html
+       and the files in:
+       /Developer/Library/PrivateFrameworks/XcodeEdit.framework/Versions/A/Resources/
+
+       Place this file in directory:
+       ~/Library/Application Support/Developer/Shared/Xcode/Specifications/
+*/
+
+(
+
+    {
+        Identifier = "xcode.lang.gyp.keyword";
+        Syntax = {
+            Words = (
+                "and",
+                "or",
+                "<!",
+                "<",
+             );
+            Type = "xcode.syntax.keyword";
+        };
+    },
+
+    {
+        Identifier = "xcode.lang.gyp.target.declarator";
+        Syntax = {
+               Words = (
+                       "'target_name'",
+               );
+            Type = "xcode.syntax.identifier.type";
+        };
+    },
+
+       {
+               Identifier = "xcode.lang.gyp.string.singlequote";
+               Syntax = {
+                       IncludeRules = (
+                               "xcode.lang.string",
+                               "xcode.lang.gyp.keyword",
+                               "xcode.lang.number",
+                       );
+                       Start = "'";
+                       End = "'";
+               };
+       },
+       
+       {
+               Identifier = "xcode.lang.gyp.comma";
+               Syntax = {
+                       Words = ( ",", );
+                       
+               };
+       },
+
+       {
+               Identifier = "xcode.lang.gyp";
+               Description = "GYP Coloring";
+               BasedOn = "xcode.lang.simpleColoring";
+               IncludeInMenu = YES;
+               Name = "GYP";
+               Syntax = {
+                       Tokenizer = "xcode.lang.gyp.lexer.toplevel";
+                       IncludeRules = (
+                               "xcode.lang.gyp.dictionary",
+                       );
+                       Type = "xcode.syntax.plain";
+               };
+       },
+
+       // The following rule returns tokens to the other rules
+       {
+               Identifier = "xcode.lang.gyp.lexer";
+               Syntax = {
+                       IncludeRules = (
+                               "xcode.lang.gyp.comment",
+                               "xcode.lang.string",
+                               'xcode.lang.gyp.targetname.declarator',
+                               "xcode.lang.gyp.string.singlequote",
+                               "xcode.lang.number",
+                               "xcode.lang.gyp.comma",
+                       );
+               };
+       },
+
+       {
+               Identifier = "xcode.lang.gyp.lexer.toplevel";
+               Syntax = {
+                       IncludeRules = (
+                               "xcode.lang.gyp.comment",
+                       );
+               };
+       },
+
+       {
+        Identifier = "xcode.lang.gyp.assignment";
+        Syntax = {
+            Tokenizer = "xcode.lang.gyp.lexer";
+            Rules = (
+               "xcode.lang.gyp.assignment.lhs",
+               ":",
+                "xcode.lang.gyp.assignment.rhs",
+            );
+        };
+       
+    },
+    
+    {
+        Identifier = "xcode.lang.gyp.target.declaration";
+        Syntax = {
+            Tokenizer = "xcode.lang.gyp.lexer";
+            Rules = (
+                "xcode.lang.gyp.target.declarator",
+                ":",
+                "xcode.lang.gyp.target.name",
+            );
+        };
+   },
+   
+   {
+        Identifier = "xcode.lang.gyp.target.name";
+        Syntax = {
+            Tokenizer = "xcode.lang.gyp.lexer";
+            Rules = (
+                "xcode.lang.gyp.string.singlequote",
+            );
+               Type = "xcode.syntax.definition.function";
+        };
+    },
+    
+       {
+        Identifier = "xcode.lang.gyp.assignment.lhs";
+        Syntax = {
+            Tokenizer = "xcode.lang.gyp.lexer";
+            Rules = (
+               "xcode.lang.gyp.string.singlequote",
+            );
+               Type = "xcode.syntax.identifier.type";
+        };
+    },
+    
+    {
+        Identifier = "xcode.lang.gyp.assignment.rhs";
+        Syntax = {
+               Tokenizer = "xcode.lang.gyp.lexer";
+            Rules = (
+               "xcode.lang.gyp.string.singlequote?",
+                "xcode.lang.gyp.array?",
+                               "xcode.lang.gyp.dictionary?",
+                               "xcode.lang.number?",
+            );
+        };
+    },
+
+       {
+               Identifier = "xcode.lang.gyp.dictionary";
+               Syntax = {
+                       Tokenizer = "xcode.lang.gyp.lexer";
+                       Start = "{";
+                       End = "}";
+                       Foldable = YES;
+                       Recursive = YES;
+                       IncludeRules = (
+                               "xcode.lang.gyp.target.declaration",
+                               "xcode.lang.gyp.assignment",
+                       );
+               };
+       },
+
+       {
+               Identifier = "xcode.lang.gyp.array";
+               Syntax = {
+                       Tokenizer = "xcode.lang.gyp.lexer";
+                       Start = "[";
+                       End = "]";
+                       Foldable = YES;
+                       Recursive = YES;
+                       IncludeRules = (
+                               "xcode.lang.gyp.array",
+                               "xcode.lang.gyp.dictionary",
+                               "xcode.lang.gyp.string.singlequote",
+                       );
+               };
+       },
+
+    {
+        Identifier = "xcode.lang.gyp.todo.mark";
+        Syntax = {
+            StartChars = "T";
+            Match = (
+                "^\(TODO\(.*\):[ \t]+.*\)$",       // include "TODO: " in the markers list
+            );
+            // This is the order of captures. All of the match strings above need the same order.
+            CaptureTypes = (
+                "xcode.syntax.mark"
+            );
+            Type = "xcode.syntax.comment";
+        };
+    },
+
+       {
+               Identifier = "xcode.lang.gyp.comment";
+               BasedOn = "xcode.lang.comment"; // for text macros
+               Syntax = {
+                       Start = "#";
+                       End = "\n";
+                       IncludeRules = (
+                               "xcode.lang.url",
+                               "xcode.lang.url.mail",
+                               "xcode.lang.comment.mark",
+                               "xcode.lang.gyp.todo.mark",
+                       );
+                       Type = "xcode.syntax.comment";
+               };
+       },
+)
diff --git a/gyp/tools/emacs/README b/gyp/tools/emacs/README
new file mode 100644 (file)
index 0000000..eeef39f
--- /dev/null
@@ -0,0 +1,12 @@
+How to install gyp-mode for emacs:
+
+Add the following to your ~/.emacs (replace ... with the path to your gyp
+checkout).
+
+(setq load-path (cons ".../tools/emacs" load-path))
+(require 'gyp)
+
+Restart emacs (or eval-region the added lines) and you should be all set.
+
+Please note that ert is required for running the tests, which is included in
+Emacs 24, or available separately from https://github.com/ohler/ert
diff --git a/gyp/tools/emacs/gyp-tests.el b/gyp/tools/emacs/gyp-tests.el
new file mode 100644 (file)
index 0000000..11b8497
--- /dev/null
@@ -0,0 +1,63 @@
+;;; gyp-tests.el - unit tests for gyp-mode.
+
+;; Copyright (c) 2012 Google Inc. All rights reserved.
+;; Use of this source code is governed by a BSD-style license that can be
+;; found in the LICENSE file.
+
+;; The recommended way to run these tests is to run them from the command-line,
+;; with the run-unit-tests.sh script.
+
+(require 'cl)
+(require 'ert)
+(require 'gyp)
+
+(defconst samples (directory-files "testdata" t ".gyp$")
+  "List of golden samples to check")
+
+(defun fontify (filename)
+  (with-temp-buffer
+    (insert-file-contents-literally filename)
+    (gyp-mode)
+    (font-lock-fontify-buffer)
+    (buffer-string)))
+
+(defun read-golden-sample (filename)
+  (with-temp-buffer
+    (insert-file-contents-literally (concat filename ".fontified"))
+    (read (current-buffer))))
+
+(defun equivalent-face (face)
+  "For the purposes of face comparison, we're not interested in the
+   differences between certain faces. For example, the difference between
+   font-lock-comment-delimiter and font-lock-comment-face."
+  (case face
+    ((font-lock-comment-delimiter-face) font-lock-comment-face)
+    (t face)))
+
+(defun text-face-properties (s)
+  "Extract the text properties from s"
+  (let ((result (list t)))
+    (dotimes (i (length s))
+      (setq result (cons (equivalent-face (get-text-property i 'face s))
+                         result)))
+    (nreverse result)))
+
+(ert-deftest test-golden-samples ()
+  "Check that fontification produces the same results as the golden samples"
+  (dolist (sample samples)
+    (let ((golden (read-golden-sample sample))
+          (fontified (fontify sample)))
+      (should (equal golden fontified))
+      (should (equal (text-face-properties golden)
+                     (text-face-properties fontified))))))
+
+(defun create-golden-sample (filename)
+  "Create a golden sample by fontifying filename and writing out the printable
+   representation of the fontified buffer (with text properties) to the
+   FILENAME.fontified"
+  (with-temp-file (concat filename ".fontified")
+    (print (fontify filename) (current-buffer))))
+
+(defun create-golden-samples ()
+  "Recreate the golden samples"
+  (dolist (sample samples) (create-golden-sample sample)))
diff --git a/gyp/tools/emacs/gyp.el b/gyp/tools/emacs/gyp.el
new file mode 100644 (file)
index 0000000..3db9f64
--- /dev/null
@@ -0,0 +1,252 @@
+;;; gyp.el - font-lock-mode support for gyp files.
+
+;; Copyright (c) 2012 Google Inc. All rights reserved.
+;; Use of this source code is governed by a BSD-style license that can be
+;; found in the LICENSE file.
+
+;; Put this somewhere in your load-path and
+;; (require 'gyp)
+
+(require 'python)
+(require 'cl)
+
+(when (string-match "python-mode.el" (symbol-file 'python-mode 'defun))
+  (error (concat "python-mode must be loaded from python.el (bundled with "
+                 "recent emacsen), not from the older and less maintained "
+                 "python-mode.el")))
+
+(defadvice python-calculate-indentation (after ami-outdent-closing-parens
+                                               activate)
+  "De-indent closing parens, braces, and brackets in gyp-mode."
+  (if (and (eq major-mode 'gyp-mode)
+           (string-match "^ *[])}][],)}]* *$"
+                         (buffer-substring-no-properties
+                          (line-beginning-position) (line-end-position))))
+      (setq ad-return-value (- ad-return-value 2))))
+
+(define-derived-mode gyp-mode python-mode "Gyp"
+  "Major mode for editing .gyp files. See http://code.google.com/p/gyp/"
+  ;; gyp-parse-history is a stack of (POSITION . PARSE-STATE) tuples,
+  ;; with greater positions at the top of the stack. PARSE-STATE
+  ;; is a list of section symbols (see gyp-section-name and gyp-parse-to)
+  ;; with most nested section symbol at the front of the list.
+  (set (make-local-variable 'gyp-parse-history) '((1 . (list))))
+  (gyp-add-font-lock-keywords))
+
+(defun gyp-set-indentation ()
+  "Hook function to configure python indentation to suit gyp mode."
+  (setq python-continuation-offset 2
+        python-indent 2
+        python-guess-indent nil))
+
+(add-hook 'gyp-mode-hook 'gyp-set-indentation)
+
+(add-to-list 'auto-mode-alist '("\\.gyp\\'" . gyp-mode))
+(add-to-list 'auto-mode-alist '("\\.gypi\\'" . gyp-mode))
+(add-to-list 'auto-mode-alist '("/\\.gclient\\'" . gyp-mode))
+
+;;; Font-lock support
+
+(defconst gyp-dependencies-regexp
+  (regexp-opt (list "dependencies" "export_dependent_settings"))
+  "Regular expression to introduce 'dependencies' section")
+
+(defconst gyp-sources-regexp
+  (regexp-opt (list "action" "files" "include_dirs" "includes" "inputs"
+                    "libraries" "outputs" "sources"))
+  "Regular expression to introduce 'sources' sections")
+
+(defconst gyp-conditions-regexp
+  (regexp-opt (list "conditions" "target_conditions"))
+  "Regular expression to introduce conditions sections")
+
+(defconst gyp-variables-regexp
+  "^variables"
+  "Regular expression to introduce variables sections")
+
+(defconst gyp-defines-regexp
+  "^defines"
+  "Regular expression to introduce 'defines' sections")
+
+(defconst gyp-targets-regexp
+  "^targets"
+  "Regular expression to introduce 'targets' sections")
+
+(defun gyp-section-name (section)
+  "Map the sections we are interested in from SECTION to symbol.
+
+   SECTION is a string from the buffer that introduces a section.  The result is
+   a symbol representing the kind of section.
+
+   This allows us to treat (for the purposes of font-lock) several different
+   section names as the same kind of section. For example, a 'sources section
+   can be introduced by the 'sources', 'inputs', 'outputs' keyword.
+
+   'other is the default section kind when a more specific match is not made."
+  (cond ((string-match-p gyp-dependencies-regexp section) 'dependencies)
+        ((string-match-p gyp-sources-regexp section) 'sources)
+        ((string-match-p gyp-variables-regexp section) 'variables)
+        ((string-match-p gyp-conditions-regexp section) 'conditions)
+        ((string-match-p gyp-targets-regexp section) 'targets)
+        ((string-match-p gyp-defines-regexp section) 'defines)
+        (t 'other)))
+
+(defun gyp-invalidate-parse-states-after (target-point)
+  "Erase any parse information after target-point."
+  (while (> (caar gyp-parse-history) target-point)
+    (setq gyp-parse-history (cdr gyp-parse-history))))
+
+(defun gyp-parse-point ()
+  "The point of the last parse state added by gyp-parse-to."
+  (caar gyp-parse-history))
+
+(defun gyp-parse-sections ()
+  "A list of section symbols holding at the last parse state point."
+  (cdar gyp-parse-history))
+
+(defun gyp-inside-dictionary-p ()
+  "Predicate returning true if the parser is inside a dictionary."
+  (not (eq (cadar gyp-parse-history) 'list)))
+
+(defun gyp-add-parse-history (point sections)
+  "Add parse state SECTIONS to the parse history at POINT so that parsing can be
+   resumed instantly."
+  (while (>= (caar gyp-parse-history) point)
+    (setq gyp-parse-history (cdr gyp-parse-history)))
+  (setq gyp-parse-history (cons (cons point sections) gyp-parse-history)))
+
+(defun gyp-parse-to (target-point)
+  "Parses from (point) to TARGET-POINT adding the parse state information to
+   gyp-parse-state-history. Parsing stops if TARGET-POINT is reached or if a
+   string literal has been parsed. Returns nil if no further parsing can be
+   done, otherwise returns the position of the start of a parsed string, leaving
+   the point at the end of the string."
+  (let ((parsing t)
+        string-start)
+    (while parsing
+      (setq string-start nil)
+      ;; Parse up to a character that starts a sexp, or if the nesting
+      ;; level decreases.
+      (let ((state (parse-partial-sexp (gyp-parse-point)
+                                       target-point
+                                       -1
+                                       t))
+            (sections (gyp-parse-sections)))
+        (if (= (nth 0 state) -1)
+            (setq sections (cdr sections)) ; pop out a level
+          (cond ((looking-at-p "['\"]") ; a string
+                 (setq string-start (point))
+                 (goto-char (scan-sexps (point) 1))
+                 (if (gyp-inside-dictionary-p)
+                     ;; Look for sections inside a dictionary
+                     (let ((section (gyp-section-name
+                                     (buffer-substring-no-properties
+                                      (+ 1 string-start)
+                                      (- (point) 1)))))
+                       (setq sections (cons section (cdr sections)))))
+                 ;; Stop after the string so it can be fontified.
+                 (setq target-point (point)))
+                ((looking-at-p "{")
+                 ;; Inside a dictionary. Increase nesting.
+                 (forward-char 1)
+                 (setq sections (cons 'unknown sections)))
+                ((looking-at-p "\\[")
+                 ;; Inside a list. Increase nesting
+                 (forward-char 1)
+                 (setq sections (cons 'list sections)))
+                ((not (eobp))
+                 ;; other
+                 (forward-char 1))))
+        (gyp-add-parse-history (point) sections)
+        (setq parsing (< (point) target-point))))
+    string-start))
+
+(defun gyp-section-at-point ()
+  "Transform the last parse state, which is a list of nested sections and return
+   the section symbol that should be used to determine font-lock information for
+   the string. Can return nil indicating the string should not have any attached
+   section."
+  (let ((sections (gyp-parse-sections)))
+    (cond
+     ((eq (car sections) 'conditions)
+      ;; conditions can occur in a variables section, but we still want to
+      ;; highlight it as a keyword.
+      nil)
+     ((and (eq (car sections) 'list)
+           (eq (cadr sections) 'list))
+      ;; conditions and sources can have items in [[ ]]
+      (caddr sections))
+     (t (cadr sections)))))
+
+(defun gyp-section-match (limit)
+  "Parse from (point) to LIMIT returning by means of match data what was
+   matched. The group of the match indicates what style font-lock should apply.
+   See also `gyp-add-font-lock-keywords'."
+  (gyp-invalidate-parse-states-after (point))
+  (let ((group nil)
+        (string-start t))
+    (while (and (< (point) limit)
+                (not group)
+                string-start)
+      (setq string-start (gyp-parse-to limit))
+      (if string-start
+          (setq group (case (gyp-section-at-point)
+                        ('dependencies 1)
+                        ('variables 2)
+                        ('conditions 2)
+                        ('sources 3)
+                        ('defines 4)
+                        (nil nil)))))
+    (if group
+        (progn
+          ;; Set the match data to indicate to the font-lock mechanism the
+          ;; highlighting to be performed.
+          (set-match-data (append (list string-start (point))
+                                  (make-list (* (1- group) 2) nil)
+                                  (list (1+ string-start) (1- (point)))))
+          t))))
+
+;;; Please see http://code.google.com/p/gyp/wiki/GypLanguageSpecification for
+;;; canonical list of keywords.
+(defun gyp-add-font-lock-keywords ()
+  "Add gyp-mode keywords to font-lock mechanism."
+  ;; TODO(jknotten): Move all the keyword highlighting into gyp-section-match
+  ;; so that we can do the font-locking in a single font-lock pass.
+  (font-lock-add-keywords
+   nil
+   (list
+    ;; Top-level keywords
+    (list (concat "['\"]\\("
+              (regexp-opt (list "action" "action_name" "actions" "cflags"
+                                "conditions" "configurations" "copies" "defines"
+                                "dependencies" "destination"
+                                "direct_dependent_settings"
+                                "export_dependent_settings" "extension" "files"
+                                "include_dirs" "includes" "inputs" "libraries"
+                                "link_settings" "mac_bundle" "message"
+                                "msvs_external_rule" "outputs" "product_name"
+                                "process_outputs_as_sources" "rules" "rule_name"
+                                "sources" "suppress_wildcard"
+                                "target_conditions" "target_defaults"
+                                "target_defines" "target_name" "toolsets"
+                                "targets" "type" "variables" "xcode_settings"))
+              "[!/+=]?\\)") 1 'font-lock-keyword-face t)
+    ;; Type of target
+    (list (concat "['\"]\\("
+              (regexp-opt (list "loadable_module" "static_library"
+                                "shared_library" "executable" "none"))
+              "\\)") 1 'font-lock-type-face t)
+    (list "\\(?:target\\|action\\)_name['\"]\\s-*:\\s-*['\"]\\([^ '\"]*\\)" 1
+          'font-lock-function-name-face t)
+    (list 'gyp-section-match
+          (list 1 'font-lock-function-name-face t t) ; dependencies
+          (list 2 'font-lock-variable-name-face t t) ; variables, conditions
+          (list 3 'font-lock-constant-face t t) ; sources
+          (list 4 'font-lock-preprocessor-face t t)) ; preprocessor
+    ;; Variable expansion
+    (list "<@?(\\([^\n )]+\\))" 1 'font-lock-variable-name-face t)
+    ;; Command expansion
+    (list "<!@?(\\([^\n )]+\\))" 1 'font-lock-variable-name-face t)
+    )))
+
+(provide 'gyp)
diff --git a/gyp/tools/emacs/run-unit-tests.sh b/gyp/tools/emacs/run-unit-tests.sh
new file mode 100755 (executable)
index 0000000..6e62b9b
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+emacs --no-site-file --no-init-file --batch \
+      --load ert.el --load gyp.el --load gyp-tests.el \
+      -f ert-run-tests-batch-and-exit
diff --git a/gyp/tools/emacs/testdata/media.gyp b/gyp/tools/emacs/testdata/media.gyp
new file mode 100644 (file)
index 0000000..29300fe
--- /dev/null
@@ -0,0 +1,1105 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+    # Override to dynamically link the PulseAudio library.
+    'use_pulseaudio%': 0,
+    # Override to dynamically link the cras (ChromeOS audio) library.
+    'use_cras%': 0,
+  },
+  'targets': [
+    {
+      'target_name': 'media',
+      'type': '<(component)',
+      'dependencies': [
+        'yuv_convert',
+        '../base/base.gyp:base',
+        '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '../build/temp_gyp/googleurl.gyp:googleurl',
+        '../crypto/crypto.gyp:crypto',
+        '../third_party/openmax/openmax.gyp:il',
+        '../ui/ui.gyp:ui',
+      ],
+      'defines': [
+        'MEDIA_IMPLEMENTATION',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'audio/android/audio_manager_android.cc',
+        'audio/android/audio_manager_android.h',
+        'audio/android/audio_track_output_android.cc',
+        'audio/android/audio_track_output_android.h',
+        'audio/android/opensles_input.cc',
+        'audio/android/opensles_input.h',
+        'audio/android/opensles_output.cc',
+        'audio/android/opensles_output.h',
+        'audio/async_socket_io_handler.h',
+        'audio/async_socket_io_handler_posix.cc',
+        'audio/async_socket_io_handler_win.cc',
+        'audio/audio_buffers_state.cc',
+        'audio/audio_buffers_state.h',
+        'audio/audio_io.h',
+        'audio/audio_input_controller.cc',
+        'audio/audio_input_controller.h',
+        'audio/audio_input_stream_impl.cc',
+        'audio/audio_input_stream_impl.h',
+        'audio/audio_device_name.cc',
+        'audio/audio_device_name.h',
+        'audio/audio_manager.cc',
+        'audio/audio_manager.h',
+        'audio/audio_manager_base.cc',
+        'audio/audio_manager_base.h',
+        'audio/audio_output_controller.cc',
+        'audio/audio_output_controller.h',
+        'audio/audio_output_dispatcher.cc',
+        'audio/audio_output_dispatcher.h',
+        'audio/audio_output_dispatcher_impl.cc',
+        'audio/audio_output_dispatcher_impl.h',
+        'audio/audio_output_mixer.cc',
+        'audio/audio_output_mixer.h',
+        'audio/audio_output_proxy.cc',
+        'audio/audio_output_proxy.h',
+        'audio/audio_parameters.cc',
+        'audio/audio_parameters.h',
+        'audio/audio_util.cc',
+        'audio/audio_util.h',
+        'audio/cross_process_notification.cc',
+        'audio/cross_process_notification.h',
+        'audio/cross_process_notification_win.cc',
+        'audio/cross_process_notification_posix.cc',
+        'audio/fake_audio_input_stream.cc',
+        'audio/fake_audio_input_stream.h',
+        'audio/fake_audio_output_stream.cc',
+        'audio/fake_audio_output_stream.h',
+        'audio/linux/audio_manager_linux.cc',
+        'audio/linux/audio_manager_linux.h',
+        'audio/linux/alsa_input.cc',
+        'audio/linux/alsa_input.h',
+        'audio/linux/alsa_output.cc',
+        'audio/linux/alsa_output.h',
+        'audio/linux/alsa_util.cc',
+        'audio/linux/alsa_util.h',
+        'audio/linux/alsa_wrapper.cc',
+        'audio/linux/alsa_wrapper.h',
+        'audio/linux/cras_output.cc',
+        'audio/linux/cras_output.h',
+        'audio/openbsd/audio_manager_openbsd.cc',
+        'audio/openbsd/audio_manager_openbsd.h',
+        'audio/mac/audio_input_mac.cc',
+        'audio/mac/audio_input_mac.h',
+        'audio/mac/audio_low_latency_input_mac.cc',
+        'audio/mac/audio_low_latency_input_mac.h',
+        'audio/mac/audio_low_latency_output_mac.cc',
+        'audio/mac/audio_low_latency_output_mac.h',
+        'audio/mac/audio_manager_mac.cc',
+        'audio/mac/audio_manager_mac.h',
+        'audio/mac/audio_output_mac.cc',
+        'audio/mac/audio_output_mac.h',
+        'audio/null_audio_sink.cc',
+        'audio/null_audio_sink.h',
+        'audio/pulse/pulse_output.cc',
+        'audio/pulse/pulse_output.h',
+        'audio/sample_rates.cc',
+        'audio/sample_rates.h',
+        'audio/simple_sources.cc',
+        'audio/simple_sources.h',
+        'audio/win/audio_low_latency_input_win.cc',
+        'audio/win/audio_low_latency_input_win.h',
+        'audio/win/audio_low_latency_output_win.cc',
+        'audio/win/audio_low_latency_output_win.h',
+        'audio/win/audio_manager_win.cc',
+        'audio/win/audio_manager_win.h',
+        'audio/win/avrt_wrapper_win.cc',
+        'audio/win/avrt_wrapper_win.h',
+        'audio/win/device_enumeration_win.cc',
+        'audio/win/device_enumeration_win.h',
+        'audio/win/wavein_input_win.cc',
+        'audio/win/wavein_input_win.h',
+        'audio/win/waveout_output_win.cc',
+        'audio/win/waveout_output_win.h',
+        'base/android/media_jni_registrar.cc',
+        'base/android/media_jni_registrar.h',
+        'base/audio_decoder.cc',
+        'base/audio_decoder.h',
+        'base/audio_decoder_config.cc',
+        'base/audio_decoder_config.h',
+        'base/audio_renderer.h',
+        'base/audio_renderer_mixer.cc',
+        'base/audio_renderer_mixer.h',
+        'base/audio_renderer_mixer_input.cc',
+        'base/audio_renderer_mixer_input.h',
+        'base/bitstream_buffer.h',
+        'base/buffers.cc',
+        'base/buffers.h',
+        'base/byte_queue.cc',
+        'base/byte_queue.h',
+        'base/channel_layout.cc',
+        'base/channel_layout.h',
+        'base/clock.cc',
+        'base/clock.h',
+        'base/composite_filter.cc',
+        'base/composite_filter.h',
+        'base/data_buffer.cc',
+        'base/data_buffer.h',
+        'base/data_source.cc',
+        'base/data_source.h',
+        'base/decoder_buffer.cc',
+        'base/decoder_buffer.h',
+        'base/decrypt_config.cc',
+        'base/decrypt_config.h',
+        'base/decryptor.h',
+        'base/decryptor_client.h',
+        'base/demuxer.cc',
+        'base/demuxer.h',
+        'base/demuxer_stream.cc',
+        'base/demuxer_stream.h',
+        'base/djb2.cc',
+        'base/djb2.h',
+        'base/filter_collection.cc',
+        'base/filter_collection.h',
+        'base/filter_host.h',
+        'base/filters.cc',
+        'base/filters.h',
+        'base/h264_bitstream_converter.cc',
+        'base/h264_bitstream_converter.h',
+        'base/media.h',
+        'base/media_android.cc',
+        'base/media_export.h',
+        'base/media_log.cc',
+        'base/media_log.h',
+        'base/media_log_event.h',
+        'base/media_posix.cc',
+        'base/media_switches.cc',
+        'base/media_switches.h',
+        'base/media_win.cc',
+        'base/message_loop_factory.cc',
+        'base/message_loop_factory.h',
+        'base/pipeline.cc',
+        'base/pipeline.h',
+        'base/pipeline_status.cc',
+        'base/pipeline_status.h',
+        'base/ranges.cc',
+        'base/ranges.h',
+        'base/seekable_buffer.cc',
+        'base/seekable_buffer.h',
+        'base/state_matrix.cc',
+        'base/state_matrix.h',
+        'base/stream_parser.cc',
+        'base/stream_parser.h',
+        'base/stream_parser_buffer.cc',
+        'base/stream_parser_buffer.h',
+        'base/video_decoder.cc',
+        'base/video_decoder.h',
+        'base/video_decoder_config.cc',
+        'base/video_decoder_config.h',
+        'base/video_frame.cc',
+        'base/video_frame.h',
+        'base/video_renderer.h',
+        'base/video_util.cc',
+        'base/video_util.h',
+        'crypto/aes_decryptor.cc',
+        'crypto/aes_decryptor.h',
+        'ffmpeg/ffmpeg_common.cc',
+        'ffmpeg/ffmpeg_common.h',
+        'ffmpeg/file_protocol.cc',
+        'ffmpeg/file_protocol.h',
+        'filters/audio_file_reader.cc',
+        'filters/audio_file_reader.h',
+        'filters/audio_renderer_algorithm.cc',
+        'filters/audio_renderer_algorithm.h',
+        'filters/audio_renderer_impl.cc',
+        'filters/audio_renderer_impl.h',
+        'filters/bitstream_converter.cc',
+        'filters/bitstream_converter.h',
+        'filters/chunk_demuxer.cc',
+        'filters/chunk_demuxer.h',
+        'filters/chunk_demuxer_client.h',
+        'filters/dummy_demuxer.cc',
+        'filters/dummy_demuxer.h',
+        'filters/ffmpeg_audio_decoder.cc',
+        'filters/ffmpeg_audio_decoder.h',
+        'filters/ffmpeg_demuxer.cc',
+        'filters/ffmpeg_demuxer.h',
+        'filters/ffmpeg_h264_bitstream_converter.cc',
+        'filters/ffmpeg_h264_bitstream_converter.h',
+        'filters/ffmpeg_glue.cc',
+        'filters/ffmpeg_glue.h',
+        'filters/ffmpeg_video_decoder.cc',
+        'filters/ffmpeg_video_decoder.h',
+        'filters/file_data_source.cc',
+        'filters/file_data_source.h',
+        'filters/gpu_video_decoder.cc',
+        'filters/gpu_video_decoder.h',
+        'filters/in_memory_url_protocol.cc',
+        'filters/in_memory_url_protocol.h',
+        'filters/source_buffer_stream.cc',
+        'filters/source_buffer_stream.h',
+        'filters/video_frame_generator.cc',
+        'filters/video_frame_generator.h',
+        'filters/video_renderer_base.cc',
+        'filters/video_renderer_base.h',
+        'video/capture/fake_video_capture_device.cc',
+        'video/capture/fake_video_capture_device.h',
+        'video/capture/linux/video_capture_device_linux.cc',
+        'video/capture/linux/video_capture_device_linux.h',
+        'video/capture/mac/video_capture_device_mac.h',
+        'video/capture/mac/video_capture_device_mac.mm',
+        'video/capture/mac/video_capture_device_qtkit_mac.h',
+        'video/capture/mac/video_capture_device_qtkit_mac.mm',
+        'video/capture/video_capture.h',
+        'video/capture/video_capture_device.h',
+        'video/capture/video_capture_device_dummy.cc',
+        'video/capture/video_capture_device_dummy.h',
+        'video/capture/video_capture_proxy.cc',
+        'video/capture/video_capture_proxy.h',
+        'video/capture/video_capture_types.h',
+        'video/capture/win/filter_base_win.cc',
+        'video/capture/win/filter_base_win.h',
+        'video/capture/win/pin_base_win.cc',
+        'video/capture/win/pin_base_win.h',
+        'video/capture/win/sink_filter_observer_win.h',
+        'video/capture/win/sink_filter_win.cc',
+        'video/capture/win/sink_filter_win.h',
+        'video/capture/win/sink_input_pin_win.cc',
+        'video/capture/win/sink_input_pin_win.h',
+        'video/capture/win/video_capture_device_win.cc',
+        'video/capture/win/video_capture_device_win.h',
+        'video/picture.cc',
+        'video/picture.h',
+        'video/video_decode_accelerator.cc',
+        'video/video_decode_accelerator.h',
+        'webm/webm_constants.h',
+        'webm/webm_cluster_parser.cc',
+        'webm/webm_cluster_parser.h',
+        'webm/webm_content_encodings.cc',
+        'webm/webm_content_encodings.h',
+        'webm/webm_content_encodings_client.cc',
+        'webm/webm_content_encodings_client.h',
+        'webm/webm_info_parser.cc',
+        'webm/webm_info_parser.h',
+        'webm/webm_parser.cc',
+        'webm/webm_parser.h',
+        'webm/webm_stream_parser.cc',
+        'webm/webm_stream_parser.h',
+        'webm/webm_tracks_parser.cc',
+        'webm/webm_tracks_parser.h',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '..',
+        ],
+      },
+      'conditions': [
+        # Android doesn't use ffmpeg, so make the dependency conditional
+        # and exclude the sources which depend on ffmpeg.
+        ['OS != "android"', {
+          'dependencies': [
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+        }],
+        ['OS == "android"', {
+          'sources!': [
+            'base/media_posix.cc',
+            'ffmpeg/ffmpeg_common.cc',
+            'ffmpeg/ffmpeg_common.h',
+            'ffmpeg/file_protocol.cc',
+            'ffmpeg/file_protocol.h',
+            'filters/audio_file_reader.cc',
+            'filters/audio_file_reader.h',
+            'filters/bitstream_converter.cc',
+            'filters/bitstream_converter.h',
+            'filters/chunk_demuxer.cc',
+            'filters/chunk_demuxer.h',
+            'filters/chunk_demuxer_client.h',
+            'filters/ffmpeg_audio_decoder.cc',
+            'filters/ffmpeg_audio_decoder.h',
+            'filters/ffmpeg_demuxer.cc',
+            'filters/ffmpeg_demuxer.h',
+            'filters/ffmpeg_h264_bitstream_converter.cc',
+            'filters/ffmpeg_h264_bitstream_converter.h',
+            'filters/ffmpeg_glue.cc',
+            'filters/ffmpeg_glue.h',
+            'filters/ffmpeg_video_decoder.cc',
+            'filters/ffmpeg_video_decoder.h',
+            'filters/gpu_video_decoder.cc',
+            'filters/gpu_video_decoder.h',
+            'webm/webm_cluster_parser.cc',
+            'webm/webm_cluster_parser.h',
+            'webm/webm_stream_parser.cc',
+            'webm/webm_stream_parser.h',
+          ],
+        }],
+        # The below 'android' condition were added temporarily and should be
+        # removed in downstream, because there is no Java environment setup in
+        # upstream yet.
+        ['OS == "android"', {
+          'sources!':[
+            'audio/android/audio_track_output_android.cc',
+          ],
+          'sources':[
+            'audio/android/audio_track_output_stub_android.cc',
+          ],
+          'link_settings': {
+            'libraries': [
+              '-lOpenSLES',
+            ],
+          },
+        }],
+        ['OS=="linux" or OS=="freebsd" or OS=="solaris"', {
+          'link_settings': {
+            'libraries': [
+              '-lasound',
+            ],
+          },
+        }],
+        ['OS=="openbsd"', {
+          'sources/': [ ['exclude', '/alsa_' ],
+                        ['exclude', '/audio_manager_linux' ] ],
+          'link_settings': {
+            'libraries': [
+            ],
+          },
+        }],
+        ['OS!="openbsd"', {
+          'sources!': [
+            'audio/openbsd/audio_manager_openbsd.cc',
+            'audio/openbsd/audio_manager_openbsd.h',
+          ],
+        }],
+        ['OS=="linux"', {
+          'variables': {
+            'conditions': [
+              ['sysroot!=""', {
+                'pkg-config': '../build/linux/pkg-config-wrapper "<(sysroot)" "<(target_arch)"',
+              }, {
+                'pkg-config': 'pkg-config'
+              }],
+            ],
+          },
+          'conditions': [
+            ['use_cras == 1', {
+              'cflags': [
+                '<!@(<(pkg-config) --cflags libcras)',
+              ],
+              'link_settings': {
+                'libraries': [
+                  '<!@(<(pkg-config) --libs libcras)',
+                ],
+              },
+              'defines': [
+                'USE_CRAS',
+              ],
+            }, {  # else: use_cras == 0
+              'sources!': [
+                'audio/linux/cras_output.cc',
+                'audio/linux/cras_output.h',
+              ],
+            }],
+          ],
+        }],
+        ['os_posix == 1', {
+          'conditions': [
+            ['use_pulseaudio == 1', {
+              'cflags': [
+                '<!@(pkg-config --cflags libpulse)',
+              ],
+              'link_settings': {
+                'libraries': [
+                  '<!@(pkg-config --libs-only-l libpulse)',
+                ],
+              },
+              'defines': [
+                'USE_PULSEAUDIO',
+              ],
+            }, {  # else: use_pulseaudio == 0
+              'sources!': [
+                'audio/pulse/pulse_output.cc',
+                'audio/pulse/pulse_output.h',
+              ],
+            }],
+          ],
+        }],
+        ['os_posix == 1 and OS != "android"', {
+          # Video capture isn't supported in Android yet.
+          'sources!': [
+            'video/capture/video_capture_device_dummy.cc',
+            'video/capture/video_capture_device_dummy.h',
+          ],
+        }],
+        ['OS=="mac"', {
+          'link_settings': {
+            'libraries': [
+              '$(SDKROOT)/System/Library/Frameworks/AudioUnit.framework',
+              '$(SDKROOT)/System/Library/Frameworks/AudioToolbox.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreAudio.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreVideo.framework',
+              '$(SDKROOT)/System/Library/Frameworks/QTKit.framework',
+            ],
+          },
+        }],
+        ['OS=="win"', {
+          'sources!': [
+            'audio/pulse/pulse_output.cc',
+            'audio/pulse/pulse_output.h',
+            'video/capture/video_capture_device_dummy.cc',
+            'video/capture/video_capture_device_dummy.h',
+          ],
+        }],
+        ['proprietary_codecs==1 or branding=="Chrome"', {
+          'sources': [
+            'mp4/avc.cc',
+            'mp4/avc.h',
+            'mp4/box_definitions.cc',
+            'mp4/box_definitions.h',
+            'mp4/box_reader.cc',
+            'mp4/box_reader.h',
+            'mp4/cenc.cc',
+            'mp4/cenc.h',
+            'mp4/mp4_stream_parser.cc',
+            'mp4/mp4_stream_parser.h',
+            'mp4/offset_byte_queue.cc',
+            'mp4/offset_byte_queue.h',
+            'mp4/track_run_iterator.cc',
+            'mp4/track_run_iterator.h',
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'yuv_convert',
+      'type': 'static_library',
+      'include_dirs': [
+        '..',
+      ],
+      'conditions': [
+        ['order_profiling != 0', {
+          'target_conditions' : [
+            ['_toolset=="target"', {
+              'cflags!': [ '-finstrument-functions' ],
+            }],
+          ],
+        }],
+        [ 'target_arch == "ia32" or target_arch == "x64"', {
+          'dependencies': [
+            'yuv_convert_simd_x86',
+          ],
+        }],
+        [ 'target_arch == "arm"', {
+          'dependencies': [
+            'yuv_convert_simd_arm',
+          ],
+        }],
+      ],
+      'sources': [
+        'base/yuv_convert.cc',
+        'base/yuv_convert.h',
+      ],
+    },
+    {
+      'target_name': 'yuv_convert_simd_x86',
+      'type': 'static_library',
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'base/simd/convert_rgb_to_yuv_c.cc',
+        'base/simd/convert_rgb_to_yuv_sse2.cc',
+        'base/simd/convert_rgb_to_yuv_ssse3.asm',
+        'base/simd/convert_rgb_to_yuv_ssse3.cc',
+        'base/simd/convert_rgb_to_yuv_ssse3.inc',
+        'base/simd/convert_yuv_to_rgb_c.cc',
+        'base/simd/convert_yuv_to_rgb_x86.cc',
+        'base/simd/convert_yuv_to_rgb_mmx.asm',
+        'base/simd/convert_yuv_to_rgb_mmx.inc',
+        'base/simd/convert_yuv_to_rgb_sse.asm',
+        'base/simd/filter_yuv.h',
+        'base/simd/filter_yuv_c.cc',
+        'base/simd/filter_yuv_mmx.cc',
+        'base/simd/filter_yuv_sse2.cc',
+        'base/simd/linear_scale_yuv_to_rgb_mmx.asm',
+        'base/simd/linear_scale_yuv_to_rgb_mmx.inc',
+        'base/simd/linear_scale_yuv_to_rgb_sse.asm',
+        'base/simd/scale_yuv_to_rgb_mmx.asm',
+        'base/simd/scale_yuv_to_rgb_mmx.inc',
+        'base/simd/scale_yuv_to_rgb_sse.asm',
+        'base/simd/yuv_to_rgb_table.cc',
+        'base/simd/yuv_to_rgb_table.h',
+      ],
+      'conditions': [
+        ['order_profiling != 0', {
+          'target_conditions' : [
+            ['_toolset=="target"', {
+              'cflags!': [ '-finstrument-functions' ],
+            }],
+          ],
+        }],
+        [ 'target_arch == "x64"', {
+          # Source files optimized for X64 systems.
+          'sources': [
+            'base/simd/linear_scale_yuv_to_rgb_mmx_x64.asm',
+            'base/simd/scale_yuv_to_rgb_sse2_x64.asm',
+          ],
+        }],
+        [ 'os_posix == 1 and OS != "mac" and OS != "android"', {
+          'cflags': [
+            '-msse2',
+          ],
+        }],
+        [ 'OS == "mac"', {
+          'configurations': {
+            'Debug': {
+              'xcode_settings': {
+                # gcc on the mac builds horribly unoptimized sse code in debug
+                # mode. Since this is rarely going to be debugged, run with full
+                # optimizations in Debug as well as Release.
+                'GCC_OPTIMIZATION_LEVEL': '3',  # -O3
+               },
+             },
+          },
+        }],
+        [ 'OS=="win"', {
+          'variables': {
+            'yasm_flags': [
+              '-DWIN32',
+              '-DMSVC',
+              '-DCHROMIUM',
+              '-Isimd',
+            ],
+          },
+        }],
+        [ 'OS=="mac"', {
+          'variables': {
+            'yasm_flags': [
+              '-DPREFIX',
+              '-DMACHO',
+              '-DCHROMIUM',
+              '-Isimd',
+            ],
+          },
+        }],
+        [ 'os_posix==1 and OS!="mac"', {
+          'variables': {
+            'conditions': [
+              [ 'target_arch=="ia32"', {
+                'yasm_flags': [
+                  '-DX86_32',
+                  '-DELF',
+                  '-DCHROMIUM',
+                  '-Isimd',
+                ],
+              }, {
+                'yasm_flags': [
+                  '-DARCH_X86_64',
+                  '-DELF',
+                  '-DPIC',
+                  '-DCHROMIUM',
+                  '-Isimd',
+                ],
+              }],
+            ],
+          },
+        }],
+      ],
+      'variables': {
+        'yasm_output_path': '<(SHARED_INTERMEDIATE_DIR)/media',
+      },
+      'msvs_2010_disable_uldi_when_referenced': 1,
+      'includes': [
+        '../third_party/yasm/yasm_compile.gypi',
+      ],
+    },
+    {
+      'target_name': 'yuv_convert_simd_arm',
+      'type': 'static_library',
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'base/simd/convert_rgb_to_yuv_c.cc',
+        'base/simd/convert_rgb_to_yuv.h',
+        'base/simd/convert_yuv_to_rgb_c.cc',
+        'base/simd/convert_yuv_to_rgb.h',
+        'base/simd/filter_yuv.h',
+        'base/simd/filter_yuv_c.cc',
+        'base/simd/yuv_to_rgb_table.cc',
+        'base/simd/yuv_to_rgb_table.h',
+      ],
+    },
+    {
+      'target_name': 'media_unittests',
+      'type': 'executable',
+      'dependencies': [
+        'media',
+        'media_test_support',
+        'yuv_convert',
+        '../base/base.gyp:base',
+        '../base/base.gyp:base_i18n',
+        '../base/base.gyp:test_support_base',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        '../ui/ui.gyp:ui',
+      ],
+      'sources': [
+        'audio/async_socket_io_handler_unittest.cc',
+        'audio/audio_input_controller_unittest.cc',
+        'audio/audio_input_device_unittest.cc',
+        'audio/audio_input_unittest.cc',
+        'audio/audio_input_volume_unittest.cc',
+        'audio/audio_low_latency_input_output_unittest.cc',
+        'audio/audio_output_controller_unittest.cc',
+        'audio/audio_output_proxy_unittest.cc',
+        'audio/audio_parameters_unittest.cc',
+        'audio/audio_util_unittest.cc',
+        'audio/cross_process_notification_unittest.cc',
+        'audio/linux/alsa_output_unittest.cc',
+        'audio/mac/audio_low_latency_input_mac_unittest.cc',
+        'audio/mac/audio_output_mac_unittest.cc',
+        'audio/simple_sources_unittest.cc',
+        'audio/win/audio_low_latency_input_win_unittest.cc',
+        'audio/win/audio_low_latency_output_win_unittest.cc',
+        'audio/win/audio_output_win_unittest.cc',
+        'base/audio_renderer_mixer_unittest.cc',
+        'base/audio_renderer_mixer_input_unittest.cc',
+        'base/buffers_unittest.cc',
+        'base/clock_unittest.cc',
+        'base/composite_filter_unittest.cc',
+        'base/data_buffer_unittest.cc',
+        'base/decoder_buffer_unittest.cc',
+        'base/djb2_unittest.cc',
+        'base/fake_audio_render_callback.cc',
+        'base/fake_audio_render_callback.h',
+        'base/filter_collection_unittest.cc',
+        'base/h264_bitstream_converter_unittest.cc',
+        'base/pipeline_unittest.cc',
+        'base/ranges_unittest.cc',
+        'base/run_all_unittests.cc',
+        'base/seekable_buffer_unittest.cc',
+        'base/state_matrix_unittest.cc',
+        'base/test_data_util.cc',
+        'base/test_data_util.h',
+        'base/video_frame_unittest.cc',
+        'base/video_util_unittest.cc',
+        'base/yuv_convert_unittest.cc',
+        'crypto/aes_decryptor_unittest.cc',
+        'ffmpeg/ffmpeg_common_unittest.cc',
+        'filters/audio_renderer_algorithm_unittest.cc',
+        'filters/audio_renderer_impl_unittest.cc',
+        'filters/bitstream_converter_unittest.cc',
+        'filters/chunk_demuxer_unittest.cc',
+        'filters/ffmpeg_audio_decoder_unittest.cc',
+        'filters/ffmpeg_decoder_unittest.h',
+        'filters/ffmpeg_demuxer_unittest.cc',
+        'filters/ffmpeg_glue_unittest.cc',
+        'filters/ffmpeg_h264_bitstream_converter_unittest.cc',
+        'filters/ffmpeg_video_decoder_unittest.cc',
+        'filters/file_data_source_unittest.cc',
+        'filters/pipeline_integration_test.cc',
+        'filters/pipeline_integration_test_base.cc',
+        'filters/source_buffer_stream_unittest.cc',
+        'filters/video_renderer_base_unittest.cc',
+        'video/capture/video_capture_device_unittest.cc',
+        'webm/cluster_builder.cc',
+        'webm/cluster_builder.h',
+        'webm/webm_cluster_parser_unittest.cc',
+        'webm/webm_content_encodings_client_unittest.cc',
+        'webm/webm_parser_unittest.cc',
+      ],
+      'conditions': [
+        ['os_posix==1 and OS!="mac"', {
+          'conditions': [
+            ['linux_use_tcmalloc==1', {
+              'dependencies': [
+                '../base/allocator/allocator.gyp:allocator',
+              ],
+            }],
+          ],
+        }],
+        ['OS != "android"', {
+          'dependencies': [
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+        }],
+        ['OS == "android"', {
+          'sources!': [
+            'audio/audio_input_volume_unittest.cc',
+            'base/test_data_util.cc',
+            'base/test_data_util.h',
+            'ffmpeg/ffmpeg_common_unittest.cc',
+            'filters/ffmpeg_audio_decoder_unittest.cc',
+            'filters/bitstream_converter_unittest.cc',
+            'filters/chunk_demuxer_unittest.cc',
+            'filters/ffmpeg_demuxer_unittest.cc',
+            'filters/ffmpeg_glue_unittest.cc',
+            'filters/ffmpeg_h264_bitstream_converter_unittest.cc',
+            'filters/ffmpeg_video_decoder_unittest.cc',
+            'filters/pipeline_integration_test.cc',
+            'filters/pipeline_integration_test_base.cc',
+            'mp4/mp4_stream_parser_unittest.cc',
+            'webm/webm_cluster_parser_unittest.cc',
+          ],
+        }],
+        ['OS == "linux"', {
+          'conditions': [
+            ['use_cras == 1', {
+              'sources': [
+                'audio/linux/cras_output_unittest.cc',
+              ],
+              'defines': [
+                'USE_CRAS',
+              ],
+            }],
+          ],
+        }],
+        [ 'target_arch=="ia32" or target_arch=="x64"', {
+          'sources': [
+            'base/simd/convert_rgb_to_yuv_unittest.cc',
+          ],
+        }],
+        ['proprietary_codecs==1 or branding=="Chrome"', {
+          'sources': [
+            'mp4/avc_unittest.cc',
+            'mp4/box_reader_unittest.cc',
+            'mp4/mp4_stream_parser_unittest.cc',
+            'mp4/offset_byte_queue_unittest.cc',
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'media_test_support',
+      'type': 'static_library',
+      'dependencies': [
+        'media',
+        '../base/base.gyp:base',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'audio/test_audio_input_controller_factory.cc',
+        'audio/test_audio_input_controller_factory.h',
+        'base/mock_callback.cc',
+        'base/mock_callback.h',
+        'base/mock_data_source_host.cc',
+        'base/mock_data_source_host.h',
+        'base/mock_demuxer_host.cc',
+        'base/mock_demuxer_host.h',
+        'base/mock_filter_host.cc',
+        'base/mock_filter_host.h',
+        'base/mock_filters.cc',
+        'base/mock_filters.h',
+      ],
+    },
+    {
+      'target_name': 'scaler_bench',
+      'type': 'executable',
+      'dependencies': [
+        'media',
+        'yuv_convert',
+        '../base/base.gyp:base',
+        '../skia/skia.gyp:skia',
+      ],
+      'sources': [
+        'tools/scaler_bench/scaler_bench.cc',
+      ],
+    },
+    {
+      'target_name': 'qt_faststart',
+      'type': 'executable',
+      'sources': [
+        'tools/qt_faststart/qt_faststart.c'
+      ],
+    },
+    {
+      'target_name': 'seek_tester',
+      'type': 'executable',
+      'dependencies': [
+        'media',
+        '../base/base.gyp:base',
+      ],
+      'sources': [
+        'tools/seek_tester/seek_tester.cc',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="win"', {
+      'targets': [
+        {
+          'target_name': 'player_wtl',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            'yuv_convert',
+            '../base/base.gyp:base',
+            '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+            '../ui/ui.gyp:ui',
+          ],
+          'include_dirs': [
+            '<(DEPTH)/third_party/wtl/include',
+          ],
+          'sources': [
+            'tools/player_wtl/list.h',
+            'tools/player_wtl/mainfrm.h',
+            'tools/player_wtl/movie.cc',
+            'tools/player_wtl/movie.h',
+            'tools/player_wtl/player_wtl.cc',
+            'tools/player_wtl/player_wtl.rc',
+            'tools/player_wtl/props.h',
+            'tools/player_wtl/seek.h',
+            'tools/player_wtl/resource.h',
+            'tools/player_wtl/view.h',
+          ],
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+            },
+          },
+          'defines': [
+            '_CRT_SECURE_NO_WARNINGS=1',
+          ],
+        },
+      ],
+    }],
+    ['OS == "win" or toolkit_uses_gtk == 1', {
+      'targets': [
+        {
+          'target_name': 'shader_bench',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            'yuv_convert',
+            '../base/base.gyp:base',
+            '../ui/gl/gl.gyp:gl',
+          ],
+          'sources': [
+            'tools/shader_bench/shader_bench.cc',
+            'tools/shader_bench/cpu_color_painter.cc',
+            'tools/shader_bench/cpu_color_painter.h',
+            'tools/shader_bench/gpu_color_painter.cc',
+            'tools/shader_bench/gpu_color_painter.h',
+            'tools/shader_bench/gpu_painter.cc',
+            'tools/shader_bench/gpu_painter.h',
+            'tools/shader_bench/painter.cc',
+            'tools/shader_bench/painter.h',
+            'tools/shader_bench/window.cc',
+            'tools/shader_bench/window.h',
+          ],
+          'conditions': [
+            ['toolkit_uses_gtk == 1', {
+              'dependencies': [
+                '../build/linux/system.gyp:gtk',
+              ],
+              'sources': [
+                'tools/shader_bench/window_linux.cc',
+              ],
+            }],
+            ['OS=="win"', {
+              'dependencies': [
+                '../third_party/angle/src/build_angle.gyp:libEGL',
+                '../third_party/angle/src/build_angle.gyp:libGLESv2',
+              ],
+              'sources': [
+                'tools/shader_bench/window_win.cc',
+              ],
+            }],
+          ],
+        },
+      ],
+    }],
+    ['OS == "linux" and target_arch != "arm"', {
+      'targets': [
+        {
+          'target_name': 'tile_render_bench',
+          'type': 'executable',
+          'dependencies': [
+            '../base/base.gyp:base',
+            '../ui/gl/gl.gyp:gl',
+          ],
+          'libraries': [
+            '-lGL',
+            '-ldl',
+          ],
+          'sources': [
+            'tools/tile_render_bench/tile_render_bench.cc',
+          ],
+        },
+      ],
+    }],
+    ['os_posix == 1 and OS != "mac" and OS != "android"', {
+      'targets': [
+        {
+          'target_name': 'player_x11',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            'yuv_convert',
+            '../base/base.gyp:base',
+            '../ui/gl/gl.gyp:gl',
+          ],
+          'link_settings': {
+            'libraries': [
+              '-ldl',
+              '-lX11',
+              '-lXrender',
+              '-lXext',
+            ],
+          },
+          'sources': [
+            'tools/player_x11/data_source_logger.cc',
+            'tools/player_x11/data_source_logger.h',
+            'tools/player_x11/gl_video_renderer.cc',
+            'tools/player_x11/gl_video_renderer.h',
+            'tools/player_x11/player_x11.cc',
+            'tools/player_x11/x11_video_renderer.cc',
+            'tools/player_x11/x11_video_renderer.h',
+          ],
+        },
+      ],
+    }],
+    ['OS == "android"', {
+      'targets': [
+        {
+          'target_name': 'player_android',
+          'type': 'static_library',
+          'sources': [
+            'base/android/media_player_bridge.cc',
+            'base/android/media_player_bridge.h',
+          ],
+          'dependencies': [
+            '../base/base.gyp:base',
+          ],
+          'include_dirs': [
+            '<(SHARED_INTERMEDIATE_DIR)/media',
+          ],
+          'actions': [
+            {
+              'action_name': 'generate-jni-headers',
+              'inputs': [
+                '../base/android/jni_generator/jni_generator.py',
+                'base/android/java/src/org/chromium/media/MediaPlayerListener.java',
+              ],
+              'outputs': [
+                '<(SHARED_INTERMEDIATE_DIR)/media/jni/media_player_listener_jni.h',
+              ],
+              'action': [
+                'python',
+                '<(DEPTH)/base/android/jni_generator/jni_generator.py',
+                '-o',
+                '<@(_inputs)',
+                '<@(_outputs)',
+              ],
+            },
+          ],
+        },
+        {
+          'target_name': 'media_java',
+          'type': 'none',
+          'dependencies': [ '../base/base.gyp:base_java' ],
+          'variables': {
+            'package_name': 'media',
+            'java_in_dir': 'base/android/java',
+          },
+          'includes': [ '../build/java.gypi' ],
+        },
+
+      ],
+    }, { # OS != "android"'
+      # Android does not use ffmpeg, so disable the targets which require it.
+      'targets': [
+        {
+          'target_name': 'ffmpeg_unittests',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            'media_test_support',
+            '../base/base.gyp:base',
+            '../base/base.gyp:base_i18n',
+            '../base/base.gyp:test_support_base',
+            '../base/base.gyp:test_support_perf',
+            '../testing/gtest.gyp:gtest',
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+          'sources': [
+            'ffmpeg/ffmpeg_unittest.cc',
+          ],
+          'conditions': [
+            ['toolkit_uses_gtk == 1', {
+              'dependencies': [
+                # Needed for the following #include chain:
+                #   base/run_all_unittests.cc
+                #   ../base/test_suite.h
+                #   gtk/gtk.h
+                '../build/linux/system.gyp:gtk',
+              ],
+              'conditions': [
+                ['linux_use_tcmalloc==1', {
+                  'dependencies': [
+                    '../base/allocator/allocator.gyp:allocator',
+                  ],
+                }],
+              ],
+            }],
+          ],
+        },
+        {
+          'target_name': 'ffmpeg_regression_tests',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            'media_test_support',
+            '../base/base.gyp:test_support_base',
+            '../testing/gmock.gyp:gmock',
+            '../testing/gtest.gyp:gtest',
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+          'sources': [
+            'base/test_data_util.cc',
+            'base/run_all_unittests.cc',
+            'ffmpeg/ffmpeg_regression_tests.cc',
+            'filters/pipeline_integration_test_base.cc',
+          ],
+          'conditions': [
+            ['os_posix==1 and OS!="mac"', {
+              'conditions': [
+                ['linux_use_tcmalloc==1', {
+                  'dependencies': [
+                    '../base/allocator/allocator.gyp:allocator',
+                  ],
+                }],
+              ],
+            }],
+          ],
+        },
+        {
+          'target_name': 'ffmpeg_tests',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            '../base/base.gyp:base',
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+          'sources': [
+            'test/ffmpeg_tests/ffmpeg_tests.cc',
+          ],
+        },
+        {
+          'target_name': 'media_bench',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            '../base/base.gyp:base',
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+          'sources': [
+            'tools/media_bench/media_bench.cc',
+          ],
+        },
+      ],
+    }]
+  ],
+}
diff --git a/gyp/tools/emacs/testdata/media.gyp.fontified b/gyp/tools/emacs/testdata/media.gyp.fontified
new file mode 100644 (file)
index 0000000..962b7b2
--- /dev/null
@@ -0,0 +1,1107 @@
+
+#("# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+    # Override to dynamically link the PulseAudio library.
+    'use_pulseaudio%': 0,
+    # Override to dynamically link the cras (ChromeOS audio) library.
+    'use_cras%': 0,
+  },
+  'targets': [
+    {
+      'target_name': 'media',
+      'type': '<(component)',
+      'dependencies': [
+        'yuv_convert',
+        '../base/base.gyp:base',
+        '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '../build/temp_gyp/googleurl.gyp:googleurl',
+        '../crypto/crypto.gyp:crypto',
+        '../third_party/openmax/openmax.gyp:il',
+        '../ui/ui.gyp:ui',
+      ],
+      'defines': [
+        'MEDIA_IMPLEMENTATION',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'audio/android/audio_manager_android.cc',
+        'audio/android/audio_manager_android.h',
+        'audio/android/audio_track_output_android.cc',
+        'audio/android/audio_track_output_android.h',
+        'audio/android/opensles_input.cc',
+        'audio/android/opensles_input.h',
+        'audio/android/opensles_output.cc',
+        'audio/android/opensles_output.h',
+        'audio/async_socket_io_handler.h',
+        'audio/async_socket_io_handler_posix.cc',
+        'audio/async_socket_io_handler_win.cc',
+        'audio/audio_buffers_state.cc',
+        'audio/audio_buffers_state.h',
+        'audio/audio_io.h',
+        'audio/audio_input_controller.cc',
+        'audio/audio_input_controller.h',
+        'audio/audio_input_stream_impl.cc',
+        'audio/audio_input_stream_impl.h',
+        'audio/audio_device_name.cc',
+        'audio/audio_device_name.h',
+        'audio/audio_manager.cc',
+        'audio/audio_manager.h',
+        'audio/audio_manager_base.cc',
+        'audio/audio_manager_base.h',
+        'audio/audio_output_controller.cc',
+        'audio/audio_output_controller.h',
+        'audio/audio_output_dispatcher.cc',
+        'audio/audio_output_dispatcher.h',
+        'audio/audio_output_dispatcher_impl.cc',
+        'audio/audio_output_dispatcher_impl.h',
+        'audio/audio_output_mixer.cc',
+        'audio/audio_output_mixer.h',
+        'audio/audio_output_proxy.cc',
+        'audio/audio_output_proxy.h',
+        'audio/audio_parameters.cc',
+        'audio/audio_parameters.h',
+        'audio/audio_util.cc',
+        'audio/audio_util.h',
+        'audio/cross_process_notification.cc',
+        'audio/cross_process_notification.h',
+        'audio/cross_process_notification_win.cc',
+        'audio/cross_process_notification_posix.cc',
+        'audio/fake_audio_input_stream.cc',
+        'audio/fake_audio_input_stream.h',
+        'audio/fake_audio_output_stream.cc',
+        'audio/fake_audio_output_stream.h',
+        'audio/linux/audio_manager_linux.cc',
+        'audio/linux/audio_manager_linux.h',
+        'audio/linux/alsa_input.cc',
+        'audio/linux/alsa_input.h',
+        'audio/linux/alsa_output.cc',
+        'audio/linux/alsa_output.h',
+        'audio/linux/alsa_util.cc',
+        'audio/linux/alsa_util.h',
+        'audio/linux/alsa_wrapper.cc',
+        'audio/linux/alsa_wrapper.h',
+        'audio/linux/cras_output.cc',
+        'audio/linux/cras_output.h',
+        'audio/openbsd/audio_manager_openbsd.cc',
+        'audio/openbsd/audio_manager_openbsd.h',
+        'audio/mac/audio_input_mac.cc',
+        'audio/mac/audio_input_mac.h',
+        'audio/mac/audio_low_latency_input_mac.cc',
+        'audio/mac/audio_low_latency_input_mac.h',
+        'audio/mac/audio_low_latency_output_mac.cc',
+        'audio/mac/audio_low_latency_output_mac.h',
+        'audio/mac/audio_manager_mac.cc',
+        'audio/mac/audio_manager_mac.h',
+        'audio/mac/audio_output_mac.cc',
+        'audio/mac/audio_output_mac.h',
+        'audio/null_audio_sink.cc',
+        'audio/null_audio_sink.h',
+        'audio/pulse/pulse_output.cc',
+        'audio/pulse/pulse_output.h',
+        'audio/sample_rates.cc',
+        'audio/sample_rates.h',
+        'audio/simple_sources.cc',
+        'audio/simple_sources.h',
+        'audio/win/audio_low_latency_input_win.cc',
+        'audio/win/audio_low_latency_input_win.h',
+        'audio/win/audio_low_latency_output_win.cc',
+        'audio/win/audio_low_latency_output_win.h',
+        'audio/win/audio_manager_win.cc',
+        'audio/win/audio_manager_win.h',
+        'audio/win/avrt_wrapper_win.cc',
+        'audio/win/avrt_wrapper_win.h',
+        'audio/win/device_enumeration_win.cc',
+        'audio/win/device_enumeration_win.h',
+        'audio/win/wavein_input_win.cc',
+        'audio/win/wavein_input_win.h',
+        'audio/win/waveout_output_win.cc',
+        'audio/win/waveout_output_win.h',
+        'base/android/media_jni_registrar.cc',
+        'base/android/media_jni_registrar.h',
+        'base/audio_decoder.cc',
+        'base/audio_decoder.h',
+        'base/audio_decoder_config.cc',
+        'base/audio_decoder_config.h',
+        'base/audio_renderer.h',
+        'base/audio_renderer_mixer.cc',
+        'base/audio_renderer_mixer.h',
+        'base/audio_renderer_mixer_input.cc',
+        'base/audio_renderer_mixer_input.h',
+        'base/bitstream_buffer.h',
+        'base/buffers.cc',
+        'base/buffers.h',
+        'base/byte_queue.cc',
+        'base/byte_queue.h',
+        'base/channel_layout.cc',
+        'base/channel_layout.h',
+        'base/clock.cc',
+        'base/clock.h',
+        'base/composite_filter.cc',
+        'base/composite_filter.h',
+        'base/data_buffer.cc',
+        'base/data_buffer.h',
+        'base/data_source.cc',
+        'base/data_source.h',
+        'base/decoder_buffer.cc',
+        'base/decoder_buffer.h',
+        'base/decrypt_config.cc',
+        'base/decrypt_config.h',
+        'base/decryptor.h',
+        'base/decryptor_client.h',
+        'base/demuxer.cc',
+        'base/demuxer.h',
+        'base/demuxer_stream.cc',
+        'base/demuxer_stream.h',
+        'base/djb2.cc',
+        'base/djb2.h',
+        'base/filter_collection.cc',
+        'base/filter_collection.h',
+        'base/filter_host.h',
+        'base/filters.cc',
+        'base/filters.h',
+        'base/h264_bitstream_converter.cc',
+        'base/h264_bitstream_converter.h',
+        'base/media.h',
+        'base/media_android.cc',
+        'base/media_export.h',
+        'base/media_log.cc',
+        'base/media_log.h',
+        'base/media_log_event.h',
+        'base/media_posix.cc',
+        'base/media_switches.cc',
+        'base/media_switches.h',
+        'base/media_win.cc',
+        'base/message_loop_factory.cc',
+        'base/message_loop_factory.h',
+        'base/pipeline.cc',
+        'base/pipeline.h',
+        'base/pipeline_status.cc',
+        'base/pipeline_status.h',
+        'base/ranges.cc',
+        'base/ranges.h',
+        'base/seekable_buffer.cc',
+        'base/seekable_buffer.h',
+        'base/state_matrix.cc',
+        'base/state_matrix.h',
+        'base/stream_parser.cc',
+        'base/stream_parser.h',
+        'base/stream_parser_buffer.cc',
+        'base/stream_parser_buffer.h',
+        'base/video_decoder.cc',
+        'base/video_decoder.h',
+        'base/video_decoder_config.cc',
+        'base/video_decoder_config.h',
+        'base/video_frame.cc',
+        'base/video_frame.h',
+        'base/video_renderer.h',
+        'base/video_util.cc',
+        'base/video_util.h',
+        'crypto/aes_decryptor.cc',
+        'crypto/aes_decryptor.h',
+        'ffmpeg/ffmpeg_common.cc',
+        'ffmpeg/ffmpeg_common.h',
+        'ffmpeg/file_protocol.cc',
+        'ffmpeg/file_protocol.h',
+        'filters/audio_file_reader.cc',
+        'filters/audio_file_reader.h',
+        'filters/audio_renderer_algorithm.cc',
+        'filters/audio_renderer_algorithm.h',
+        'filters/audio_renderer_impl.cc',
+        'filters/audio_renderer_impl.h',
+        'filters/bitstream_converter.cc',
+        'filters/bitstream_converter.h',
+        'filters/chunk_demuxer.cc',
+        'filters/chunk_demuxer.h',
+        'filters/chunk_demuxer_client.h',
+        'filters/dummy_demuxer.cc',
+        'filters/dummy_demuxer.h',
+        'filters/ffmpeg_audio_decoder.cc',
+        'filters/ffmpeg_audio_decoder.h',
+        'filters/ffmpeg_demuxer.cc',
+        'filters/ffmpeg_demuxer.h',
+        'filters/ffmpeg_h264_bitstream_converter.cc',
+        'filters/ffmpeg_h264_bitstream_converter.h',
+        'filters/ffmpeg_glue.cc',
+        'filters/ffmpeg_glue.h',
+        'filters/ffmpeg_video_decoder.cc',
+        'filters/ffmpeg_video_decoder.h',
+        'filters/file_data_source.cc',
+        'filters/file_data_source.h',
+        'filters/gpu_video_decoder.cc',
+        'filters/gpu_video_decoder.h',
+        'filters/in_memory_url_protocol.cc',
+        'filters/in_memory_url_protocol.h',
+        'filters/source_buffer_stream.cc',
+        'filters/source_buffer_stream.h',
+        'filters/video_frame_generator.cc',
+        'filters/video_frame_generator.h',
+        'filters/video_renderer_base.cc',
+        'filters/video_renderer_base.h',
+        'video/capture/fake_video_capture_device.cc',
+        'video/capture/fake_video_capture_device.h',
+        'video/capture/linux/video_capture_device_linux.cc',
+        'video/capture/linux/video_capture_device_linux.h',
+        'video/capture/mac/video_capture_device_mac.h',
+        'video/capture/mac/video_capture_device_mac.mm',
+        'video/capture/mac/video_capture_device_qtkit_mac.h',
+        'video/capture/mac/video_capture_device_qtkit_mac.mm',
+        'video/capture/video_capture.h',
+        'video/capture/video_capture_device.h',
+        'video/capture/video_capture_device_dummy.cc',
+        'video/capture/video_capture_device_dummy.h',
+        'video/capture/video_capture_proxy.cc',
+        'video/capture/video_capture_proxy.h',
+        'video/capture/video_capture_types.h',
+        'video/capture/win/filter_base_win.cc',
+        'video/capture/win/filter_base_win.h',
+        'video/capture/win/pin_base_win.cc',
+        'video/capture/win/pin_base_win.h',
+        'video/capture/win/sink_filter_observer_win.h',
+        'video/capture/win/sink_filter_win.cc',
+        'video/capture/win/sink_filter_win.h',
+        'video/capture/win/sink_input_pin_win.cc',
+        'video/capture/win/sink_input_pin_win.h',
+        'video/capture/win/video_capture_device_win.cc',
+        'video/capture/win/video_capture_device_win.h',
+        'video/picture.cc',
+        'video/picture.h',
+        'video/video_decode_accelerator.cc',
+        'video/video_decode_accelerator.h',
+        'webm/webm_constants.h',
+        'webm/webm_cluster_parser.cc',
+        'webm/webm_cluster_parser.h',
+        'webm/webm_content_encodings.cc',
+        'webm/webm_content_encodings.h',
+        'webm/webm_content_encodings_client.cc',
+        'webm/webm_content_encodings_client.h',
+        'webm/webm_info_parser.cc',
+        'webm/webm_info_parser.h',
+        'webm/webm_parser.cc',
+        'webm/webm_parser.h',
+        'webm/webm_stream_parser.cc',
+        'webm/webm_stream_parser.h',
+        'webm/webm_tracks_parser.cc',
+        'webm/webm_tracks_parser.h',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '..',
+        ],
+      },
+      'conditions': [
+        # Android doesn't use ffmpeg, so make the dependency conditional
+        # and exclude the sources which depend on ffmpeg.
+        ['OS != \"android\"', {
+          'dependencies': [
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+        }],
+        ['OS == \"android\"', {
+          'sources!': [
+            'base/media_posix.cc',
+            'ffmpeg/ffmpeg_common.cc',
+            'ffmpeg/ffmpeg_common.h',
+            'ffmpeg/file_protocol.cc',
+            'ffmpeg/file_protocol.h',
+            'filters/audio_file_reader.cc',
+            'filters/audio_file_reader.h',
+            'filters/bitstream_converter.cc',
+            'filters/bitstream_converter.h',
+            'filters/chunk_demuxer.cc',
+            'filters/chunk_demuxer.h',
+            'filters/chunk_demuxer_client.h',
+            'filters/ffmpeg_audio_decoder.cc',
+            'filters/ffmpeg_audio_decoder.h',
+            'filters/ffmpeg_demuxer.cc',
+            'filters/ffmpeg_demuxer.h',
+            'filters/ffmpeg_h264_bitstream_converter.cc',
+            'filters/ffmpeg_h264_bitstream_converter.h',
+            'filters/ffmpeg_glue.cc',
+            'filters/ffmpeg_glue.h',
+            'filters/ffmpeg_video_decoder.cc',
+            'filters/ffmpeg_video_decoder.h',
+            'filters/gpu_video_decoder.cc',
+            'filters/gpu_video_decoder.h',
+            'webm/webm_cluster_parser.cc',
+            'webm/webm_cluster_parser.h',
+            'webm/webm_stream_parser.cc',
+            'webm/webm_stream_parser.h',
+          ],
+        }],
+        # The below 'android' condition were added temporarily and should be
+        # removed in downstream, because there is no Java environment setup in
+        # upstream yet.
+        ['OS == \"android\"', {
+          'sources!':[
+            'audio/android/audio_track_output_android.cc',
+          ],
+          'sources':[
+            'audio/android/audio_track_output_stub_android.cc',
+          ],
+          'link_settings': {
+            'libraries': [
+              '-lOpenSLES',
+            ],
+          },
+        }],
+        ['OS==\"linux\" or OS==\"freebsd\" or OS==\"solaris\"', {
+          'link_settings': {
+            'libraries': [
+              '-lasound',
+            ],
+          },
+        }],
+        ['OS==\"openbsd\"', {
+          'sources/': [ ['exclude', '/alsa_' ],
+                        ['exclude', '/audio_manager_linux' ] ],
+          'link_settings': {
+            'libraries': [
+            ],
+          },
+        }],
+        ['OS!=\"openbsd\"', {
+          'sources!': [
+            'audio/openbsd/audio_manager_openbsd.cc',
+            'audio/openbsd/audio_manager_openbsd.h',
+          ],
+        }],
+        ['OS==\"linux\"', {
+          'variables': {
+            'conditions': [
+              ['sysroot!=\"\"', {
+                'pkg-config': '../build/linux/pkg-config-wrapper \"<(sysroot)\" \"<(target_arch)\"',
+              }, {
+                'pkg-config': 'pkg-config'
+              }],
+            ],
+          },
+          'conditions': [
+            ['use_cras == 1', {
+              'cflags': [
+                '<!@(<(pkg-config) --cflags libcras)',
+              ],
+              'link_settings': {
+                'libraries': [
+                  '<!@(<(pkg-config) --libs libcras)',
+                ],
+              },
+              'defines': [
+                'USE_CRAS',
+              ],
+            }, {  # else: use_cras == 0
+              'sources!': [
+                'audio/linux/cras_output.cc',
+                'audio/linux/cras_output.h',
+              ],
+            }],
+          ],
+        }],
+        ['os_posix == 1', {
+          'conditions': [
+            ['use_pulseaudio == 1', {
+              'cflags': [
+                '<!@(pkg-config --cflags libpulse)',
+              ],
+              'link_settings': {
+                'libraries': [
+                  '<!@(pkg-config --libs-only-l libpulse)',
+                ],
+              },
+              'defines': [
+                'USE_PULSEAUDIO',
+              ],
+            }, {  # else: use_pulseaudio == 0
+              'sources!': [
+                'audio/pulse/pulse_output.cc',
+                'audio/pulse/pulse_output.h',
+              ],
+            }],
+          ],
+        }],
+        ['os_posix == 1 and OS != \"android\"', {
+          # Video capture isn't supported in Android yet.
+          'sources!': [
+            'video/capture/video_capture_device_dummy.cc',
+            'video/capture/video_capture_device_dummy.h',
+          ],
+        }],
+        ['OS==\"mac\"', {
+          'link_settings': {
+            'libraries': [
+              '$(SDKROOT)/System/Library/Frameworks/AudioUnit.framework',
+              '$(SDKROOT)/System/Library/Frameworks/AudioToolbox.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreAudio.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreVideo.framework',
+              '$(SDKROOT)/System/Library/Frameworks/QTKit.framework',
+            ],
+          },
+        }],
+        ['OS==\"win\"', {
+          'sources!': [
+            'audio/pulse/pulse_output.cc',
+            'audio/pulse/pulse_output.h',
+            'video/capture/video_capture_device_dummy.cc',
+            'video/capture/video_capture_device_dummy.h',
+          ],
+        }],
+        ['proprietary_codecs==1 or branding==\"Chrome\"', {
+          'sources': [
+            'mp4/avc.cc',
+            'mp4/avc.h',
+            'mp4/box_definitions.cc',
+            'mp4/box_definitions.h',
+            'mp4/box_reader.cc',
+            'mp4/box_reader.h',
+            'mp4/cenc.cc',
+            'mp4/cenc.h',
+            'mp4/mp4_stream_parser.cc',
+            'mp4/mp4_stream_parser.h',
+            'mp4/offset_byte_queue.cc',
+            'mp4/offset_byte_queue.h',
+            'mp4/track_run_iterator.cc',
+            'mp4/track_run_iterator.h',
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'yuv_convert',
+      'type': 'static_library',
+      'include_dirs': [
+        '..',
+      ],
+      'conditions': [
+        ['order_profiling != 0', {
+          'target_conditions' : [
+            ['_toolset==\"target\"', {
+              'cflags!': [ '-finstrument-functions' ],
+            }],
+          ],
+        }],
+        [ 'target_arch == \"ia32\" or target_arch == \"x64\"', {
+          'dependencies': [
+            'yuv_convert_simd_x86',
+          ],
+        }],
+        [ 'target_arch == \"arm\"', {
+          'dependencies': [
+            'yuv_convert_simd_arm',
+          ],
+        }],
+      ],
+      'sources': [
+        'base/yuv_convert.cc',
+        'base/yuv_convert.h',
+      ],
+    },
+    {
+      'target_name': 'yuv_convert_simd_x86',
+      'type': 'static_library',
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'base/simd/convert_rgb_to_yuv_c.cc',
+        'base/simd/convert_rgb_to_yuv_sse2.cc',
+        'base/simd/convert_rgb_to_yuv_ssse3.asm',
+        'base/simd/convert_rgb_to_yuv_ssse3.cc',
+        'base/simd/convert_rgb_to_yuv_ssse3.inc',
+        'base/simd/convert_yuv_to_rgb_c.cc',
+        'base/simd/convert_yuv_to_rgb_x86.cc',
+        'base/simd/convert_yuv_to_rgb_mmx.asm',
+        'base/simd/convert_yuv_to_rgb_mmx.inc',
+        'base/simd/convert_yuv_to_rgb_sse.asm',
+        'base/simd/filter_yuv.h',
+        'base/simd/filter_yuv_c.cc',
+        'base/simd/filter_yuv_mmx.cc',
+        'base/simd/filter_yuv_sse2.cc',
+        'base/simd/linear_scale_yuv_to_rgb_mmx.asm',
+        'base/simd/linear_scale_yuv_to_rgb_mmx.inc',
+        'base/simd/linear_scale_yuv_to_rgb_sse.asm',
+        'base/simd/scale_yuv_to_rgb_mmx.asm',
+        'base/simd/scale_yuv_to_rgb_mmx.inc',
+        'base/simd/scale_yuv_to_rgb_sse.asm',
+        'base/simd/yuv_to_rgb_table.cc',
+        'base/simd/yuv_to_rgb_table.h',
+      ],
+      'conditions': [
+        ['order_profiling != 0', {
+          'target_conditions' : [
+            ['_toolset==\"target\"', {
+              'cflags!': [ '-finstrument-functions' ],
+            }],
+          ],
+        }],
+        [ 'target_arch == \"x64\"', {
+          # Source files optimized for X64 systems.
+          'sources': [
+            'base/simd/linear_scale_yuv_to_rgb_mmx_x64.asm',
+            'base/simd/scale_yuv_to_rgb_sse2_x64.asm',
+          ],
+        }],
+        [ 'os_posix == 1 and OS != \"mac\" and OS != \"android\"', {
+          'cflags': [
+            '-msse2',
+          ],
+        }],
+        [ 'OS == \"mac\"', {
+          'configurations': {
+            'Debug': {
+              'xcode_settings': {
+                # gcc on the mac builds horribly unoptimized sse code in debug
+                # mode. Since this is rarely going to be debugged, run with full
+                # optimizations in Debug as well as Release.
+                'GCC_OPTIMIZATION_LEVEL': '3',  # -O3
+               },
+             },
+          },
+        }],
+        [ 'OS==\"win\"', {
+          'variables': {
+            'yasm_flags': [
+              '-DWIN32',
+              '-DMSVC',
+              '-DCHROMIUM',
+              '-Isimd',
+            ],
+          },
+        }],
+        [ 'OS==\"mac\"', {
+          'variables': {
+            'yasm_flags': [
+              '-DPREFIX',
+              '-DMACHO',
+              '-DCHROMIUM',
+              '-Isimd',
+            ],
+          },
+        }],
+        [ 'os_posix==1 and OS!=\"mac\"', {
+          'variables': {
+            'conditions': [
+              [ 'target_arch==\"ia32\"', {
+                'yasm_flags': [
+                  '-DX86_32',
+                  '-DELF',
+                  '-DCHROMIUM',
+                  '-Isimd',
+                ],
+              }, {
+                'yasm_flags': [
+                  '-DARCH_X86_64',
+                  '-DELF',
+                  '-DPIC',
+                  '-DCHROMIUM',
+                  '-Isimd',
+                ],
+              }],
+            ],
+          },
+        }],
+      ],
+      'variables': {
+        'yasm_output_path': '<(SHARED_INTERMEDIATE_DIR)/media',
+      },
+      'msvs_2010_disable_uldi_when_referenced': 1,
+      'includes': [
+        '../third_party/yasm/yasm_compile.gypi',
+      ],
+    },
+    {
+      'target_name': 'yuv_convert_simd_arm',
+      'type': 'static_library',
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'base/simd/convert_rgb_to_yuv_c.cc',
+        'base/simd/convert_rgb_to_yuv.h',
+        'base/simd/convert_yuv_to_rgb_c.cc',
+        'base/simd/convert_yuv_to_rgb.h',
+        'base/simd/filter_yuv.h',
+        'base/simd/filter_yuv_c.cc',
+        'base/simd/yuv_to_rgb_table.cc',
+        'base/simd/yuv_to_rgb_table.h',
+      ],
+    },
+    {
+      'target_name': 'media_unittests',
+      'type': 'executable',
+      'dependencies': [
+        'media',
+        'media_test_support',
+        'yuv_convert',
+        '../base/base.gyp:base',
+        '../base/base.gyp:base_i18n',
+        '../base/base.gyp:test_support_base',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        '../ui/ui.gyp:ui',
+      ],
+      'sources': [
+        'audio/async_socket_io_handler_unittest.cc',
+        'audio/audio_input_controller_unittest.cc',
+        'audio/audio_input_device_unittest.cc',
+        'audio/audio_input_unittest.cc',
+        'audio/audio_input_volume_unittest.cc',
+        'audio/audio_low_latency_input_output_unittest.cc',
+        'audio/audio_output_controller_unittest.cc',
+        'audio/audio_output_proxy_unittest.cc',
+        'audio/audio_parameters_unittest.cc',
+        'audio/audio_util_unittest.cc',
+        'audio/cross_process_notification_unittest.cc',
+        'audio/linux/alsa_output_unittest.cc',
+        'audio/mac/audio_low_latency_input_mac_unittest.cc',
+        'audio/mac/audio_output_mac_unittest.cc',
+        'audio/simple_sources_unittest.cc',
+        'audio/win/audio_low_latency_input_win_unittest.cc',
+        'audio/win/audio_low_latency_output_win_unittest.cc',
+        'audio/win/audio_output_win_unittest.cc',
+        'base/audio_renderer_mixer_unittest.cc',
+        'base/audio_renderer_mixer_input_unittest.cc',
+        'base/buffers_unittest.cc',
+        'base/clock_unittest.cc',
+        'base/composite_filter_unittest.cc',
+        'base/data_buffer_unittest.cc',
+        'base/decoder_buffer_unittest.cc',
+        'base/djb2_unittest.cc',
+        'base/fake_audio_render_callback.cc',
+        'base/fake_audio_render_callback.h',
+        'base/filter_collection_unittest.cc',
+        'base/h264_bitstream_converter_unittest.cc',
+        'base/pipeline_unittest.cc',
+        'base/ranges_unittest.cc',
+        'base/run_all_unittests.cc',
+        'base/seekable_buffer_unittest.cc',
+        'base/state_matrix_unittest.cc',
+        'base/test_data_util.cc',
+        'base/test_data_util.h',
+        'base/video_frame_unittest.cc',
+        'base/video_util_unittest.cc',
+        'base/yuv_convert_unittest.cc',
+        'crypto/aes_decryptor_unittest.cc',
+        'ffmpeg/ffmpeg_common_unittest.cc',
+        'filters/audio_renderer_algorithm_unittest.cc',
+        'filters/audio_renderer_impl_unittest.cc',
+        'filters/bitstream_converter_unittest.cc',
+        'filters/chunk_demuxer_unittest.cc',
+        'filters/ffmpeg_audio_decoder_unittest.cc',
+        'filters/ffmpeg_decoder_unittest.h',
+        'filters/ffmpeg_demuxer_unittest.cc',
+        'filters/ffmpeg_glue_unittest.cc',
+        'filters/ffmpeg_h264_bitstream_converter_unittest.cc',
+        'filters/ffmpeg_video_decoder_unittest.cc',
+        'filters/file_data_source_unittest.cc',
+        'filters/pipeline_integration_test.cc',
+        'filters/pipeline_integration_test_base.cc',
+        'filters/source_buffer_stream_unittest.cc',
+        'filters/video_renderer_base_unittest.cc',
+        'video/capture/video_capture_device_unittest.cc',
+        'webm/cluster_builder.cc',
+        'webm/cluster_builder.h',
+        'webm/webm_cluster_parser_unittest.cc',
+        'webm/webm_content_encodings_client_unittest.cc',
+        'webm/webm_parser_unittest.cc',
+      ],
+      'conditions': [
+        ['os_posix==1 and OS!=\"mac\"', {
+          'conditions': [
+            ['linux_use_tcmalloc==1', {
+              'dependencies': [
+                '../base/allocator/allocator.gyp:allocator',
+              ],
+            }],
+          ],
+        }],
+        ['OS != \"android\"', {
+          'dependencies': [
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+        }],
+        ['OS == \"android\"', {
+          'sources!': [
+            'audio/audio_input_volume_unittest.cc',
+            'base/test_data_util.cc',
+            'base/test_data_util.h',
+            'ffmpeg/ffmpeg_common_unittest.cc',
+            'filters/ffmpeg_audio_decoder_unittest.cc',
+            'filters/bitstream_converter_unittest.cc',
+            'filters/chunk_demuxer_unittest.cc',
+            'filters/ffmpeg_demuxer_unittest.cc',
+            'filters/ffmpeg_glue_unittest.cc',
+            'filters/ffmpeg_h264_bitstream_converter_unittest.cc',
+            'filters/ffmpeg_video_decoder_unittest.cc',
+            'filters/pipeline_integration_test.cc',
+            'filters/pipeline_integration_test_base.cc',
+            'mp4/mp4_stream_parser_unittest.cc',
+            'webm/webm_cluster_parser_unittest.cc',
+          ],
+        }],
+        ['OS == \"linux\"', {
+          'conditions': [
+            ['use_cras == 1', {
+              'sources': [
+                'audio/linux/cras_output_unittest.cc',
+              ],
+              'defines': [
+                'USE_CRAS',
+              ],
+            }],
+          ],
+        }],
+        [ 'target_arch==\"ia32\" or target_arch==\"x64\"', {
+          'sources': [
+            'base/simd/convert_rgb_to_yuv_unittest.cc',
+          ],
+        }],
+        ['proprietary_codecs==1 or branding==\"Chrome\"', {
+          'sources': [
+            'mp4/avc_unittest.cc',
+            'mp4/box_reader_unittest.cc',
+            'mp4/mp4_stream_parser_unittest.cc',
+            'mp4/offset_byte_queue_unittest.cc',
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'media_test_support',
+      'type': 'static_library',
+      'dependencies': [
+        'media',
+        '../base/base.gyp:base',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'audio/test_audio_input_controller_factory.cc',
+        'audio/test_audio_input_controller_factory.h',
+        'base/mock_callback.cc',
+        'base/mock_callback.h',
+        'base/mock_data_source_host.cc',
+        'base/mock_data_source_host.h',
+        'base/mock_demuxer_host.cc',
+        'base/mock_demuxer_host.h',
+        'base/mock_filter_host.cc',
+        'base/mock_filter_host.h',
+        'base/mock_filters.cc',
+        'base/mock_filters.h',
+      ],
+    },
+    {
+      'target_name': 'scaler_bench',
+      'type': 'executable',
+      'dependencies': [
+        'media',
+        'yuv_convert',
+        '../base/base.gyp:base',
+        '../skia/skia.gyp:skia',
+      ],
+      'sources': [
+        'tools/scaler_bench/scaler_bench.cc',
+      ],
+    },
+    {
+      'target_name': 'qt_faststart',
+      'type': 'executable',
+      'sources': [
+        'tools/qt_faststart/qt_faststart.c'
+      ],
+    },
+    {
+      'target_name': 'seek_tester',
+      'type': 'executable',
+      'dependencies': [
+        'media',
+        '../base/base.gyp:base',
+      ],
+      'sources': [
+        'tools/seek_tester/seek_tester.cc',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS==\"win\"', {
+      'targets': [
+        {
+          'target_name': 'player_wtl',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            'yuv_convert',
+            '../base/base.gyp:base',
+            '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+            '../ui/ui.gyp:ui',
+          ],
+          'include_dirs': [
+            '<(DEPTH)/third_party/wtl/include',
+          ],
+          'sources': [
+            'tools/player_wtl/list.h',
+            'tools/player_wtl/mainfrm.h',
+            'tools/player_wtl/movie.cc',
+            'tools/player_wtl/movie.h',
+            'tools/player_wtl/player_wtl.cc',
+            'tools/player_wtl/player_wtl.rc',
+            'tools/player_wtl/props.h',
+            'tools/player_wtl/seek.h',
+            'tools/player_wtl/resource.h',
+            'tools/player_wtl/view.h',
+          ],
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+            },
+          },
+          'defines': [
+            '_CRT_SECURE_NO_WARNINGS=1',
+          ],
+        },
+      ],
+    }],
+    ['OS == \"win\" or toolkit_uses_gtk == 1', {
+      'targets': [
+        {
+          'target_name': 'shader_bench',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            'yuv_convert',
+            '../base/base.gyp:base',
+            '../ui/gl/gl.gyp:gl',
+          ],
+          'sources': [
+            'tools/shader_bench/shader_bench.cc',
+            'tools/shader_bench/cpu_color_painter.cc',
+            'tools/shader_bench/cpu_color_painter.h',
+            'tools/shader_bench/gpu_color_painter.cc',
+            'tools/shader_bench/gpu_color_painter.h',
+            'tools/shader_bench/gpu_painter.cc',
+            'tools/shader_bench/gpu_painter.h',
+            'tools/shader_bench/painter.cc',
+            'tools/shader_bench/painter.h',
+            'tools/shader_bench/window.cc',
+            'tools/shader_bench/window.h',
+          ],
+          'conditions': [
+            ['toolkit_uses_gtk == 1', {
+              'dependencies': [
+                '../build/linux/system.gyp:gtk',
+              ],
+              'sources': [
+                'tools/shader_bench/window_linux.cc',
+              ],
+            }],
+            ['OS==\"win\"', {
+              'dependencies': [
+                '../third_party/angle/src/build_angle.gyp:libEGL',
+                '../third_party/angle/src/build_angle.gyp:libGLESv2',
+              ],
+              'sources': [
+                'tools/shader_bench/window_win.cc',
+              ],
+            }],
+          ],
+        },
+      ],
+    }],
+    ['OS == \"linux\" and target_arch != \"arm\"', {
+      'targets': [
+        {
+          'target_name': 'tile_render_bench',
+          'type': 'executable',
+          'dependencies': [
+            '../base/base.gyp:base',
+            '../ui/gl/gl.gyp:gl',
+          ],
+          'libraries': [
+            '-lGL',
+            '-ldl',
+          ],
+          'sources': [
+            'tools/tile_render_bench/tile_render_bench.cc',
+          ],
+        },
+      ],
+    }],
+    ['os_posix == 1 and OS != \"mac\" and OS != \"android\"', {
+      'targets': [
+        {
+          'target_name': 'player_x11',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            'yuv_convert',
+            '../base/base.gyp:base',
+            '../ui/gl/gl.gyp:gl',
+          ],
+          'link_settings': {
+            'libraries': [
+              '-ldl',
+              '-lX11',
+              '-lXrender',
+              '-lXext',
+            ],
+          },
+          'sources': [
+            'tools/player_x11/data_source_logger.cc',
+            'tools/player_x11/data_source_logger.h',
+            'tools/player_x11/gl_video_renderer.cc',
+            'tools/player_x11/gl_video_renderer.h',
+            'tools/player_x11/player_x11.cc',
+            'tools/player_x11/x11_video_renderer.cc',
+            'tools/player_x11/x11_video_renderer.h',
+          ],
+        },
+      ],
+    }],
+    ['OS == \"android\"', {
+      'targets': [
+        {
+          'target_name': 'player_android',
+          'type': 'static_library',
+          'sources': [
+            'base/android/media_player_bridge.cc',
+            'base/android/media_player_bridge.h',
+          ],
+          'dependencies': [
+            '../base/base.gyp:base',
+          ],
+          'include_dirs': [
+            '<(SHARED_INTERMEDIATE_DIR)/media',
+          ],
+          'actions': [
+            {
+              'action_name': 'generate-jni-headers',
+              'inputs': [
+                '../base/android/jni_generator/jni_generator.py',
+                'base/android/java/src/org/chromium/media/MediaPlayerListener.java',
+              ],
+              'outputs': [
+                '<(SHARED_INTERMEDIATE_DIR)/media/jni/media_player_listener_jni.h',
+              ],
+              'action': [
+                'python',
+                '<(DEPTH)/base/android/jni_generator/jni_generator.py',
+                '-o',
+                '<@(_inputs)',
+                '<@(_outputs)',
+              ],
+            },
+          ],
+        },
+        {
+          'target_name': 'media_java',
+          'type': 'none',
+          'dependencies': [ '../base/base.gyp:base_java' ],
+          'variables': {
+            'package_name': 'media',
+            'java_in_dir': 'base/android/java',
+          },
+          'includes': [ '../build/java.gypi' ],
+        },
+
+      ],
+    }, { # OS != \"android\"'
+      # Android does not use ffmpeg, so disable the targets which require it.
+      'targets': [
+        {
+          'target_name': 'ffmpeg_unittests',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            'media_test_support',
+            '../base/base.gyp:base',
+            '../base/base.gyp:base_i18n',
+            '../base/base.gyp:test_support_base',
+            '../base/base.gyp:test_support_perf',
+            '../testing/gtest.gyp:gtest',
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+          'sources': [
+            'ffmpeg/ffmpeg_unittest.cc',
+          ],
+          'conditions': [
+            ['toolkit_uses_gtk == 1', {
+              'dependencies': [
+                # Needed for the following #include chain:
+                #   base/run_all_unittests.cc
+                #   ../base/test_suite.h
+                #   gtk/gtk.h
+                '../build/linux/system.gyp:gtk',
+              ],
+              'conditions': [
+                ['linux_use_tcmalloc==1', {
+                  'dependencies': [
+                    '../base/allocator/allocator.gyp:allocator',
+                  ],
+                }],
+              ],
+            }],
+          ],
+        },
+        {
+          'target_name': 'ffmpeg_regression_tests',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            'media_test_support',
+            '../base/base.gyp:test_support_base',
+            '../testing/gmock.gyp:gmock',
+            '../testing/gtest.gyp:gtest',
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+          'sources': [
+            'base/test_data_util.cc',
+            'base/run_all_unittests.cc',
+            'ffmpeg/ffmpeg_regression_tests.cc',
+            'filters/pipeline_integration_test_base.cc',
+          ],
+          'conditions': [
+            ['os_posix==1 and OS!=\"mac\"', {
+              'conditions': [
+                ['linux_use_tcmalloc==1', {
+                  'dependencies': [
+                    '../base/allocator/allocator.gyp:allocator',
+                  ],
+                }],
+              ],
+            }],
+          ],
+        },
+        {
+          'target_name': 'ffmpeg_tests',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            '../base/base.gyp:base',
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+          'sources': [
+            'test/ffmpeg_tests/ffmpeg_tests.cc',
+          ],
+        },
+        {
+          'target_name': 'media_bench',
+          'type': 'executable',
+          'dependencies': [
+            'media',
+            '../base/base.gyp:base',
+            '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
+          ],
+          'sources': [
+            'tools/media_bench/media_bench.cc',
+          ],
+        },
+      ],
+    }]
+  ],
+}
+" 0 64 (face font-lock-comment-face) 64 137 (face font-lock-comment-face) 137 166 (face font-lock-comment-face) 166 171 nil 171 172 (face font-lock-string-face) 172 181 (face font-lock-keyword-face) 181 182 (face font-lock-string-face) 182 190 nil 190 191 (face font-lock-string-face) 191 204 (face font-lock-variable-name-face) 204 205 (face font-lock-string-face) 205 214 nil 214 269 (face font-lock-comment-face) 269 273 nil 273 274 (face font-lock-string-face) 274 289 (face font-lock-variable-name-face) 289 290 (face font-lock-string-face) 290 299 nil 299 365 (face font-lock-comment-face) 365 369 nil 369 370 (face font-lock-string-face) 370 379 (face font-lock-variable-name-face) 379 380 (face font-lock-string-face) 380 392 nil 392 393 (face font-lock-string-face) 393 400 (face font-lock-keyword-face) 400 401 (face font-lock-string-face) 401 417 nil 417 418 (face font-lock-string-face) 418 429 (face font-lock-keyword-face) 429 430 (face font-lock-string-face) 430 432 nil 432 433 (face font-lock-string-face) 433 438 (face font-lock-function-name-face) 438 439 (face font-lock-string-face) 439 447 nil 447 448 (face font-lock-string-face) 448 452 (face font-lock-keyword-face) 452 453 (face font-lock-string-face) 453 455 nil 455 458 (face font-lock-string-face) 458 467 (face font-lock-variable-name-face) 467 469 (face font-lock-string-face) 469 477 nil 477 478 (face font-lock-string-face) 478 490 (face font-lock-keyword-face) 490 491 (face font-lock-string-face) 491 503 nil 503 504 (face font-lock-string-face) 504 515 (face font-lock-function-name-face) 515 516 (face font-lock-string-face) 516 526 nil 526 527 (face font-lock-string-face) 527 548 (face font-lock-function-name-face) 548 549 (face font-lock-string-face) 549 559 nil 559 560 (face font-lock-string-face) 560 643 (face font-lock-function-name-face) 643 644 (face font-lock-string-face) 644 654 nil 654 655 (face font-lock-string-face) 655 696 (face font-lock-function-name-face) 696 697 (face font-lock-string-face) 697 707 nil 707 708 (face font-lock-string-face) 708 735 (face font-lock-function-name-face) 735 736 (face font-lock-string-face) 736 746 nil 746 747 (face font-lock-string-face) 747 784 (face font-lock-function-name-face) 784 785 (face font-lock-string-face) 785 795 nil 795 796 (face font-lock-string-face) 796 811 (face font-lock-function-name-face) 811 812 (face font-lock-string-face) 812 829 nil 829 830 (face font-lock-string-face) 830 837 (face font-lock-keyword-face) 837 838 (face font-lock-string-face) 838 850 nil 850 851 (face font-lock-string-face) 851 871 (face font-lock-preprocessor-face) 871 872 (face font-lock-string-face) 872 889 nil 889 890 (face font-lock-string-face) 890 902 (face font-lock-keyword-face) 902 903 (face font-lock-string-face) 903 915 nil 915 916 (face font-lock-string-face) 916 918 (face font-lock-constant-face) 918 919 (face font-lock-string-face) 919 936 nil 936 937 (face font-lock-string-face) 937 944 (face font-lock-keyword-face) 944 945 (face font-lock-string-face) 945 957 nil 957 958 (face font-lock-string-face) 958 996 (face font-lock-constant-face) 996 997 (face font-lock-string-face) 997 1007 nil 1007 1008 (face font-lock-string-face) 1008 1045 (face font-lock-constant-face) 1045 1046 (face font-lock-string-face) 1046 1056 nil 1056 1057 (face font-lock-string-face) 1057 1100 (face font-lock-constant-face) 1100 1101 (face font-lock-string-face) 1101 1111 nil 1111 1112 (face font-lock-string-face) 1112 1154 (face font-lock-constant-face) 1154 1155 (face font-lock-string-face) 1155 1165 nil 1165 1166 (face font-lock-string-face) 1166 1197 (face font-lock-constant-face) 1197 1198 (face font-lock-string-face) 1198 1208 nil 1208 1209 (face font-lock-string-face) 1209 1239 (face font-lock-constant-face) 1239 1240 (face font-lock-string-face) 1240 1250 nil 1250 1251 (face font-lock-string-face) 1251 1283 (face font-lock-constant-face) 1283 1284 (face font-lock-string-face) 1284 1294 nil 1294 1295 (face font-lock-string-face) 1295 1326 (face font-lock-constant-face) 1326 1327 (face font-lock-string-face) 1327 1337 nil 1337 1338 (face font-lock-string-face) 1338 1369 (face font-lock-constant-face) 1369 1370 (face font-lock-string-face) 1370 1380 nil 1380 1381 (face font-lock-string-face) 1381 1419 (face font-lock-constant-face) 1419 1420 (face font-lock-string-face) 1420 1430 nil 1430 1431 (face font-lock-string-face) 1431 1467 (face font-lock-constant-face) 1467 1468 (face font-lock-string-face) 1468 1478 nil 1478 1479 (face font-lock-string-face) 1479 1507 (face font-lock-constant-face) 1507 1508 (face font-lock-string-face) 1508 1518 nil 1518 1519 (face font-lock-string-face) 1519 1546 (face font-lock-constant-face) 1546 1547 (face font-lock-string-face) 1547 1557 nil 1557 1558 (face font-lock-string-face) 1558 1574 (face font-lock-constant-face) 1574 1575 (face font-lock-string-face) 1575 1585 nil 1585 1586 (face font-lock-string-face) 1586 1617 (face font-lock-constant-face) 1617 1618 (face font-lock-string-face) 1618 1628 nil 1628 1629 (face font-lock-string-face) 1629 1659 (face font-lock-constant-face) 1659 1660 (face font-lock-string-face) 1660 1670 nil 1670 1671 (face font-lock-string-face) 1671 1703 (face font-lock-constant-face) 1703 1704 (face font-lock-string-face) 1704 1714 nil 1714 1715 (face font-lock-string-face) 1715 1746 (face font-lock-constant-face) 1746 1747 (face font-lock-string-face) 1747 1757 nil 1757 1758 (face font-lock-string-face) 1758 1784 (face font-lock-constant-face) 1784 1785 (face font-lock-string-face) 1785 1795 nil 1795 1796 (face font-lock-string-face) 1796 1821 (face font-lock-constant-face) 1821 1822 (face font-lock-string-face) 1822 1832 nil 1832 1833 (face font-lock-string-face) 1833 1855 (face font-lock-constant-face) 1855 1856 (face font-lock-string-face) 1856 1866 nil 1866 1867 (face font-lock-string-face) 1867 1888 (face font-lock-constant-face) 1888 1889 (face font-lock-string-face) 1889 1899 nil 1899 1900 (face font-lock-string-face) 1900 1927 (face font-lock-constant-face) 1927 1928 (face font-lock-string-face) 1928 1938 nil 1938 1939 (face font-lock-string-face) 1939 1965 (face font-lock-constant-face) 1965 1966 (face font-lock-string-face) 1966 1976 nil 1976 1977 (face font-lock-string-face) 1977 2009 (face font-lock-constant-face) 2009 2010 (face font-lock-string-face) 2010 2020 nil 2020 2021 (face font-lock-string-face) 2021 2052 (face font-lock-constant-face) 2052 2053 (face font-lock-string-face) 2053 2063 nil 2063 2064 (face font-lock-string-face) 2064 2096 (face font-lock-constant-face) 2096 2097 (face font-lock-string-face) 2097 2107 nil 2107 2108 (face font-lock-string-face) 2108 2139 (face font-lock-constant-face) 2139 2140 (face font-lock-string-face) 2140 2150 nil 2150 2151 (face font-lock-string-face) 2151 2188 (face font-lock-constant-face) 2188 2189 (face font-lock-string-face) 2189 2199 nil 2199 2200 (face font-lock-string-face) 2200 2236 (face font-lock-constant-face) 2236 2237 (face font-lock-string-face) 2237 2247 nil 2247 2248 (face font-lock-string-face) 2248 2275 (face font-lock-constant-face) 2275 2276 (face font-lock-string-face) 2276 2286 nil 2286 2287 (face font-lock-string-face) 2287 2313 (face font-lock-constant-face) 2313 2314 (face font-lock-string-face) 2314 2324 nil 2324 2325 (face font-lock-string-face) 2325 2352 (face font-lock-constant-face) 2352 2353 (face font-lock-string-face) 2353 2363 nil 2363 2364 (face font-lock-string-face) 2364 2390 (face font-lock-constant-face) 2390 2391 (face font-lock-string-face) 2391 2401 nil 2401 2402 (face font-lock-string-face) 2402 2427 (face font-lock-constant-face) 2427 2428 (face font-lock-string-face) 2428 2438 nil 2438 2439 (face font-lock-string-face) 2439 2463 (face font-lock-constant-face) 2463 2464 (face font-lock-string-face) 2464 2474 nil 2474 2475 (face font-lock-string-face) 2475 2494 (face font-lock-constant-face) 2494 2495 (face font-lock-string-face) 2495 2505 nil 2505 2506 (face font-lock-string-face) 2506 2524 (face font-lock-constant-face) 2524 2525 (face font-lock-string-face) 2525 2535 nil 2535 2536 (face font-lock-string-face) 2536 2571 (face font-lock-constant-face) 2571 2572 (face font-lock-string-face) 2572 2582 nil 2582 2583 (face font-lock-string-face) 2583 2617 (face font-lock-constant-face) 2617 2618 (face font-lock-string-face) 2618 2628 nil 2628 2629 (face font-lock-string-face) 2629 2668 (face font-lock-constant-face) 2668 2669 (face font-lock-string-face) 2669 2679 nil 2679 2680 (face font-lock-string-face) 2680 2721 (face font-lock-constant-face) 2721 2722 (face font-lock-string-face) 2722 2732 nil 2732 2733 (face font-lock-string-face) 2733 2765 (face font-lock-constant-face) 2765 2766 (face font-lock-string-face) 2766 2776 nil 2776 2777 (face font-lock-string-face) 2777 2808 (face font-lock-constant-face) 2808 2809 (face font-lock-string-face) 2809 2819 nil 2819 2820 (face font-lock-string-face) 2820 2853 (face font-lock-constant-face) 2853 2854 (face font-lock-string-face) 2854 2864 nil 2864 2865 (face font-lock-string-face) 2865 2897 (face font-lock-constant-face) 2897 2898 (face font-lock-string-face) 2898 2908 nil 2908 2909 (face font-lock-string-face) 2909 2943 (face font-lock-constant-face) 2943 2944 (face font-lock-string-face) 2944 2954 nil 2954 2955 (face font-lock-string-face) 2955 2988 (face font-lock-constant-face) 2988 2989 (face font-lock-string-face) 2989 2999 nil 2999 3000 (face font-lock-string-face) 3000 3025 (face font-lock-constant-face) 3025 3026 (face font-lock-string-face) 3026 3036 nil 3036 3037 (face font-lock-string-face) 3037 3061 (face font-lock-constant-face) 3061 3062 (face font-lock-string-face) 3062 3072 nil 3072 3073 (face font-lock-string-face) 3073 3099 (face font-lock-constant-face) 3099 3100 (face font-lock-string-face) 3100 3110 nil 3110 3111 (face font-lock-string-face) 3111 3136 (face font-lock-constant-face) 3136 3137 (face font-lock-string-face) 3137 3147 nil 3147 3148 (face font-lock-string-face) 3148 3172 (face font-lock-constant-face) 3172 3173 (face font-lock-string-face) 3173 3183 nil 3183 3184 (face font-lock-string-face) 3184 3207 (face font-lock-constant-face) 3207 3208 (face font-lock-string-face) 3208 3218 nil 3218 3219 (face font-lock-string-face) 3219 3246 (face font-lock-constant-face) 3246 3247 (face font-lock-string-face) 3247 3257 nil 3257 3258 (face font-lock-string-face) 3258 3284 (face font-lock-constant-face) 3284 3285 (face font-lock-string-face) 3285 3295 nil 3295 3296 (face font-lock-string-face) 3296 3322 (face font-lock-constant-face) 3322 3323 (face font-lock-string-face) 3323 3333 nil 3333 3334 (face font-lock-string-face) 3334 3359 (face font-lock-constant-face) 3359 3360 (face font-lock-string-face) 3360 3370 nil 3370 3371 (face font-lock-string-face) 3371 3409 (face font-lock-constant-face) 3409 3410 (face font-lock-string-face) 3410 3420 nil 3420 3421 (face font-lock-string-face) 3421 3458 (face font-lock-constant-face) 3458 3459 (face font-lock-string-face) 3459 3469 nil 3469 3470 (face font-lock-string-face) 3470 3498 (face font-lock-constant-face) 3498 3499 (face font-lock-string-face) 3499 3509 nil 3509 3510 (face font-lock-string-face) 3510 3537 (face font-lock-constant-face) 3537 3538 (face font-lock-string-face) 3538 3548 nil 3548 3549 (face font-lock-string-face) 3549 3589 (face font-lock-constant-face) 3589 3590 (face font-lock-string-face) 3590 3600 nil 3600 3601 (face font-lock-string-face) 3601 3640 (face font-lock-constant-face) 3640 3641 (face font-lock-string-face) 3641 3651 nil 3651 3652 (face font-lock-string-face) 3652 3693 (face font-lock-constant-face) 3693 3694 (face font-lock-string-face) 3694 3704 nil 3704 3705 (face font-lock-string-face) 3705 3745 (face font-lock-constant-face) 3745 3746 (face font-lock-string-face) 3746 3756 nil 3756 3757 (face font-lock-string-face) 3757 3787 (face font-lock-constant-face) 3787 3788 (face font-lock-string-face) 3788 3798 nil 3798 3799 (face font-lock-string-face) 3799 3828 (face font-lock-constant-face) 3828 3829 (face font-lock-string-face) 3829 3839 nil 3839 3840 (face font-lock-string-face) 3840 3869 (face font-lock-constant-face) 3869 3870 (face font-lock-string-face) 3870 3880 nil 3880 3881 (face font-lock-string-face) 3881 3909 (face font-lock-constant-face) 3909 3910 (face font-lock-string-face) 3910 3920 nil 3920 3921 (face font-lock-string-face) 3921 3945 (face font-lock-constant-face) 3945 3946 (face font-lock-string-face) 3946 3956 nil 3956 3957 (face font-lock-string-face) 3957 3980 (face font-lock-constant-face) 3980 3981 (face font-lock-string-face) 3981 3991 nil 3991 3992 (face font-lock-string-face) 3992 4019 (face font-lock-constant-face) 4019 4020 (face font-lock-string-face) 4020 4030 nil 4030 4031 (face font-lock-string-face) 4031 4057 (face font-lock-constant-face) 4057 4058 (face font-lock-string-face) 4058 4068 nil 4068 4069 (face font-lock-string-face) 4069 4090 (face font-lock-constant-face) 4090 4091 (face font-lock-string-face) 4091 4101 nil 4101 4102 (face font-lock-string-face) 4102 4122 (face font-lock-constant-face) 4122 4123 (face font-lock-string-face) 4123 4133 nil 4133 4134 (face font-lock-string-face) 4134 4157 (face font-lock-constant-face) 4157 4158 (face font-lock-string-face) 4158 4168 nil 4168 4169 (face font-lock-string-face) 4169 4191 (face font-lock-constant-face) 4191 4192 (face font-lock-string-face) 4192 4202 nil 4202 4203 (face font-lock-string-face) 4203 4243 (face font-lock-constant-face) 4243 4244 (face font-lock-string-face) 4244 4254 nil 4254 4255 (face font-lock-string-face) 4255 4294 (face font-lock-constant-face) 4294 4295 (face font-lock-string-face) 4295 4305 nil 4305 4306 (face font-lock-string-face) 4306 4347 (face font-lock-constant-face) 4347 4348 (face font-lock-string-face) 4348 4358 nil 4358 4359 (face font-lock-string-face) 4359 4399 (face font-lock-constant-face) 4399 4400 (face font-lock-string-face) 4400 4410 nil 4410 4411 (face font-lock-string-face) 4411 4441 (face font-lock-constant-face) 4441 4442 (face font-lock-string-face) 4442 4452 nil 4452 4453 (face font-lock-string-face) 4453 4482 (face font-lock-constant-face) 4482 4483 (face font-lock-string-face) 4483 4493 nil 4493 4494 (face font-lock-string-face) 4494 4523 (face font-lock-constant-face) 4523 4524 (face font-lock-string-face) 4524 4534 nil 4534 4535 (face font-lock-string-face) 4535 4563 (face font-lock-constant-face) 4563 4564 (face font-lock-string-face) 4564 4574 nil 4574 4575 (face font-lock-string-face) 4575 4610 (face font-lock-constant-face) 4610 4611 (face font-lock-string-face) 4611 4621 nil 4621 4622 (face font-lock-string-face) 4622 4656 (face font-lock-constant-face) 4656 4657 (face font-lock-string-face) 4657 4667 nil 4667 4668 (face font-lock-string-face) 4668 4697 (face font-lock-constant-face) 4697 4698 (face font-lock-string-face) 4698 4708 nil 4708 4709 (face font-lock-string-face) 4709 4737 (face font-lock-constant-face) 4737 4738 (face font-lock-string-face) 4738 4748 nil 4748 4749 (face font-lock-string-face) 4749 4780 (face font-lock-constant-face) 4780 4781 (face font-lock-string-face) 4781 4791 nil 4791 4792 (face font-lock-string-face) 4792 4822 (face font-lock-constant-face) 4822 4823 (face font-lock-string-face) 4823 4833 nil 4833 4834 (face font-lock-string-face) 4834 4869 (face font-lock-constant-face) 4869 4870 (face font-lock-string-face) 4870 4880 nil 4880 4881 (face font-lock-string-face) 4881 4915 (face font-lock-constant-face) 4915 4916 (face font-lock-string-face) 4916 4926 nil 4926 4927 (face font-lock-string-face) 4927 4948 (face font-lock-constant-face) 4948 4949 (face font-lock-string-face) 4949 4959 nil 4959 4960 (face font-lock-string-face) 4960 4980 (face font-lock-constant-face) 4980 4981 (face font-lock-string-face) 4981 4991 nil 4991 4992 (face font-lock-string-face) 4992 5020 (face font-lock-constant-face) 5020 5021 (face font-lock-string-face) 5021 5031 nil 5031 5032 (face font-lock-string-face) 5032 5059 (face font-lock-constant-face) 5059 5060 (face font-lock-string-face) 5060 5070 nil 5070 5071 (face font-lock-string-face) 5071 5092 (face font-lock-constant-face) 5092 5093 (face font-lock-string-face) 5093 5103 nil 5103 5104 (face font-lock-string-face) 5104 5132 (face font-lock-constant-face) 5132 5133 (face font-lock-string-face) 5133 5143 nil 5143 5144 (face font-lock-string-face) 5144 5171 (face font-lock-constant-face) 5171 5172 (face font-lock-string-face) 5172 5182 nil 5182 5183 (face font-lock-string-face) 5183 5217 (face font-lock-constant-face) 5217 5218 (face font-lock-string-face) 5218 5228 nil 5228 5229 (face font-lock-string-face) 5229 5262 (face font-lock-constant-face) 5262 5263 (face font-lock-string-face) 5263 5273 nil 5273 5274 (face font-lock-string-face) 5274 5297 (face font-lock-constant-face) 5297 5298 (face font-lock-string-face) 5298 5308 nil 5308 5309 (face font-lock-string-face) 5309 5324 (face font-lock-constant-face) 5324 5325 (face font-lock-string-face) 5325 5335 nil 5335 5336 (face font-lock-string-face) 5336 5350 (face font-lock-constant-face) 5350 5351 (face font-lock-string-face) 5351 5361 nil 5361 5362 (face font-lock-string-face) 5362 5380 (face font-lock-constant-face) 5380 5381 (face font-lock-string-face) 5381 5391 nil 5391 5392 (face font-lock-string-face) 5392 5409 (face font-lock-constant-face) 5409 5410 (face font-lock-string-face) 5410 5420 nil 5420 5421 (face font-lock-string-face) 5421 5443 (face font-lock-constant-face) 5443 5444 (face font-lock-string-face) 5444 5454 nil 5454 5455 (face font-lock-string-face) 5455 5476 (face font-lock-constant-face) 5476 5477 (face font-lock-string-face) 5477 5487 nil 5487 5488 (face font-lock-string-face) 5488 5501 (face font-lock-constant-face) 5501 5502 (face font-lock-string-face) 5502 5512 nil 5512 5513 (face font-lock-string-face) 5513 5525 (face font-lock-constant-face) 5525 5526 (face font-lock-string-face) 5526 5536 nil 5536 5537 (face font-lock-string-face) 5537 5561 (face font-lock-constant-face) 5561 5562 (face font-lock-string-face) 5562 5572 nil 5572 5573 (face font-lock-string-face) 5573 5596 (face font-lock-constant-face) 5596 5597 (face font-lock-string-face) 5597 5607 nil 5607 5608 (face font-lock-string-face) 5608 5627 (face font-lock-constant-face) 5627 5628 (face font-lock-string-face) 5628 5638 nil 5638 5639 (face font-lock-string-face) 5639 5657 (face font-lock-constant-face) 5657 5658 (face font-lock-string-face) 5658 5668 nil 5668 5669 (face font-lock-string-face) 5669 5688 (face font-lock-constant-face) 5688 5689 (face font-lock-string-face) 5689 5699 nil 5699 5700 (face font-lock-string-face) 5700 5718 (face font-lock-constant-face) 5718 5719 (face font-lock-string-face) 5719 5729 nil 5729 5730 (face font-lock-string-face) 5730 5752 (face font-lock-constant-face) 5752 5753 (face font-lock-string-face) 5753 5763 nil 5763 5764 (face font-lock-string-face) 5764 5785 (face font-lock-constant-face) 5785 5786 (face font-lock-string-face) 5786 5796 nil 5796 5797 (face font-lock-string-face) 5797 5819 (face font-lock-constant-face) 5819 5820 (face font-lock-string-face) 5820 5830 nil 5830 5831 (face font-lock-string-face) 5831 5852 (face font-lock-constant-face) 5852 5853 (face font-lock-string-face) 5853 5863 nil 5863 5864 (face font-lock-string-face) 5864 5880 (face font-lock-constant-face) 5880 5881 (face font-lock-string-face) 5881 5891 nil 5891 5892 (face font-lock-string-face) 5892 5915 (face font-lock-constant-face) 5915 5916 (face font-lock-string-face) 5916 5926 nil 5926 5927 (face font-lock-string-face) 5927 5942 (face font-lock-constant-face) 5942 5943 (face font-lock-string-face) 5943 5953 nil 5953 5954 (face font-lock-string-face) 5954 5968 (face font-lock-constant-face) 5968 5969 (face font-lock-string-face) 5969 5979 nil 5979 5980 (face font-lock-string-face) 5980 6002 (face font-lock-constant-face) 6002 6003 (face font-lock-string-face) 6003 6013 nil 6013 6014 (face font-lock-string-face) 6014 6035 (face font-lock-constant-face) 6035 6036 (face font-lock-string-face) 6036 6046 nil 6046 6047 (face font-lock-string-face) 6047 6059 (face font-lock-constant-face) 6059 6060 (face font-lock-string-face) 6060 6070 nil 6070 6071 (face font-lock-string-face) 6071 6082 (face font-lock-constant-face) 6082 6083 (face font-lock-string-face) 6083 6093 nil 6093 6094 (face font-lock-string-face) 6094 6119 (face font-lock-constant-face) 6119 6120 (face font-lock-string-face) 6120 6130 nil 6130 6131 (face font-lock-string-face) 6131 6155 (face font-lock-constant-face) 6155 6156 (face font-lock-string-face) 6156 6166 nil 6166 6167 (face font-lock-string-face) 6167 6185 (face font-lock-constant-face) 6185 6186 (face font-lock-string-face) 6186 6196 nil 6196 6197 (face font-lock-string-face) 6197 6212 (face font-lock-constant-face) 6212 6213 (face font-lock-string-face) 6213 6223 nil 6223 6224 (face font-lock-string-face) 6224 6238 (face font-lock-constant-face) 6238 6239 (face font-lock-string-face) 6239 6249 nil 6249 6250 (face font-lock-string-face) 6250 6282 (face font-lock-constant-face) 6282 6283 (face font-lock-string-face) 6283 6293 nil 6293 6294 (face font-lock-string-face) 6294 6325 (face font-lock-constant-face) 6325 6326 (face font-lock-string-face) 6326 6336 nil 6336 6337 (face font-lock-string-face) 6337 6349 (face font-lock-constant-face) 6349 6350 (face font-lock-string-face) 6350 6360 nil 6360 6361 (face font-lock-string-face) 6361 6382 (face font-lock-constant-face) 6382 6383 (face font-lock-string-face) 6383 6393 nil 6393 6394 (face font-lock-string-face) 6394 6413 (face font-lock-constant-face) 6413 6414 (face font-lock-string-face) 6414 6424 nil 6424 6425 (face font-lock-string-face) 6425 6442 (face font-lock-constant-face) 6442 6443 (face font-lock-string-face) 6443 6453 nil 6453 6454 (face font-lock-string-face) 6454 6470 (face font-lock-constant-face) 6470 6471 (face font-lock-string-face) 6471 6481 nil 6481 6482 (face font-lock-string-face) 6482 6504 (face font-lock-constant-face) 6504 6505 (face font-lock-string-face) 6505 6515 nil 6515 6516 (face font-lock-string-face) 6516 6535 (face font-lock-constant-face) 6535 6536 (face font-lock-string-face) 6536 6546 nil 6546 6547 (face font-lock-string-face) 6547 6569 (face font-lock-constant-face) 6569 6570 (face font-lock-string-face) 6570 6580 nil 6580 6581 (face font-lock-string-face) 6581 6602 (face font-lock-constant-face) 6602 6603 (face font-lock-string-face) 6603 6613 nil 6613 6614 (face font-lock-string-face) 6614 6631 (face font-lock-constant-face) 6631 6632 (face font-lock-string-face) 6632 6642 nil 6642 6643 (face font-lock-string-face) 6643 6671 (face font-lock-constant-face) 6671 6672 (face font-lock-string-face) 6672 6682 nil 6682 6683 (face font-lock-string-face) 6683 6710 (face font-lock-constant-face) 6710 6711 (face font-lock-string-face) 6711 6721 nil 6721 6722 (face font-lock-string-face) 6722 6738 (face font-lock-constant-face) 6738 6739 (face font-lock-string-face) 6739 6749 nil 6749 6750 (face font-lock-string-face) 6750 6765 (face font-lock-constant-face) 6765 6766 (face font-lock-string-face) 6766 6776 nil 6776 6777 (face font-lock-string-face) 6777 6800 (face font-lock-constant-face) 6800 6801 (face font-lock-string-face) 6801 6811 nil 6811 6812 (face font-lock-string-face) 6812 6834 (face font-lock-constant-face) 6834 6835 (face font-lock-string-face) 6835 6845 nil 6845 6846 (face font-lock-string-face) 6846 6860 (face font-lock-constant-face) 6860 6861 (face font-lock-string-face) 6861 6871 nil 6871 6872 (face font-lock-string-face) 6872 6885 (face font-lock-constant-face) 6885 6886 (face font-lock-string-face) 6886 6896 nil 6896 6897 (face font-lock-string-face) 6897 6920 (face font-lock-constant-face) 6920 6921 (face font-lock-string-face) 6921 6931 nil 6931 6932 (face font-lock-string-face) 6932 6954 (face font-lock-constant-face) 6954 6955 (face font-lock-string-face) 6955 6965 nil 6965 6966 (face font-lock-string-face) 6966 6986 (face font-lock-constant-face) 6986 6987 (face font-lock-string-face) 6987 6997 nil 6997 6998 (face font-lock-string-face) 6998 7017 (face font-lock-constant-face) 7017 7018 (face font-lock-string-face) 7018 7028 nil 7028 7029 (face font-lock-string-face) 7029 7050 (face font-lock-constant-face) 7050 7051 (face font-lock-string-face) 7051 7061 nil 7061 7062 (face font-lock-string-face) 7062 7082 (face font-lock-constant-face) 7082 7083 (face font-lock-string-face) 7083 7093 nil 7093 7094 (face font-lock-string-face) 7094 7122 (face font-lock-constant-face) 7122 7123 (face font-lock-string-face) 7123 7133 nil 7133 7134 (face font-lock-string-face) 7134 7161 (face font-lock-constant-face) 7161 7162 (face font-lock-string-face) 7162 7172 nil 7172 7173 (face font-lock-string-face) 7173 7194 (face font-lock-constant-face) 7194 7195 (face font-lock-string-face) 7195 7205 nil 7205 7206 (face font-lock-string-face) 7206 7226 (face font-lock-constant-face) 7226 7227 (face font-lock-string-face) 7227 7237 nil 7237 7238 (face font-lock-string-face) 7238 7266 (face font-lock-constant-face) 7266 7267 (face font-lock-string-face) 7267 7277 nil 7277 7278 (face font-lock-string-face) 7278 7305 (face font-lock-constant-face) 7305 7306 (face font-lock-string-face) 7306 7316 nil 7316 7317 (face font-lock-string-face) 7317 7336 (face font-lock-constant-face) 7336 7337 (face font-lock-string-face) 7337 7347 nil 7347 7348 (face font-lock-string-face) 7348 7366 (face font-lock-constant-face) 7366 7367 (face font-lock-string-face) 7367 7377 nil 7377 7378 (face font-lock-string-face) 7378 7399 (face font-lock-constant-face) 7399 7400 (face font-lock-string-face) 7400 7410 nil 7410 7411 (face font-lock-string-face) 7411 7429 (face font-lock-constant-face) 7429 7430 (face font-lock-string-face) 7430 7440 nil 7440 7441 (face font-lock-string-face) 7441 7458 (face font-lock-constant-face) 7458 7459 (face font-lock-string-face) 7459 7469 nil 7469 7470 (face font-lock-string-face) 7470 7493 (face font-lock-constant-face) 7493 7494 (face font-lock-string-face) 7494 7504 nil 7504 7505 (face font-lock-string-face) 7505 7527 (face font-lock-constant-face) 7527 7528 (face font-lock-string-face) 7528 7538 nil 7538 7539 (face font-lock-string-face) 7539 7562 (face font-lock-constant-face) 7562 7563 (face font-lock-string-face) 7563 7573 nil 7573 7574 (face font-lock-string-face) 7574 7596 (face font-lock-constant-face) 7596 7597 (face font-lock-string-face) 7597 7607 nil 7607 7608 (face font-lock-string-face) 7608 7631 (face font-lock-constant-face) 7631 7632 (face font-lock-string-face) 7632 7642 nil 7642 7643 (face font-lock-string-face) 7643 7665 (face font-lock-constant-face) 7665 7666 (face font-lock-string-face) 7666 7676 nil 7676 7677 (face font-lock-string-face) 7677 7705 (face font-lock-constant-face) 7705 7706 (face font-lock-string-face) 7706 7716 nil 7716 7717 (face font-lock-string-face) 7717 7744 (face font-lock-constant-face) 7744 7745 (face font-lock-string-face) 7745 7755 nil 7755 7756 (face font-lock-string-face) 7756 7791 (face font-lock-constant-face) 7791 7792 (face font-lock-string-face) 7792 7802 nil 7802 7803 (face font-lock-string-face) 7803 7837 (face font-lock-constant-face) 7837 7838 (face font-lock-string-face) 7838 7848 nil 7848 7849 (face font-lock-string-face) 7849 7879 (face font-lock-constant-face) 7879 7880 (face font-lock-string-face) 7880 7890 nil 7890 7891 (face font-lock-string-face) 7891 7920 (face font-lock-constant-face) 7920 7921 (face font-lock-string-face) 7921 7931 nil 7931 7932 (face font-lock-string-face) 7932 7962 (face font-lock-constant-face) 7962 7963 (face font-lock-string-face) 7963 7973 nil 7973 7974 (face font-lock-string-face) 7974 8003 (face font-lock-constant-face) 8003 8004 (face font-lock-string-face) 8004 8014 nil 8014 8015 (face font-lock-string-face) 8015 8039 (face font-lock-constant-face) 8039 8040 (face font-lock-string-face) 8040 8050 nil 8050 8051 (face font-lock-string-face) 8051 8074 (face font-lock-constant-face) 8074 8075 (face font-lock-string-face) 8075 8085 nil 8085 8086 (face font-lock-string-face) 8086 8116 (face font-lock-constant-face) 8116 8117 (face font-lock-string-face) 8117 8127 nil 8127 8128 (face font-lock-string-face) 8128 8152 (face font-lock-constant-face) 8152 8153 (face font-lock-string-face) 8153 8163 nil 8163 8164 (face font-lock-string-face) 8164 8187 (face font-lock-constant-face) 8187 8188 (face font-lock-string-face) 8188 8198 nil 8198 8199 (face font-lock-string-face) 8199 8230 (face font-lock-constant-face) 8230 8231 (face font-lock-string-face) 8231 8241 nil 8241 8242 (face font-lock-string-face) 8242 8272 (face font-lock-constant-face) 8272 8273 (face font-lock-string-face) 8273 8283 nil 8283 8284 (face font-lock-string-face) 8284 8309 (face font-lock-constant-face) 8309 8310 (face font-lock-string-face) 8310 8320 nil 8320 8321 (face font-lock-string-face) 8321 8345 (face font-lock-constant-face) 8345 8346 (face font-lock-string-face) 8346 8356 nil 8356 8357 (face font-lock-string-face) 8357 8399 (face font-lock-constant-face) 8399 8400 (face font-lock-string-face) 8400 8410 nil 8410 8411 (face font-lock-string-face) 8411 8452 (face font-lock-constant-face) 8452 8453 (face font-lock-string-face) 8453 8463 nil 8463 8464 (face font-lock-string-face) 8464 8486 (face font-lock-constant-face) 8486 8487 (face font-lock-string-face) 8487 8497 nil 8497 8498 (face font-lock-string-face) 8498 8519 (face font-lock-constant-face) 8519 8520 (face font-lock-string-face) 8520 8530 nil 8530 8531 (face font-lock-string-face) 8531 8562 (face font-lock-constant-face) 8562 8563 (face font-lock-string-face) 8563 8573 nil 8573 8574 (face font-lock-string-face) 8574 8604 (face font-lock-constant-face) 8604 8605 (face font-lock-string-face) 8605 8615 nil 8615 8616 (face font-lock-string-face) 8616 8643 (face font-lock-constant-face) 8643 8644 (face font-lock-string-face) 8644 8654 nil 8654 8655 (face font-lock-string-face) 8655 8681 (face font-lock-constant-face) 8681 8682 (face font-lock-string-face) 8682 8692 nil 8692 8693 (face font-lock-string-face) 8693 8721 (face font-lock-constant-face) 8721 8722 (face font-lock-string-face) 8722 8732 nil 8732 8733 (face font-lock-string-face) 8733 8760 (face font-lock-constant-face) 8760 8761 (face font-lock-string-face) 8761 8771 nil 8771 8772 (face font-lock-string-face) 8772 8805 (face font-lock-constant-face) 8805 8806 (face font-lock-string-face) 8806 8816 nil 8816 8817 (face font-lock-string-face) 8817 8849 (face font-lock-constant-face) 8849 8850 (face font-lock-string-face) 8850 8860 nil 8860 8861 (face font-lock-string-face) 8861 8892 (face font-lock-constant-face) 8892 8893 (face font-lock-string-face) 8893 8903 nil 8903 8904 (face font-lock-string-face) 8904 8934 (face font-lock-constant-face) 8934 8935 (face font-lock-string-face) 8935 8945 nil 8945 8946 (face font-lock-string-face) 8946 8978 (face font-lock-constant-face) 8978 8979 (face font-lock-string-face) 8979 8989 nil 8989 8990 (face font-lock-string-face) 8990 9021 (face font-lock-constant-face) 9021 9022 (face font-lock-string-face) 9022 9032 nil 9032 9033 (face font-lock-string-face) 9033 9063 (face font-lock-constant-face) 9063 9064 (face font-lock-string-face) 9064 9074 nil 9074 9075 (face font-lock-string-face) 9075 9104 (face font-lock-constant-face) 9104 9105 (face font-lock-string-face) 9105 9115 nil 9115 9116 (face font-lock-string-face) 9116 9158 (face font-lock-constant-face) 9158 9159 (face font-lock-string-face) 9159 9169 nil 9169 9170 (face font-lock-string-face) 9170 9211 (face font-lock-constant-face) 9211 9212 (face font-lock-string-face) 9212 9222 nil 9222 9223 (face font-lock-string-face) 9223 9272 (face font-lock-constant-face) 9272 9273 (face font-lock-string-face) 9273 9283 nil 9283 9284 (face font-lock-string-face) 9284 9332 (face font-lock-constant-face) 9332 9333 (face font-lock-string-face) 9333 9343 nil 9343 9344 (face font-lock-string-face) 9344 9388 (face font-lock-constant-face) 9388 9389 (face font-lock-string-face) 9389 9399 nil 9399 9400 (face font-lock-string-face) 9400 9445 (face font-lock-constant-face) 9445 9446 (face font-lock-string-face) 9446 9456 nil 9456 9457 (face font-lock-string-face) 9457 9507 (face font-lock-constant-face) 9507 9508 (face font-lock-string-face) 9508 9518 nil 9518 9519 (face font-lock-string-face) 9519 9570 (face font-lock-constant-face) 9570 9571 (face font-lock-string-face) 9571 9581 nil 9581 9582 (face font-lock-string-face) 9582 9611 (face font-lock-constant-face) 9611 9612 (face font-lock-string-face) 9612 9622 nil 9622 9623 (face font-lock-string-face) 9623 9659 (face font-lock-constant-face) 9659 9660 (face font-lock-string-face) 9660 9670 nil 9670 9671 (face font-lock-string-face) 9671 9714 (face font-lock-constant-face) 9714 9715 (face font-lock-string-face) 9715 9725 nil 9725 9726 (face font-lock-string-face) 9726 9768 (face font-lock-constant-face) 9768 9769 (face font-lock-string-face) 9769 9779 nil 9779 9780 (face font-lock-string-face) 9780 9816 (face font-lock-constant-face) 9816 9817 (face font-lock-string-face) 9817 9827 nil 9827 9828 (face font-lock-string-face) 9828 9863 (face font-lock-constant-face) 9863 9864 (face font-lock-string-face) 9864 9874 nil 9874 9875 (face font-lock-string-face) 9875 9910 (face font-lock-constant-face) 9910 9911 (face font-lock-string-face) 9911 9921 nil 9921 9922 (face font-lock-string-face) 9922 9958 (face font-lock-constant-face) 9958 9959 (face font-lock-string-face) 9959 9969 nil 9969 9970 (face font-lock-string-face) 9970 10005 (face font-lock-constant-face) 10005 10006 (face font-lock-string-face) 10006 10016 nil 10016 10017 (face font-lock-string-face) 10017 10050 (face font-lock-constant-face) 10050 10051 (face font-lock-string-face) 10051 10061 nil 10061 10062 (face font-lock-string-face) 10062 10094 (face font-lock-constant-face) 10094 10095 (face font-lock-string-face) 10095 10105 nil 10105 10106 (face font-lock-string-face) 10106 10150 (face font-lock-constant-face) 10150 10151 (face font-lock-string-face) 10151 10161 nil 10161 10162 (face font-lock-string-face) 10162 10198 (face font-lock-constant-face) 10198 10199 (face font-lock-string-face) 10199 10209 nil 10209 10210 (face font-lock-string-face) 10210 10245 (face font-lock-constant-face) 10245 10246 (face font-lock-string-face) 10246 10256 nil 10256 10257 (face font-lock-string-face) 10257 10296 (face font-lock-constant-face) 10296 10297 (face font-lock-string-face) 10297 10307 nil 10307 10308 (face font-lock-string-face) 10308 10346 (face font-lock-constant-face) 10346 10347 (face font-lock-string-face) 10347 10357 nil 10357 10358 (face font-lock-string-face) 10358 10403 (face font-lock-constant-face) 10403 10404 (face font-lock-string-face) 10404 10414 nil 10414 10415 (face font-lock-string-face) 10415 10459 (face font-lock-constant-face) 10459 10460 (face font-lock-string-face) 10460 10470 nil 10470 10471 (face font-lock-string-face) 10471 10487 (face font-lock-constant-face) 10487 10488 (face font-lock-string-face) 10488 10498 nil 10498 10499 (face font-lock-string-face) 10499 10514 (face font-lock-constant-face) 10514 10515 (face font-lock-string-face) 10515 10525 nil 10525 10526 (face font-lock-string-face) 10526 10559 (face font-lock-constant-face) 10559 10560 (face font-lock-string-face) 10560 10570 nil 10570 10571 (face font-lock-string-face) 10571 10603 (face font-lock-constant-face) 10603 10604 (face font-lock-string-face) 10604 10614 nil 10614 10615 (face font-lock-string-face) 10615 10636 (face font-lock-constant-face) 10636 10637 (face font-lock-string-face) 10637 10647 nil 10647 10648 (face font-lock-string-face) 10648 10675 (face font-lock-constant-face) 10675 10676 (face font-lock-string-face) 10676 10686 nil 10686 10687 (face font-lock-string-face) 10687 10713 (face font-lock-constant-face) 10713 10714 (face font-lock-string-face) 10714 10724 nil 10724 10725 (face font-lock-string-face) 10725 10755 (face font-lock-constant-face) 10755 10756 (face font-lock-string-face) 10756 10766 nil 10766 10767 (face font-lock-string-face) 10767 10796 (face font-lock-constant-face) 10796 10797 (face font-lock-string-face) 10797 10807 nil 10807 10808 (face font-lock-string-face) 10808 10845 (face font-lock-constant-face) 10845 10846 (face font-lock-string-face) 10846 10856 nil 10856 10857 (face font-lock-string-face) 10857 10893 (face font-lock-constant-face) 10893 10894 (face font-lock-string-face) 10894 10904 nil 10904 10905 (face font-lock-string-face) 10905 10929 (face font-lock-constant-face) 10929 10930 (face font-lock-string-face) 10930 10940 nil 10940 10941 (face font-lock-string-face) 10941 10964 (face font-lock-constant-face) 10964 10965 (face font-lock-string-face) 10965 10975 nil 10975 10976 (face font-lock-string-face) 10976 10995 (face font-lock-constant-face) 10995 10996 (face font-lock-string-face) 10996 11006 nil 11006 11007 (face font-lock-string-face) 11007 11025 (face font-lock-constant-face) 11025 11026 (face font-lock-string-face) 11026 11036 nil 11036 11037 (face font-lock-string-face) 11037 11063 (face font-lock-constant-face) 11063 11064 (face font-lock-string-face) 11064 11074 nil 11074 11075 (face font-lock-string-face) 11075 11100 (face font-lock-constant-face) 11100 11101 (face font-lock-string-face) 11101 11111 nil 11111 11112 (face font-lock-string-face) 11112 11138 (face font-lock-constant-face) 11138 11139 (face font-lock-string-face) 11139 11149 nil 11149 11150 (face font-lock-string-face) 11150 11175 (face font-lock-constant-face) 11175 11176 (face font-lock-string-face) 11176 11193 nil 11193 11194 (face font-lock-string-face) 11194 11219 (face font-lock-keyword-face) 11219 11220 (face font-lock-string-face) 11220 11232 nil 11232 11233 (face font-lock-string-face) 11233 11245 (face font-lock-keyword-face) 11245 11246 (face font-lock-string-face) 11246 11260 nil 11260 11261 (face font-lock-string-face) 11261 11263 (face font-lock-constant-face) 11263 11264 (face font-lock-string-face) 11264 11292 nil 11292 11293 (face font-lock-string-face) 11293 11303 (face font-lock-keyword-face) 11303 11304 (face font-lock-string-face) 11304 11316 nil 11316 11381 (face font-lock-comment-face) 11381 11389 nil 11389 11439 (face font-lock-comment-face) 11439 11448 nil 11448 11449 (face font-lock-string-face) 11449 11464 (face font-lock-variable-name-face) 11464 11465 (face font-lock-string-face) 11465 11479 nil 11479 11480 (face font-lock-string-face) 11480 11492 (face font-lock-keyword-face) 11492 11493 (face font-lock-string-face) 11493 11509 nil 11509 11510 (face font-lock-string-face) 11510 11549 (face font-lock-function-name-face) 11549 11550 (face font-lock-string-face) 11550 11586 nil 11586 11587 (face font-lock-string-face) 11587 11602 (face font-lock-variable-name-face) 11602 11603 (face font-lock-string-face) 11603 11617 nil 11617 11618 (face font-lock-string-face) 11618 11626 (face font-lock-keyword-face) 11626 11627 (face font-lock-string-face) 11627 11643 nil 11643 11644 (face font-lock-string-face) 11644 11663 (face font-lock-constant-face) 11663 11664 (face font-lock-string-face) 11664 11678 nil 11678 11679 (face font-lock-string-face) 11679 11702 (face font-lock-constant-face) 11702 11703 (face font-lock-string-face) 11703 11717 nil 11717 11718 (face font-lock-string-face) 11718 11740 (face font-lock-constant-face) 11740 11741 (face font-lock-string-face) 11741 11755 nil 11755 11756 (face font-lock-string-face) 11756 11779 (face font-lock-constant-face) 11779 11780 (face font-lock-string-face) 11780 11794 nil 11794 11795 (face font-lock-string-face) 11795 11817 (face font-lock-constant-face) 11817 11818 (face font-lock-string-face) 11818 11832 nil 11832 11833 (face font-lock-string-face) 11833 11861 (face font-lock-constant-face) 11861 11862 (face font-lock-string-face) 11862 11876 nil 11876 11877 (face font-lock-string-face) 11877 11904 (face font-lock-constant-face) 11904 11905 (face font-lock-string-face) 11905 11919 nil 11919 11920 (face font-lock-string-face) 11920 11950 (face font-lock-constant-face) 11950 11951 (face font-lock-string-face) 11951 11965 nil 11965 11966 (face font-lock-string-face) 11966 11995 (face font-lock-constant-face) 11995 11996 (face font-lock-string-face) 11996 12010 nil 12010 12011 (face font-lock-string-face) 12011 12035 (face font-lock-constant-face) 12035 12036 (face font-lock-string-face) 12036 12050 nil 12050 12051 (face font-lock-string-face) 12051 12074 (face font-lock-constant-face) 12074 12075 (face font-lock-string-face) 12075 12089 nil 12089 12090 (face font-lock-string-face) 12090 12120 (face font-lock-constant-face) 12120 12121 (face font-lock-string-face) 12121 12135 nil 12135 12136 (face font-lock-string-face) 12136 12167 (face font-lock-constant-face) 12167 12168 (face font-lock-string-face) 12168 12182 nil 12182 12183 (face font-lock-string-face) 12183 12213 (face font-lock-constant-face) 12213 12214 (face font-lock-string-face) 12214 12228 nil 12228 12229 (face font-lock-string-face) 12229 12254 (face font-lock-constant-face) 12254 12255 (face font-lock-string-face) 12255 12269 nil 12269 12270 (face font-lock-string-face) 12270 12294 (face font-lock-constant-face) 12294 12295 (face font-lock-string-face) 12295 12309 nil 12309 12310 (face font-lock-string-face) 12310 12352 (face font-lock-constant-face) 12352 12353 (face font-lock-string-face) 12353 12367 nil 12367 12368 (face font-lock-string-face) 12368 12409 (face font-lock-constant-face) 12409 12410 (face font-lock-string-face) 12410 12424 nil 12424 12425 (face font-lock-string-face) 12425 12447 (face font-lock-constant-face) 12447 12448 (face font-lock-string-face) 12448 12462 nil 12462 12463 (face font-lock-string-face) 12463 12484 (face font-lock-constant-face) 12484 12485 (face font-lock-string-face) 12485 12499 nil 12499 12500 (face font-lock-string-face) 12500 12531 (face font-lock-constant-face) 12531 12532 (face font-lock-string-face) 12532 12546 nil 12546 12547 (face font-lock-string-face) 12547 12577 (face font-lock-constant-face) 12577 12578 (face font-lock-string-face) 12578 12592 nil 12592 12593 (face font-lock-string-face) 12593 12621 (face font-lock-constant-face) 12621 12622 (face font-lock-string-face) 12622 12636 nil 12636 12637 (face font-lock-string-face) 12637 12664 (face font-lock-constant-face) 12664 12665 (face font-lock-string-face) 12665 12679 nil 12679 12680 (face font-lock-string-face) 12680 12707 (face font-lock-constant-face) 12707 12708 (face font-lock-string-face) 12708 12722 nil 12722 12723 (face font-lock-string-face) 12723 12749 (face font-lock-constant-face) 12749 12750 (face font-lock-string-face) 12750 12764 nil 12764 12765 (face font-lock-string-face) 12765 12791 (face font-lock-constant-face) 12791 12792 (face font-lock-string-face) 12792 12806 nil 12806 12807 (face font-lock-string-face) 12807 12832 (face font-lock-constant-face) 12832 12833 (face font-lock-string-face) 12833 12868 nil 12868 12937 (face font-lock-comment-face) 12937 12945 nil 12945 13016 (face font-lock-comment-face) 13016 13024 nil 13024 13040 (face font-lock-comment-face) 13040 13049 nil 13049 13050 (face font-lock-string-face) 13050 13065 (face font-lock-variable-name-face) 13065 13066 (face font-lock-string-face) 13066 13080 nil 13080 13081 (face font-lock-string-face) 13081 13089 (face font-lock-keyword-face) 13089 13090 (face font-lock-string-face) 13090 13105 nil 13105 13106 (face font-lock-string-face) 13106 13149 (face font-lock-constant-face) 13149 13150 (face font-lock-string-face) 13150 13175 nil 13175 13176 (face font-lock-string-face) 13176 13183 (face font-lock-keyword-face) 13183 13184 (face font-lock-string-face) 13184 13199 nil 13199 13200 (face font-lock-string-face) 13200 13248 (face font-lock-constant-face) 13248 13249 (face font-lock-string-face) 13249 13274 nil 13274 13275 (face font-lock-string-face) 13275 13288 (face font-lock-keyword-face) 13288 13289 (face font-lock-string-face) 13289 13305 nil 13305 13306 (face font-lock-string-face) 13306 13315 (face font-lock-keyword-face) 13315 13316 (face font-lock-string-face) 13316 13334 nil 13334 13335 (face font-lock-string-face) 13335 13345 (face font-lock-constant-face) 13345 13346 (face font-lock-string-face) 13346 13397 nil 13397 13398 (face font-lock-string-face) 13398 13443 (face font-lock-variable-name-face) 13443 13444 (face font-lock-string-face) 13444 13458 nil 13458 13459 (face font-lock-string-face) 13459 13472 (face font-lock-keyword-face) 13472 13473 (face font-lock-string-face) 13473 13489 nil 13489 13490 (face font-lock-string-face) 13490 13499 (face font-lock-keyword-face) 13499 13500 (face font-lock-string-face) 13500 13518 nil 13518 13519 (face font-lock-string-face) 13519 13527 (face font-lock-constant-face) 13527 13528 (face font-lock-string-face) 13528 13579 nil 13579 13580 (face font-lock-string-face) 13580 13593 (face font-lock-variable-name-face) 13593 13594 (face font-lock-string-face) 13594 13608 nil 13608 13609 (face font-lock-string-face) 13609 13617 (face font-lock-keyword-face) 13617 13618 (face font-lock-string-face) 13618 13623 nil 13623 13624 (face font-lock-string-face) 13624 13631 (face font-lock-constant-face) 13631 13632 (face font-lock-string-face) 13632 13634 nil 13634 13635 (face font-lock-string-face) 13635 13641 (face font-lock-constant-face) 13641 13642 (face font-lock-string-face) 13642 13671 nil 13671 13672 (face font-lock-string-face) 13672 13679 (face font-lock-constant-face) 13679 13680 (face font-lock-string-face) 13680 13682 nil 13682 13683 (face font-lock-string-face) 13683 13703 (face font-lock-constant-face) 13703 13704 (face font-lock-string-face) 13704 13720 nil 13720 13721 (face font-lock-string-face) 13721 13734 (face font-lock-keyword-face) 13734 13735 (face font-lock-string-face) 13735 13751 nil 13751 13752 (face font-lock-string-face) 13752 13761 (face font-lock-keyword-face) 13761 13762 (face font-lock-string-face) 13762 13815 nil 13815 13816 (face font-lock-string-face) 13816 13829 (face font-lock-variable-name-face) 13829 13830 (face font-lock-string-face) 13830 13844 nil 13844 13845 (face font-lock-string-face) 13845 13853 (face font-lock-keyword-face) 13853 13854 (face font-lock-string-face) 13854 13870 nil 13870 13871 (face font-lock-string-face) 13871 13909 (face font-lock-constant-face) 13909 13910 (face font-lock-string-face) 13910 13924 nil 13924 13925 (face font-lock-string-face) 13925 13962 (face font-lock-constant-face) 13962 13963 (face font-lock-string-face) 13963 13999 nil 13999 14000 (face font-lock-string-face) 14000 14011 (face font-lock-variable-name-face) 14011 14012 (face font-lock-string-face) 14012 14026 nil 14026 14027 (face font-lock-string-face) 14027 14036 (face font-lock-keyword-face) 14036 14037 (face font-lock-string-face) 14037 14053 nil 14053 14054 (face font-lock-string-face) 14054 14064 (face font-lock-keyword-face) 14064 14065 (face font-lock-string-face) 14065 14084 nil 14084 14085 (face font-lock-string-face) 14085 14096 (face font-lock-variable-name-face) 14096 14097 (face font-lock-string-face) 14097 14117 nil 14117 14129 (face font-lock-string-face) 14129 14131 nil 14131 14169 (face font-lock-string-face) 14169 14176 (face font-lock-variable-name-face) 14176 14182 (face font-lock-string-face) 14182 14193 (face font-lock-variable-name-face) 14193 14196 (face font-lock-string-face) 14196 14233 nil 14233 14245 (face font-lock-string-face) 14245 14247 nil 14247 14259 (face font-lock-string-face) 14259 14316 nil 14316 14317 (face font-lock-string-face) 14317 14327 (face font-lock-keyword-face) 14327 14328 (face font-lock-string-face) 14328 14345 nil 14345 14346 (face font-lock-string-face) 14346 14359 (face font-lock-variable-name-face) 14359 14360 (face font-lock-string-face) 14360 14378 nil 14378 14379 (face font-lock-string-face) 14379 14385 (face font-lock-keyword-face) 14385 14386 (face font-lock-string-face) 14386 14406 nil 14406 14411 (face font-lock-string-face) 14411 14413 (face font-lock-variable-name-face) 14413 14423 (face font-lock-variable-name-face) 14423 14443 (face font-lock-string-face) 14443 14476 nil 14476 14477 (face font-lock-string-face) 14477 14490 (face font-lock-keyword-face) 14490 14491 (face font-lock-string-face) 14491 14511 nil 14511 14512 (face font-lock-string-face) 14512 14521 (face font-lock-keyword-face) 14521 14522 (face font-lock-string-face) 14522 14544 nil 14544 14545 (face font-lock-string-face) 14545 14549 (face font-lock-constant-face) 14549 14551 (face font-lock-variable-name-face) 14551 14561 (face font-lock-variable-name-face) 14561 14578 (face font-lock-constant-face) 14578 14579 (face font-lock-string-face) 14579 14631 nil 14631 14632 (face font-lock-string-face) 14632 14639 (face font-lock-keyword-face) 14639 14640 (face font-lock-string-face) 14640 14660 nil 14660 14661 (face font-lock-string-face) 14661 14669 (face font-lock-preprocessor-face) 14669 14670 (face font-lock-string-face) 14670 14707 nil 14707 14729 (face font-lock-comment-face) 14729 14743 nil 14743 14744 (face font-lock-string-face) 14744 14752 (face font-lock-keyword-face) 14752 14753 (face font-lock-string-face) 14753 14773 nil 14773 14774 (face font-lock-string-face) 14774 14800 (face font-lock-constant-face) 14800 14801 (face font-lock-string-face) 14801 14819 nil 14819 14820 (face font-lock-string-face) 14820 14845 (face font-lock-constant-face) 14845 14846 (face font-lock-string-face) 14846 14915 nil 14915 14916 (face font-lock-string-face) 14916 14929 (face font-lock-variable-name-face) 14929 14930 (face font-lock-string-face) 14930 14944 nil 14944 14945 (face font-lock-string-face) 14945 14955 (face font-lock-keyword-face) 14955 14956 (face font-lock-string-face) 14956 14973 nil 14973 14974 (face font-lock-string-face) 14974 14993 (face font-lock-variable-name-face) 14993 14994 (face font-lock-string-face) 14994 15012 nil 15012 15013 (face font-lock-string-face) 15013 15019 (face font-lock-keyword-face) 15019 15020 (face font-lock-string-face) 15020 15040 nil 15040 15075 (face font-lock-string-face) 15075 15108 nil 15108 15109 (face font-lock-string-face) 15109 15122 (face font-lock-keyword-face) 15122 15123 (face font-lock-string-face) 15123 15143 nil 15143 15144 (face font-lock-string-face) 15144 15153 (face font-lock-keyword-face) 15153 15154 (face font-lock-string-face) 15154 15176 nil 15176 15177 (face font-lock-string-face) 15177 15215 (face font-lock-constant-face) 15215 15216 (face font-lock-string-face) 15216 15268 nil 15268 15269 (face font-lock-string-face) 15269 15276 (face font-lock-keyword-face) 15276 15277 (face font-lock-string-face) 15277 15297 nil 15297 15298 (face font-lock-string-face) 15298 15312 (face font-lock-preprocessor-face) 15312 15313 (face font-lock-string-face) 15313 15350 nil 15350 15378 (face font-lock-comment-face) 15378 15392 nil 15392 15393 (face font-lock-string-face) 15393 15401 (face font-lock-keyword-face) 15401 15402 (face font-lock-string-face) 15402 15422 nil 15422 15423 (face font-lock-string-face) 15423 15450 (face font-lock-constant-face) 15450 15451 (face font-lock-string-face) 15451 15469 nil 15469 15470 (face font-lock-string-face) 15470 15496 (face font-lock-constant-face) 15496 15497 (face font-lock-string-face) 15497 15566 nil 15566 15567 (face font-lock-string-face) 15567 15600 (face font-lock-variable-name-face) 15600 15601 (face font-lock-string-face) 15601 15615 nil 15615 15663 (face font-lock-comment-face) 15663 15673 nil 15673 15674 (face font-lock-string-face) 15674 15682 (face font-lock-keyword-face) 15682 15683 (face font-lock-string-face) 15683 15699 nil 15699 15700 (face font-lock-string-face) 15700 15743 (face font-lock-constant-face) 15743 15744 (face font-lock-string-face) 15744 15758 nil 15758 15759 (face font-lock-string-face) 15759 15801 (face font-lock-constant-face) 15801 15802 (face font-lock-string-face) 15802 15838 nil 15838 15839 (face font-lock-string-face) 15839 15848 (face font-lock-variable-name-face) 15848 15849 (face font-lock-string-face) 15849 15863 nil 15863 15864 (face font-lock-string-face) 15864 15877 (face font-lock-keyword-face) 15877 15878 (face font-lock-string-face) 15878 15894 nil 15894 15895 (face font-lock-string-face) 15895 15904 (face font-lock-keyword-face) 15904 15905 (face font-lock-string-face) 15905 15923 nil 15923 15924 (face font-lock-string-face) 15924 15980 (face font-lock-constant-face) 15980 15981 (face font-lock-string-face) 15981 15997 nil 15997 15998 (face font-lock-string-face) 15998 16057 (face font-lock-constant-face) 16057 16058 (face font-lock-string-face) 16058 16074 nil 16074 16075 (face font-lock-string-face) 16075 16131 (face font-lock-constant-face) 16131 16132 (face font-lock-string-face) 16132 16148 nil 16148 16149 (face font-lock-string-face) 16149 16205 (face font-lock-constant-face) 16205 16206 (face font-lock-string-face) 16206 16222 nil 16222 16223 (face font-lock-string-face) 16223 16275 (face font-lock-constant-face) 16275 16276 (face font-lock-string-face) 16276 16327 nil 16327 16328 (face font-lock-string-face) 16328 16337 (face font-lock-variable-name-face) 16337 16338 (face font-lock-string-face) 16338 16352 nil 16352 16353 (face font-lock-string-face) 16353 16361 (face font-lock-keyword-face) 16361 16362 (face font-lock-string-face) 16362 16378 nil 16378 16379 (face font-lock-string-face) 16379 16406 (face font-lock-constant-face) 16406 16407 (face font-lock-string-face) 16407 16421 nil 16421 16422 (face font-lock-string-face) 16422 16448 (face font-lock-constant-face) 16448 16449 (face font-lock-string-face) 16449 16463 nil 16463 16464 (face font-lock-string-face) 16464 16507 (face font-lock-constant-face) 16507 16508 (face font-lock-string-face) 16508 16522 nil 16522 16523 (face font-lock-string-face) 16523 16565 (face font-lock-constant-face) 16565 16566 (face font-lock-string-face) 16566 16602 nil 16602 16603 (face font-lock-string-face) 16603 16646 (face font-lock-variable-name-face) 16646 16647 (face font-lock-string-face) 16647 16661 nil 16661 16662 (face font-lock-string-face) 16662 16669 (face font-lock-keyword-face) 16669 16670 (face font-lock-string-face) 16670 16686 nil 16686 16687 (face font-lock-string-face) 16687 16697 (face font-lock-constant-face) 16697 16698 (face font-lock-string-face) 16698 16712 nil 16712 16713 (face font-lock-string-face) 16713 16722 (face font-lock-constant-face) 16722 16723 (face font-lock-string-face) 16723 16737 nil 16737 16738 (face font-lock-string-face) 16738 16760 (face font-lock-constant-face) 16760 16761 (face font-lock-string-face) 16761 16775 nil 16775 16776 (face font-lock-string-face) 16776 16797 (face font-lock-constant-face) 16797 16798 (face font-lock-string-face) 16798 16812 nil 16812 16813 (face font-lock-string-face) 16813 16830 (face font-lock-constant-face) 16830 16831 (face font-lock-string-face) 16831 16845 nil 16845 16846 (face font-lock-string-face) 16846 16862 (face font-lock-constant-face) 16862 16863 (face font-lock-string-face) 16863 16877 nil 16877 16878 (face font-lock-string-face) 16878 16889 (face font-lock-constant-face) 16889 16890 (face font-lock-string-face) 16890 16904 nil 16904 16905 (face font-lock-string-face) 16905 16915 (face font-lock-constant-face) 16915 16916 (face font-lock-string-face) 16916 16930 nil 16930 16931 (face font-lock-string-face) 16931 16955 (face font-lock-constant-face) 16955 16956 (face font-lock-string-face) 16956 16970 nil 16970 16971 (face font-lock-string-face) 16971 16994 (face font-lock-constant-face) 16994 16995 (face font-lock-string-face) 16995 17009 nil 17009 17010 (face font-lock-string-face) 17010 17034 (face font-lock-constant-face) 17034 17035 (face font-lock-string-face) 17035 17049 nil 17049 17050 (face font-lock-string-face) 17050 17073 (face font-lock-constant-face) 17073 17074 (face font-lock-string-face) 17074 17088 nil 17088 17089 (face font-lock-string-face) 17089 17114 (face font-lock-constant-face) 17114 17115 (face font-lock-string-face) 17115 17129 nil 17129 17130 (face font-lock-string-face) 17130 17154 (face font-lock-constant-face) 17154 17155 (face font-lock-string-face) 17155 17210 nil 17210 17211 (face font-lock-string-face) 17211 17222 (face font-lock-keyword-face) 17222 17223 (face font-lock-string-face) 17223 17225 nil 17225 17226 (face font-lock-string-face) 17226 17237 (face font-lock-function-name-face) 17237 17238 (face font-lock-string-face) 17238 17246 nil 17246 17247 (face font-lock-string-face) 17247 17251 (face font-lock-keyword-face) 17251 17252 (face font-lock-string-face) 17252 17254 nil 17254 17255 (face font-lock-string-face) 17255 17269 (face font-lock-type-face) 17269 17270 (face font-lock-string-face) 17270 17278 nil 17278 17279 (face font-lock-string-face) 17279 17291 (face font-lock-keyword-face) 17291 17292 (face font-lock-string-face) 17292 17304 nil 17304 17305 (face font-lock-string-face) 17305 17307 (face font-lock-constant-face) 17307 17308 (face font-lock-string-face) 17308 17325 nil 17325 17326 (face font-lock-string-face) 17326 17336 (face font-lock-keyword-face) 17336 17337 (face font-lock-string-face) 17337 17350 nil 17350 17351 (face font-lock-string-face) 17351 17371 (face font-lock-variable-name-face) 17371 17372 (face font-lock-string-face) 17372 17386 nil 17386 17387 (face font-lock-string-face) 17387 17404 (face font-lock-keyword-face) 17404 17405 (face font-lock-string-face) 17405 17423 nil 17423 17424 (face font-lock-string-face) 17424 17442 (face font-lock-variable-name-face) 17442 17443 (face font-lock-string-face) 17443 17461 nil 17461 17462 (face font-lock-string-face) 17462 17469 (face font-lock-keyword-face) 17469 17470 (face font-lock-string-face) 17470 17474 nil 17474 17498 (face font-lock-string-face) 17498 17553 nil 17553 17554 (face font-lock-string-face) 17554 17599 (face font-lock-variable-name-face) 17599 17600 (face font-lock-string-face) 17600 17614 nil 17614 17615 (face font-lock-string-face) 17615 17627 (face font-lock-keyword-face) 17627 17628 (face font-lock-string-face) 17628 17644 nil 17644 17645 (face font-lock-string-face) 17645 17665 (face font-lock-function-name-face) 17665 17666 (face font-lock-string-face) 17666 17703 nil 17703 17704 (face font-lock-string-face) 17704 17724 (face font-lock-variable-name-face) 17724 17725 (face font-lock-string-face) 17725 17739 nil 17739 17740 (face font-lock-string-face) 17740 17752 (face font-lock-keyword-face) 17752 17753 (face font-lock-string-face) 17753 17769 nil 17769 17770 (face font-lock-string-face) 17770 17790 (face font-lock-function-name-face) 17790 17791 (face font-lock-string-face) 17791 17833 nil 17833 17834 (face font-lock-string-face) 17834 17841 (face font-lock-keyword-face) 17841 17842 (face font-lock-string-face) 17842 17854 nil 17854 17855 (face font-lock-string-face) 17855 17874 (face font-lock-constant-face) 17874 17875 (face font-lock-string-face) 17875 17885 nil 17885 17886 (face font-lock-string-face) 17886 17904 (face font-lock-constant-face) 17904 17905 (face font-lock-string-face) 17905 17935 nil 17935 17936 (face font-lock-string-face) 17936 17947 (face font-lock-keyword-face) 17947 17948 (face font-lock-string-face) 17948 17950 nil 17950 17951 (face font-lock-string-face) 17951 17971 (face font-lock-function-name-face) 17971 17972 (face font-lock-string-face) 17972 17980 nil 17980 17981 (face font-lock-string-face) 17981 17985 (face font-lock-keyword-face) 17985 17986 (face font-lock-string-face) 17986 17988 nil 17988 17989 (face font-lock-string-face) 17989 18003 (face font-lock-type-face) 18003 18004 (face font-lock-string-face) 18004 18012 nil 18012 18013 (face font-lock-string-face) 18013 18025 (face font-lock-keyword-face) 18025 18026 (face font-lock-string-face) 18026 18038 nil 18038 18039 (face font-lock-string-face) 18039 18041 (face font-lock-constant-face) 18041 18042 (face font-lock-string-face) 18042 18059 nil 18059 18060 (face font-lock-string-face) 18060 18067 (face font-lock-keyword-face) 18067 18068 (face font-lock-string-face) 18068 18080 nil 18080 18081 (face font-lock-string-face) 18081 18114 (face font-lock-constant-face) 18114 18115 (face font-lock-string-face) 18115 18125 nil 18125 18126 (face font-lock-string-face) 18126 18162 (face font-lock-constant-face) 18162 18163 (face font-lock-string-face) 18163 18173 nil 18173 18174 (face font-lock-string-face) 18174 18212 (face font-lock-constant-face) 18212 18213 (face font-lock-string-face) 18213 18223 nil 18223 18224 (face font-lock-string-face) 18224 18261 (face font-lock-constant-face) 18261 18262 (face font-lock-string-face) 18262 18272 nil 18272 18273 (face font-lock-string-face) 18273 18311 (face font-lock-constant-face) 18311 18312 (face font-lock-string-face) 18312 18322 nil 18322 18323 (face font-lock-string-face) 18323 18356 (face font-lock-constant-face) 18356 18357 (face font-lock-string-face) 18357 18367 nil 18367 18368 (face font-lock-string-face) 18368 18403 (face font-lock-constant-face) 18403 18404 (face font-lock-string-face) 18404 18414 nil 18414 18415 (face font-lock-string-face) 18415 18451 (face font-lock-constant-face) 18451 18452 (face font-lock-string-face) 18452 18462 nil 18462 18463 (face font-lock-string-face) 18463 18499 (face font-lock-constant-face) 18499 18500 (face font-lock-string-face) 18500 18510 nil 18510 18511 (face font-lock-string-face) 18511 18547 (face font-lock-constant-face) 18547 18548 (face font-lock-string-face) 18548 18558 nil 18558 18559 (face font-lock-string-face) 18559 18581 (face font-lock-constant-face) 18581 18582 (face font-lock-string-face) 18582 18592 nil 18592 18593 (face font-lock-string-face) 18593 18618 (face font-lock-constant-face) 18618 18619 (face font-lock-string-face) 18619 18629 nil 18629 18630 (face font-lock-string-face) 18630 18657 (face font-lock-constant-face) 18657 18658 (face font-lock-string-face) 18658 18668 nil 18668 18669 (face font-lock-string-face) 18669 18697 (face font-lock-constant-face) 18697 18698 (face font-lock-string-face) 18698 18708 nil 18708 18709 (face font-lock-string-face) 18709 18750 (face font-lock-constant-face) 18750 18751 (face font-lock-string-face) 18751 18761 nil 18761 18762 (face font-lock-string-face) 18762 18803 (face font-lock-constant-face) 18803 18804 (face font-lock-string-face) 18804 18814 nil 18814 18815 (face font-lock-string-face) 18815 18856 (face font-lock-constant-face) 18856 18857 (face font-lock-string-face) 18857 18867 nil 18867 18868 (face font-lock-string-face) 18868 18902 (face font-lock-constant-face) 18902 18903 (face font-lock-string-face) 18903 18913 nil 18913 18914 (face font-lock-string-face) 18914 18948 (face font-lock-constant-face) 18948 18949 (face font-lock-string-face) 18949 18959 nil 18959 18960 (face font-lock-string-face) 18960 18994 (face font-lock-constant-face) 18994 18995 (face font-lock-string-face) 18995 19005 nil 19005 19006 (face font-lock-string-face) 19006 19035 (face font-lock-constant-face) 19035 19036 (face font-lock-string-face) 19036 19046 nil 19046 19047 (face font-lock-string-face) 19047 19075 (face font-lock-constant-face) 19075 19076 (face font-lock-string-face) 19076 19093 nil 19093 19094 (face font-lock-string-face) 19094 19104 (face font-lock-keyword-face) 19104 19105 (face font-lock-string-face) 19105 19118 nil 19118 19119 (face font-lock-string-face) 19119 19139 (face font-lock-variable-name-face) 19139 19140 (face font-lock-string-face) 19140 19154 nil 19154 19155 (face font-lock-string-face) 19155 19172 (face font-lock-keyword-face) 19172 19173 (face font-lock-string-face) 19173 19191 nil 19191 19192 (face font-lock-string-face) 19192 19210 (face font-lock-variable-name-face) 19210 19211 (face font-lock-string-face) 19211 19229 nil 19229 19230 (face font-lock-string-face) 19230 19237 (face font-lock-keyword-face) 19237 19238 (face font-lock-string-face) 19238 19242 nil 19242 19266 (face font-lock-string-face) 19266 19321 nil 19321 19322 (face font-lock-string-face) 19322 19342 (face font-lock-variable-name-face) 19342 19343 (face font-lock-string-face) 19343 19357 nil 19357 19399 (face font-lock-comment-face) 19399 19409 nil 19409 19410 (face font-lock-string-face) 19410 19417 (face font-lock-keyword-face) 19417 19418 (face font-lock-string-face) 19418 19434 nil 19434 19435 (face font-lock-string-face) 19435 19480 (face font-lock-constant-face) 19480 19481 (face font-lock-string-face) 19481 19495 nil 19495 19496 (face font-lock-string-face) 19496 19535 (face font-lock-constant-face) 19535 19536 (face font-lock-string-face) 19536 19573 nil 19573 19574 (face font-lock-string-face) 19574 19623 (face font-lock-variable-name-face) 19623 19624 (face font-lock-string-face) 19624 19638 nil 19638 19639 (face font-lock-string-face) 19639 19645 (face font-lock-keyword-face) 19645 19646 (face font-lock-string-face) 19646 19662 nil 19662 19670 (face font-lock-string-face) 19670 19707 nil 19707 19708 (face font-lock-string-face) 19708 19719 (face font-lock-variable-name-face) 19719 19720 (face font-lock-string-face) 19720 19734 nil 19734 19735 (face font-lock-string-face) 19735 19749 (face font-lock-keyword-face) 19749 19750 (face font-lock-string-face) 19750 19766 nil 19766 19773 (face font-lock-string-face) 19773 19791 nil 19791 19792 (face font-lock-string-face) 19792 19806 (face font-lock-keyword-face) 19806 19807 (face font-lock-string-face) 19807 19827 nil 19827 19890 (face font-lock-comment-face) 19890 19906 nil 19906 19971 (face font-lock-comment-face) 19971 19987 nil 19987 20032 (face font-lock-comment-face) 20032 20048 nil 20048 20072 (face font-lock-string-face) 20072 20074 nil 20074 20077 (face font-lock-string-face) 20077 20080 nil 20080 20086 (face font-lock-comment-face) 20086 20155 nil 20155 20156 (face font-lock-string-face) 20156 20165 (face font-lock-variable-name-face) 20165 20166 (face font-lock-string-face) 20166 20180 nil 20180 20181 (face font-lock-string-face) 20181 20190 (face font-lock-keyword-face) 20190 20191 (face font-lock-string-face) 20191 20207 nil 20207 20208 (face font-lock-string-face) 20208 20218 (face font-lock-variable-name-face) 20218 20219 (face font-lock-string-face) 20219 20237 nil 20237 20246 (face font-lock-string-face) 20246 20262 nil 20262 20270 (face font-lock-string-face) 20270 20286 nil 20286 20298 (face font-lock-string-face) 20298 20314 nil 20314 20322 (face font-lock-string-face) 20322 20374 nil 20374 20375 (face font-lock-string-face) 20375 20384 (face font-lock-variable-name-face) 20384 20385 (face font-lock-string-face) 20385 20399 nil 20399 20400 (face font-lock-string-face) 20400 20409 (face font-lock-keyword-face) 20409 20410 (face font-lock-string-face) 20410 20426 nil 20426 20427 (face font-lock-string-face) 20427 20437 (face font-lock-variable-name-face) 20437 20438 (face font-lock-string-face) 20438 20456 nil 20456 20466 (face font-lock-string-face) 20466 20482 nil 20482 20491 (face font-lock-string-face) 20491 20507 nil 20507 20519 (face font-lock-string-face) 20519 20535 nil 20535 20543 (face font-lock-string-face) 20543 20595 nil 20595 20596 (face font-lock-string-face) 20596 20621 (face font-lock-variable-name-face) 20621 20622 (face font-lock-string-face) 20622 20636 nil 20636 20637 (face font-lock-string-face) 20637 20646 (face font-lock-keyword-face) 20646 20647 (face font-lock-string-face) 20647 20663 nil 20663 20664 (face font-lock-string-face) 20664 20674 (face font-lock-keyword-face) 20674 20675 (face font-lock-string-face) 20675 20695 nil 20695 20696 (face font-lock-string-face) 20696 20715 (face font-lock-variable-name-face) 20715 20716 (face font-lock-string-face) 20716 20736 nil 20736 20748 (face font-lock-string-face) 20748 20770 nil 20770 20780 (face font-lock-string-face) 20780 20800 nil 20800 20807 (face font-lock-string-face) 20807 20827 nil 20827 20839 (face font-lock-string-face) 20839 20859 nil 20859 20867 (face font-lock-string-face) 20867 20923 nil 20923 20935 (face font-lock-string-face) 20935 20957 nil 20957 20972 (face font-lock-string-face) 20972 20992 nil 20992 20999 (face font-lock-string-face) 20999 21019 nil 21019 21026 (face font-lock-string-face) 21026 21046 nil 21046 21058 (face font-lock-string-face) 21058 21078 nil 21078 21086 (face font-lock-string-face) 21086 21180 nil 21180 21181 (face font-lock-string-face) 21181 21190 (face font-lock-keyword-face) 21190 21191 (face font-lock-string-face) 21191 21203 nil 21203 21204 (face font-lock-string-face) 21204 21220 (face font-lock-variable-name-face) 21220 21221 (face font-lock-string-face) 21221 21223 nil 21223 21224 (face font-lock-string-face) 21224 21256 (face font-lock-variable-name-face) 21256 21257 (face font-lock-string-face) 21257 21274 nil 21274 21314 (face font-lock-string-face) 21314 21325 nil 21325 21326 (face font-lock-string-face) 21326 21334 (face font-lock-keyword-face) 21334 21335 (face font-lock-string-face) 21335 21347 nil 21347 21348 (face font-lock-string-face) 21348 21385 (face font-lock-constant-face) 21385 21386 (face font-lock-string-face) 21386 21416 nil 21416 21417 (face font-lock-string-face) 21417 21428 (face font-lock-keyword-face) 21428 21429 (face font-lock-string-face) 21429 21431 nil 21431 21432 (face font-lock-string-face) 21432 21452 (face font-lock-function-name-face) 21452 21453 (face font-lock-string-face) 21453 21461 nil 21461 21462 (face font-lock-string-face) 21462 21466 (face font-lock-keyword-face) 21466 21467 (face font-lock-string-face) 21467 21469 nil 21469 21470 (face font-lock-string-face) 21470 21484 (face font-lock-type-face) 21484 21485 (face font-lock-string-face) 21485 21493 nil 21493 21494 (face font-lock-string-face) 21494 21506 (face font-lock-keyword-face) 21506 21507 (face font-lock-string-face) 21507 21519 nil 21519 21520 (face font-lock-string-face) 21520 21522 (face font-lock-constant-face) 21522 21523 (face font-lock-string-face) 21523 21540 nil 21540 21541 (face font-lock-string-face) 21541 21548 (face font-lock-keyword-face) 21548 21549 (face font-lock-string-face) 21549 21561 nil 21561 21562 (face font-lock-string-face) 21562 21595 (face font-lock-constant-face) 21595 21596 (face font-lock-string-face) 21596 21606 nil 21606 21607 (face font-lock-string-face) 21607 21637 (face font-lock-constant-face) 21637 21638 (face font-lock-string-face) 21638 21648 nil 21648 21649 (face font-lock-string-face) 21649 21682 (face font-lock-constant-face) 21682 21683 (face font-lock-string-face) 21683 21693 nil 21693 21694 (face font-lock-string-face) 21694 21724 (face font-lock-constant-face) 21724 21725 (face font-lock-string-face) 21725 21735 nil 21735 21736 (face font-lock-string-face) 21736 21758 (face font-lock-constant-face) 21758 21759 (face font-lock-string-face) 21759 21769 nil 21769 21770 (face font-lock-string-face) 21770 21795 (face font-lock-constant-face) 21795 21796 (face font-lock-string-face) 21796 21806 nil 21806 21807 (face font-lock-string-face) 21807 21836 (face font-lock-constant-face) 21836 21837 (face font-lock-string-face) 21837 21847 nil 21847 21848 (face font-lock-string-face) 21848 21876 (face font-lock-constant-face) 21876 21877 (face font-lock-string-face) 21877 21907 nil 21907 21908 (face font-lock-string-face) 21908 21919 (face font-lock-keyword-face) 21919 21920 (face font-lock-string-face) 21920 21922 nil 21922 21923 (face font-lock-string-face) 21923 21938 (face font-lock-function-name-face) 21938 21939 (face font-lock-string-face) 21939 21947 nil 21947 21948 (face font-lock-string-face) 21948 21952 (face font-lock-keyword-face) 21952 21953 (face font-lock-string-face) 21953 21955 nil 21955 21956 (face font-lock-string-face) 21956 21966 (face font-lock-type-face) 21966 21967 (face font-lock-string-face) 21967 21975 nil 21975 21976 (face font-lock-string-face) 21976 21988 (face font-lock-keyword-face) 21988 21989 (face font-lock-string-face) 21989 22001 nil 22001 22002 (face font-lock-string-face) 22002 22007 (face font-lock-function-name-face) 22007 22008 (face font-lock-string-face) 22008 22018 nil 22018 22019 (face font-lock-string-face) 22019 22037 (face font-lock-function-name-face) 22037 22038 (face font-lock-string-face) 22038 22048 nil 22048 22049 (face font-lock-string-face) 22049 22060 (face font-lock-function-name-face) 22060 22061 (face font-lock-string-face) 22061 22071 nil 22071 22072 (face font-lock-string-face) 22072 22093 (face font-lock-function-name-face) 22093 22094 (face font-lock-string-face) 22094 22104 nil 22104 22105 (face font-lock-string-face) 22105 22131 (face font-lock-function-name-face) 22131 22132 (face font-lock-string-face) 22132 22142 nil 22142 22143 (face font-lock-string-face) 22143 22177 (face font-lock-function-name-face) 22177 22178 (face font-lock-string-face) 22178 22188 nil 22188 22189 (face font-lock-string-face) 22189 22215 (face font-lock-function-name-face) 22215 22216 (face font-lock-string-face) 22216 22226 nil 22226 22227 (face font-lock-string-face) 22227 22253 (face font-lock-function-name-face) 22253 22254 (face font-lock-string-face) 22254 22264 nil 22264 22265 (face font-lock-string-face) 22265 22280 (face font-lock-function-name-face) 22280 22281 (face font-lock-string-face) 22281 22298 nil 22298 22299 (face font-lock-string-face) 22299 22306 (face font-lock-keyword-face) 22306 22307 (face font-lock-string-face) 22307 22319 nil 22319 22320 (face font-lock-string-face) 22320 22361 (face font-lock-constant-face) 22361 22362 (face font-lock-string-face) 22362 22372 nil 22372 22373 (face font-lock-string-face) 22373 22413 (face font-lock-constant-face) 22413 22414 (face font-lock-string-face) 22414 22424 nil 22424 22425 (face font-lock-string-face) 22425 22461 (face font-lock-constant-face) 22461 22462 (face font-lock-string-face) 22462 22472 nil 22472 22473 (face font-lock-string-face) 22473 22502 (face font-lock-constant-face) 22502 22503 (face font-lock-string-face) 22503 22513 nil 22513 22514 (face font-lock-string-face) 22514 22550 (face font-lock-constant-face) 22550 22551 (face font-lock-string-face) 22551 22561 nil 22561 22562 (face font-lock-string-face) 22562 22610 (face font-lock-constant-face) 22610 22611 (face font-lock-string-face) 22611 22621 nil 22621 22622 (face font-lock-string-face) 22622 22663 (face font-lock-constant-face) 22663 22664 (face font-lock-string-face) 22664 22674 nil 22674 22675 (face font-lock-string-face) 22675 22711 (face font-lock-constant-face) 22711 22712 (face font-lock-string-face) 22712 22722 nil 22722 22723 (face font-lock-string-face) 22723 22757 (face font-lock-constant-face) 22757 22758 (face font-lock-string-face) 22758 22768 nil 22768 22769 (face font-lock-string-face) 22769 22797 (face font-lock-constant-face) 22797 22798 (face font-lock-string-face) 22798 22808 nil 22808 22809 (face font-lock-string-face) 22809 22853 (face font-lock-constant-face) 22853 22854 (face font-lock-string-face) 22854 22864 nil 22864 22865 (face font-lock-string-face) 22865 22900 (face font-lock-constant-face) 22900 22901 (face font-lock-string-face) 22901 22911 nil 22911 22912 (face font-lock-string-face) 22912 22961 (face font-lock-constant-face) 22961 22962 (face font-lock-string-face) 22962 22972 nil 22972 22973 (face font-lock-string-face) 22973 23011 (face font-lock-constant-face) 23011 23012 (face font-lock-string-face) 23012 23022 nil 23022 23023 (face font-lock-string-face) 23023 23055 (face font-lock-constant-face) 23055 23056 (face font-lock-string-face) 23056 23066 nil 23066 23067 (face font-lock-string-face) 23067 23116 (face font-lock-constant-face) 23116 23117 (face font-lock-string-face) 23117 23127 nil 23127 23128 (face font-lock-string-face) 23128 23178 (face font-lock-constant-face) 23178 23179 (face font-lock-string-face) 23179 23189 nil 23189 23190 (face font-lock-string-face) 23190 23228 (face font-lock-constant-face) 23228 23229 (face font-lock-string-face) 23229 23239 nil 23239 23240 (face font-lock-string-face) 23240 23277 (face font-lock-constant-face) 23277 23278 (face font-lock-string-face) 23278 23288 nil 23288 23289 (face font-lock-string-face) 23289 23332 (face font-lock-constant-face) 23332 23333 (face font-lock-string-face) 23333 23343 nil 23343 23344 (face font-lock-string-face) 23344 23368 (face font-lock-constant-face) 23368 23369 (face font-lock-string-face) 23369 23379 nil 23379 23380 (face font-lock-string-face) 23380 23402 (face font-lock-constant-face) 23402 23403 (face font-lock-string-face) 23403 23413 nil 23413 23414 (face font-lock-string-face) 23414 23447 (face font-lock-constant-face) 23447 23448 (face font-lock-string-face) 23448 23458 nil 23458 23459 (face font-lock-string-face) 23459 23487 (face font-lock-constant-face) 23487 23488 (face font-lock-string-face) 23488 23498 nil 23498 23499 (face font-lock-string-face) 23499 23530 (face font-lock-constant-face) 23530 23531 (face font-lock-string-face) 23531 23541 nil 23541 23542 (face font-lock-string-face) 23542 23563 (face font-lock-constant-face) 23563 23564 (face font-lock-string-face) 23564 23574 nil 23574 23575 (face font-lock-string-face) 23575 23609 (face font-lock-constant-face) 23609 23610 (face font-lock-string-face) 23610 23620 nil 23620 23621 (face font-lock-string-face) 23621 23654 (face font-lock-constant-face) 23654 23655 (face font-lock-string-face) 23655 23665 nil 23665 23666 (face font-lock-string-face) 23666 23700 (face font-lock-constant-face) 23700 23701 (face font-lock-string-face) 23701 23711 nil 23711 23712 (face font-lock-string-face) 23712 23753 (face font-lock-constant-face) 23753 23754 (face font-lock-string-face) 23754 23764 nil 23764 23765 (face font-lock-string-face) 23765 23790 (face font-lock-constant-face) 23790 23791 (face font-lock-string-face) 23791 23801 nil 23801 23802 (face font-lock-string-face) 23802 23825 (face font-lock-constant-face) 23825 23826 (face font-lock-string-face) 23826 23836 nil 23836 23837 (face font-lock-string-face) 23837 23862 (face font-lock-constant-face) 23862 23863 (face font-lock-string-face) 23863 23873 nil 23873 23874 (face font-lock-string-face) 23874 23906 (face font-lock-constant-face) 23906 23907 (face font-lock-string-face) 23907 23917 nil 23917 23918 (face font-lock-string-face) 23918 23947 (face font-lock-constant-face) 23947 23948 (face font-lock-string-face) 23948 23958 nil 23958 23959 (face font-lock-string-face) 23959 23981 (face font-lock-constant-face) 23981 23982 (face font-lock-string-face) 23982 23992 nil 23992 23993 (face font-lock-string-face) 23993 24014 (face font-lock-constant-face) 24014 24015 (face font-lock-string-face) 24015 24025 nil 24025 24026 (face font-lock-string-face) 24026 24054 (face font-lock-constant-face) 24054 24055 (face font-lock-string-face) 24055 24065 nil 24065 24066 (face font-lock-string-face) 24066 24093 (face font-lock-constant-face) 24093 24094 (face font-lock-string-face) 24094 24104 nil 24104 24105 (face font-lock-string-face) 24105 24133 (face font-lock-constant-face) 24133 24134 (face font-lock-string-face) 24134 24144 nil 24144 24145 (face font-lock-string-face) 24145 24177 (face font-lock-constant-face) 24177 24178 (face font-lock-string-face) 24178 24188 nil 24188 24189 (face font-lock-string-face) 24189 24221 (face font-lock-constant-face) 24221 24222 (face font-lock-string-face) 24222 24232 nil 24232 24233 (face font-lock-string-face) 24233 24277 (face font-lock-constant-face) 24277 24278 (face font-lock-string-face) 24278 24288 nil 24288 24289 (face font-lock-string-face) 24289 24328 (face font-lock-constant-face) 24328 24329 (face font-lock-string-face) 24329 24339 nil 24339 24340 (face font-lock-string-face) 24340 24379 (face font-lock-constant-face) 24379 24380 (face font-lock-string-face) 24380 24390 nil 24390 24391 (face font-lock-string-face) 24391 24424 (face font-lock-constant-face) 24424 24425 (face font-lock-string-face) 24425 24435 nil 24435 24436 (face font-lock-string-face) 24436 24476 (face font-lock-constant-face) 24476 24477 (face font-lock-string-face) 24477 24487 nil 24487 24488 (face font-lock-string-face) 24488 24521 (face font-lock-constant-face) 24521 24522 (face font-lock-string-face) 24522 24532 nil 24532 24533 (face font-lock-string-face) 24533 24567 (face font-lock-constant-face) 24567 24568 (face font-lock-string-face) 24568 24578 nil 24578 24579 (face font-lock-string-face) 24579 24610 (face font-lock-constant-face) 24610 24611 (face font-lock-string-face) 24611 24621 nil 24621 24622 (face font-lock-string-face) 24622 24673 (face font-lock-constant-face) 24673 24674 (face font-lock-string-face) 24674 24684 nil 24684 24685 (face font-lock-string-face) 24685 24725 (face font-lock-constant-face) 24725 24726 (face font-lock-string-face) 24726 24736 nil 24736 24737 (face font-lock-string-face) 24737 24773 (face font-lock-constant-face) 24773 24774 (face font-lock-string-face) 24774 24784 nil 24784 24785 (face font-lock-string-face) 24785 24821 (face font-lock-constant-face) 24821 24822 (face font-lock-string-face) 24822 24832 nil 24832 24833 (face font-lock-string-face) 24833 24874 (face font-lock-constant-face) 24874 24875 (face font-lock-string-face) 24875 24885 nil 24885 24886 (face font-lock-string-face) 24886 24926 (face font-lock-constant-face) 24926 24927 (face font-lock-string-face) 24927 24937 nil 24937 24938 (face font-lock-string-face) 24938 24977 (face font-lock-constant-face) 24977 24978 (face font-lock-string-face) 24978 24988 nil 24988 24989 (face font-lock-string-face) 24989 25035 (face font-lock-constant-face) 25035 25036 (face font-lock-string-face) 25036 25046 nil 25046 25047 (face font-lock-string-face) 25047 25070 (face font-lock-constant-face) 25070 25071 (face font-lock-string-face) 25071 25081 nil 25081 25082 (face font-lock-string-face) 25082 25104 (face font-lock-constant-face) 25104 25105 (face font-lock-string-face) 25105 25115 nil 25115 25116 (face font-lock-string-face) 25116 25152 (face font-lock-constant-face) 25152 25153 (face font-lock-string-face) 25153 25163 nil 25163 25164 (face font-lock-string-face) 25164 25210 (face font-lock-constant-face) 25210 25211 (face font-lock-string-face) 25211 25221 nil 25221 25222 (face font-lock-string-face) 25222 25250 (face font-lock-constant-face) 25250 25251 (face font-lock-string-face) 25251 25268 nil 25268 25269 (face font-lock-string-face) 25269 25279 (face font-lock-keyword-face) 25279 25280 (face font-lock-string-face) 25280 25293 nil 25293 25294 (face font-lock-string-face) 25294 25319 (face font-lock-variable-name-face) 25319 25320 (face font-lock-string-face) 25320 25334 nil 25334 25335 (face font-lock-string-face) 25335 25345 (face font-lock-keyword-face) 25345 25346 (face font-lock-string-face) 25346 25363 nil 25363 25364 (face font-lock-string-face) 25364 25385 (face font-lock-variable-name-face) 25385 25386 (face font-lock-string-face) 25386 25404 nil 25404 25405 (face font-lock-string-face) 25405 25417 (face font-lock-keyword-face) 25417 25418 (face font-lock-string-face) 25418 25438 nil 25438 25439 (face font-lock-string-face) 25439 25480 (face font-lock-function-name-face) 25480 25481 (face font-lock-string-face) 25481 25550 nil 25550 25551 (face font-lock-string-face) 25551 25566 (face font-lock-variable-name-face) 25566 25567 (face font-lock-string-face) 25567 25581 nil 25581 25582 (face font-lock-string-face) 25582 25594 (face font-lock-keyword-face) 25594 25595 (face font-lock-string-face) 25595 25611 nil 25611 25612 (face font-lock-string-face) 25612 25651 (face font-lock-function-name-face) 25651 25652 (face font-lock-string-face) 25652 25688 nil 25688 25689 (face font-lock-string-face) 25689 25704 (face font-lock-variable-name-face) 25704 25705 (face font-lock-string-face) 25705 25719 nil 25719 25720 (face font-lock-string-face) 25720 25728 (face font-lock-keyword-face) 25728 25729 (face font-lock-string-face) 25729 25745 nil 25745 25746 (face font-lock-string-face) 25746 25782 (face font-lock-constant-face) 25782 25783 (face font-lock-string-face) 25783 25797 nil 25797 25798 (face font-lock-string-face) 25798 25820 (face font-lock-constant-face) 25820 25821 (face font-lock-string-face) 25821 25835 nil 25835 25836 (face font-lock-string-face) 25836 25857 (face font-lock-constant-face) 25857 25858 (face font-lock-string-face) 25858 25872 nil 25872 25873 (face font-lock-string-face) 25873 25905 (face font-lock-constant-face) 25905 25906 (face font-lock-string-face) 25906 25920 nil 25920 25921 (face font-lock-string-face) 25921 25961 (face font-lock-constant-face) 25961 25962 (face font-lock-string-face) 25962 25976 nil 25976 25977 (face font-lock-string-face) 25977 26016 (face font-lock-constant-face) 26016 26017 (face font-lock-string-face) 26017 26031 nil 26031 26032 (face font-lock-string-face) 26032 26065 (face font-lock-constant-face) 26065 26066 (face font-lock-string-face) 26066 26080 nil 26080 26081 (face font-lock-string-face) 26081 26115 (face font-lock-constant-face) 26115 26116 (face font-lock-string-face) 26116 26130 nil 26130 26131 (face font-lock-string-face) 26131 26162 (face font-lock-constant-face) 26162 26163 (face font-lock-string-face) 26163 26177 nil 26177 26178 (face font-lock-string-face) 26178 26229 (face font-lock-constant-face) 26229 26230 (face font-lock-string-face) 26230 26244 nil 26244 26245 (face font-lock-string-face) 26245 26285 (face font-lock-constant-face) 26285 26286 (face font-lock-string-face) 26286 26300 nil 26300 26301 (face font-lock-string-face) 26301 26337 (face font-lock-constant-face) 26337 26338 (face font-lock-string-face) 26338 26352 nil 26352 26353 (face font-lock-string-face) 26353 26394 (face font-lock-constant-face) 26394 26395 (face font-lock-string-face) 26395 26409 nil 26409 26410 (face font-lock-string-face) 26410 26443 (face font-lock-constant-face) 26443 26444 (face font-lock-string-face) 26444 26458 nil 26458 26459 (face font-lock-string-face) 26459 26495 (face font-lock-constant-face) 26495 26496 (face font-lock-string-face) 26496 26532 nil 26532 26533 (face font-lock-string-face) 26533 26546 (face font-lock-variable-name-face) 26546 26547 (face font-lock-string-face) 26547 26561 nil 26561 26562 (face font-lock-string-face) 26562 26572 (face font-lock-keyword-face) 26572 26573 (face font-lock-string-face) 26573 26590 nil 26590 26591 (face font-lock-string-face) 26591 26604 (face font-lock-variable-name-face) 26604 26605 (face font-lock-string-face) 26605 26623 nil 26623 26624 (face font-lock-string-face) 26624 26631 (face font-lock-keyword-face) 26631 26632 (face font-lock-string-face) 26632 26652 nil 26652 26653 (face font-lock-string-face) 26653 26688 (face font-lock-constant-face) 26688 26689 (face font-lock-string-face) 26689 26722 nil 26722 26723 (face font-lock-string-face) 26723 26730 (face font-lock-keyword-face) 26730 26731 (face font-lock-string-face) 26731 26751 nil 26751 26752 (face font-lock-string-face) 26752 26760 (face font-lock-preprocessor-face) 26760 26761 (face font-lock-string-face) 26761 26831 nil 26831 26832 (face font-lock-string-face) 26832 26873 (face font-lock-variable-name-face) 26873 26874 (face font-lock-string-face) 26874 26888 nil 26888 26889 (face font-lock-string-face) 26889 26896 (face font-lock-keyword-face) 26896 26897 (face font-lock-string-face) 26897 26913 nil 26913 26914 (face font-lock-string-face) 26914 26954 (face font-lock-constant-face) 26954 26955 (face font-lock-string-face) 26955 26991 nil 26991 26992 (face font-lock-string-face) 26992 27035 (face font-lock-variable-name-face) 27035 27036 (face font-lock-string-face) 27036 27050 nil 27050 27051 (face font-lock-string-face) 27051 27058 (face font-lock-keyword-face) 27058 27059 (face font-lock-string-face) 27059 27075 nil 27075 27076 (face font-lock-string-face) 27076 27095 (face font-lock-constant-face) 27095 27096 (face font-lock-string-face) 27096 27110 nil 27110 27111 (face font-lock-string-face) 27111 27137 (face font-lock-constant-face) 27137 27138 (face font-lock-string-face) 27138 27152 nil 27152 27153 (face font-lock-string-face) 27153 27186 (face font-lock-constant-face) 27186 27187 (face font-lock-string-face) 27187 27201 nil 27201 27202 (face font-lock-string-face) 27202 27235 (face font-lock-constant-face) 27235 27236 (face font-lock-string-face) 27236 27291 nil 27291 27292 (face font-lock-string-face) 27292 27303 (face font-lock-keyword-face) 27303 27304 (face font-lock-string-face) 27304 27306 nil 27306 27307 (face font-lock-string-face) 27307 27325 (face font-lock-function-name-face) 27325 27326 (face font-lock-string-face) 27326 27334 nil 27334 27335 (face font-lock-string-face) 27335 27339 (face font-lock-keyword-face) 27339 27340 (face font-lock-string-face) 27340 27342 nil 27342 27343 (face font-lock-string-face) 27343 27357 (face font-lock-type-face) 27357 27358 (face font-lock-string-face) 27358 27366 nil 27366 27367 (face font-lock-string-face) 27367 27379 (face font-lock-keyword-face) 27379 27380 (face font-lock-string-face) 27380 27392 nil 27392 27393 (face font-lock-string-face) 27393 27398 (face font-lock-function-name-face) 27398 27399 (face font-lock-string-face) 27399 27409 nil 27409 27410 (face font-lock-string-face) 27410 27431 (face font-lock-function-name-face) 27431 27432 (face font-lock-string-face) 27432 27442 nil 27442 27443 (face font-lock-string-face) 27443 27469 (face font-lock-function-name-face) 27469 27470 (face font-lock-string-face) 27470 27480 nil 27480 27481 (face font-lock-string-face) 27481 27507 (face font-lock-function-name-face) 27507 27508 (face font-lock-string-face) 27508 27525 nil 27525 27526 (face font-lock-string-face) 27526 27533 (face font-lock-keyword-face) 27533 27534 (face font-lock-string-face) 27534 27546 nil 27546 27547 (face font-lock-string-face) 27547 27591 (face font-lock-constant-face) 27591 27592 (face font-lock-string-face) 27592 27602 nil 27602 27603 (face font-lock-string-face) 27603 27646 (face font-lock-constant-face) 27646 27647 (face font-lock-string-face) 27647 27657 nil 27657 27658 (face font-lock-string-face) 27658 27679 (face font-lock-constant-face) 27679 27680 (face font-lock-string-face) 27680 27690 nil 27690 27691 (face font-lock-string-face) 27691 27711 (face font-lock-constant-face) 27711 27712 (face font-lock-string-face) 27712 27722 nil 27722 27723 (face font-lock-string-face) 27723 27752 (face font-lock-constant-face) 27752 27753 (face font-lock-string-face) 27753 27763 nil 27763 27764 (face font-lock-string-face) 27764 27792 (face font-lock-constant-face) 27792 27793 (face font-lock-string-face) 27793 27803 nil 27803 27804 (face font-lock-string-face) 27804 27829 (face font-lock-constant-face) 27829 27830 (face font-lock-string-face) 27830 27840 nil 27840 27841 (face font-lock-string-face) 27841 27865 (face font-lock-constant-face) 27865 27866 (face font-lock-string-face) 27866 27876 nil 27876 27877 (face font-lock-string-face) 27877 27901 (face font-lock-constant-face) 27901 27902 (face font-lock-string-face) 27902 27912 nil 27912 27913 (face font-lock-string-face) 27913 27936 (face font-lock-constant-face) 27936 27937 (face font-lock-string-face) 27937 27947 nil 27947 27948 (face font-lock-string-face) 27948 27968 (face font-lock-constant-face) 27968 27969 (face font-lock-string-face) 27969 27979 nil 27979 27980 (face font-lock-string-face) 27980 27999 (face font-lock-constant-face) 27999 28000 (face font-lock-string-face) 28000 28030 nil 28030 28031 (face font-lock-string-face) 28031 28042 (face font-lock-keyword-face) 28042 28043 (face font-lock-string-face) 28043 28045 nil 28045 28046 (face font-lock-string-face) 28046 28058 (face font-lock-function-name-face) 28058 28059 (face font-lock-string-face) 28059 28067 nil 28067 28068 (face font-lock-string-face) 28068 28072 (face font-lock-keyword-face) 28072 28073 (face font-lock-string-face) 28073 28075 nil 28075 28076 (face font-lock-string-face) 28076 28086 (face font-lock-type-face) 28086 28087 (face font-lock-string-face) 28087 28095 nil 28095 28096 (face font-lock-string-face) 28096 28108 (face font-lock-keyword-face) 28108 28109 (face font-lock-string-face) 28109 28121 nil 28121 28122 (face font-lock-string-face) 28122 28127 (face font-lock-function-name-face) 28127 28128 (face font-lock-string-face) 28128 28138 nil 28138 28139 (face font-lock-string-face) 28139 28150 (face font-lock-function-name-face) 28150 28151 (face font-lock-string-face) 28151 28161 nil 28161 28162 (face font-lock-string-face) 28162 28183 (face font-lock-function-name-face) 28183 28184 (face font-lock-string-face) 28184 28194 nil 28194 28195 (face font-lock-string-face) 28195 28216 (face font-lock-function-name-face) 28216 28217 (face font-lock-string-face) 28217 28234 nil 28234 28235 (face font-lock-string-face) 28235 28242 (face font-lock-keyword-face) 28242 28243 (face font-lock-string-face) 28243 28255 nil 28255 28256 (face font-lock-string-face) 28256 28290 (face font-lock-constant-face) 28290 28291 (face font-lock-string-face) 28291 28321 nil 28321 28322 (face font-lock-string-face) 28322 28333 (face font-lock-keyword-face) 28333 28334 (face font-lock-string-face) 28334 28336 nil 28336 28337 (face font-lock-string-face) 28337 28349 (face font-lock-function-name-face) 28349 28350 (face font-lock-string-face) 28350 28358 nil 28358 28359 (face font-lock-string-face) 28359 28363 (face font-lock-keyword-face) 28363 28364 (face font-lock-string-face) 28364 28366 nil 28366 28367 (face font-lock-string-face) 28367 28377 (face font-lock-type-face) 28377 28378 (face font-lock-string-face) 28378 28386 nil 28386 28387 (face font-lock-string-face) 28387 28394 (face font-lock-keyword-face) 28394 28395 (face font-lock-string-face) 28395 28407 nil 28407 28408 (face font-lock-string-face) 28408 28441 (face font-lock-constant-face) 28441 28442 (face font-lock-string-face) 28442 28471 nil 28471 28472 (face font-lock-string-face) 28472 28483 (face font-lock-keyword-face) 28483 28484 (face font-lock-string-face) 28484 28486 nil 28486 28487 (face font-lock-string-face) 28487 28498 (face font-lock-function-name-face) 28498 28499 (face font-lock-string-face) 28499 28507 nil 28507 28508 (face font-lock-string-face) 28508 28512 (face font-lock-keyword-face) 28512 28513 (face font-lock-string-face) 28513 28515 nil 28515 28516 (face font-lock-string-face) 28516 28526 (face font-lock-type-face) 28526 28527 (face font-lock-string-face) 28527 28535 nil 28535 28536 (face font-lock-string-face) 28536 28548 (face font-lock-keyword-face) 28548 28549 (face font-lock-string-face) 28549 28561 nil 28561 28562 (face font-lock-string-face) 28562 28567 (face font-lock-function-name-face) 28567 28568 (face font-lock-string-face) 28568 28578 nil 28578 28579 (face font-lock-string-face) 28579 28600 (face font-lock-function-name-face) 28600 28601 (face font-lock-string-face) 28601 28618 nil 28618 28619 (face font-lock-string-face) 28619 28626 (face font-lock-keyword-face) 28626 28627 (face font-lock-string-face) 28627 28639 nil 28639 28640 (face font-lock-string-face) 28640 28672 (face font-lock-constant-face) 28672 28673 (face font-lock-string-face) 28673 28698 nil 28698 28699 (face font-lock-string-face) 28699 28709 (face font-lock-keyword-face) 28709 28710 (face font-lock-string-face) 28710 28719 nil 28719 28720 (face font-lock-string-face) 28720 28729 (face font-lock-variable-name-face) 28729 28730 (face font-lock-string-face) 28730 28740 nil 28740 28741 (face font-lock-string-face) 28741 28748 (face font-lock-keyword-face) 28748 28749 (face font-lock-string-face) 28749 28773 nil 28773 28774 (face font-lock-string-face) 28774 28785 (face font-lock-keyword-face) 28785 28786 (face font-lock-string-face) 28786 28788 nil 28788 28789 (face font-lock-string-face) 28789 28799 (face font-lock-function-name-face) 28799 28800 (face font-lock-string-face) 28800 28812 nil 28812 28813 (face font-lock-string-face) 28813 28817 (face font-lock-keyword-face) 28817 28818 (face font-lock-string-face) 28818 28820 nil 28820 28821 (face font-lock-string-face) 28821 28831 (face font-lock-type-face) 28831 28832 (face font-lock-string-face) 28832 28844 nil 28844 28845 (face font-lock-string-face) 28845 28857 (face font-lock-keyword-face) 28857 28858 (face font-lock-string-face) 28858 28874 nil 28874 28875 (face font-lock-string-face) 28875 28880 (face font-lock-function-name-face) 28880 28881 (face font-lock-string-face) 28881 28895 nil 28895 28896 (face font-lock-string-face) 28896 28907 (face font-lock-function-name-face) 28907 28908 (face font-lock-string-face) 28908 28922 nil 28922 28923 (face font-lock-string-face) 28923 28944 (face font-lock-function-name-face) 28944 28945 (face font-lock-string-face) 28945 28959 nil 28959 28960 (face font-lock-string-face) 28960 29043 (face font-lock-function-name-face) 29043 29044 (face font-lock-string-face) 29044 29058 nil 29058 29059 (face font-lock-string-face) 29059 29074 (face font-lock-function-name-face) 29074 29075 (face font-lock-string-face) 29075 29100 nil 29100 29101 (face font-lock-string-face) 29101 29113 (face font-lock-keyword-face) 29113 29114 (face font-lock-string-face) 29114 29130 nil 29130 29131 (face font-lock-string-face) 29131 29133 (face font-lock-constant-face) 29133 29138 (face font-lock-variable-name-face) 29138 29163 (face font-lock-constant-face) 29163 29164 (face font-lock-string-face) 29164 29189 nil 29189 29190 (face font-lock-string-face) 29190 29197 (face font-lock-keyword-face) 29197 29198 (face font-lock-string-face) 29198 29214 nil 29214 29215 (face font-lock-string-face) 29215 29238 (face font-lock-constant-face) 29238 29239 (face font-lock-string-face) 29239 29253 nil 29253 29254 (face font-lock-string-face) 29254 29280 (face font-lock-constant-face) 29280 29281 (face font-lock-string-face) 29281 29295 nil 29295 29296 (face font-lock-string-face) 29296 29321 (face font-lock-constant-face) 29321 29322 (face font-lock-string-face) 29322 29336 nil 29336 29337 (face font-lock-string-face) 29337 29361 (face font-lock-constant-face) 29361 29362 (face font-lock-string-face) 29362 29376 nil 29376 29377 (face font-lock-string-face) 29377 29407 (face font-lock-constant-face) 29407 29408 (face font-lock-string-face) 29408 29422 nil 29422 29423 (face font-lock-string-face) 29423 29453 (face font-lock-constant-face) 29453 29454 (face font-lock-string-face) 29454 29468 nil 29468 29469 (face font-lock-string-face) 29469 29493 (face font-lock-constant-face) 29493 29494 (face font-lock-string-face) 29494 29508 nil 29508 29509 (face font-lock-string-face) 29509 29532 (face font-lock-constant-face) 29532 29533 (face font-lock-string-face) 29533 29547 nil 29547 29548 (face font-lock-string-face) 29548 29575 (face font-lock-constant-face) 29575 29576 (face font-lock-string-face) 29576 29590 nil 29590 29591 (face font-lock-string-face) 29591 29614 (face font-lock-constant-face) 29614 29615 (face font-lock-string-face) 29615 29640 nil 29640 29655 (face font-lock-string-face) 29655 29671 nil 29671 29685 (face font-lock-string-face) 29685 29703 nil 29703 29714 (face font-lock-string-face) 29714 29716 nil 29716 29719 (face font-lock-string-face) 29719 29729 nil 29729 29754 (face font-lock-comment-face) 29754 29792 nil 29792 29793 (face font-lock-string-face) 29793 29800 (face font-lock-keyword-face) 29800 29801 (face font-lock-string-face) 29801 29817 nil 29817 29818 (face font-lock-string-face) 29818 29843 (face font-lock-preprocessor-face) 29843 29844 (face font-lock-string-face) 29844 29892 nil 29892 29893 (face font-lock-string-face) 29893 29929 (face font-lock-variable-name-face) 29929 29930 (face font-lock-string-face) 29930 29940 nil 29940 29941 (face font-lock-string-face) 29941 29948 (face font-lock-keyword-face) 29948 29949 (face font-lock-string-face) 29949 29973 nil 29973 29974 (face font-lock-string-face) 29974 29985 (face font-lock-keyword-face) 29985 29986 (face font-lock-string-face) 29986 29988 nil 29988 29989 (face font-lock-string-face) 29989 30001 (face font-lock-function-name-face) 30001 30002 (face font-lock-string-face) 30002 30014 nil 30014 30015 (face font-lock-string-face) 30015 30019 (face font-lock-keyword-face) 30019 30020 (face font-lock-string-face) 30020 30022 nil 30022 30023 (face font-lock-string-face) 30023 30033 (face font-lock-type-face) 30033 30034 (face font-lock-string-face) 30034 30046 nil 30046 30047 (face font-lock-string-face) 30047 30059 (face font-lock-keyword-face) 30059 30060 (face font-lock-string-face) 30060 30076 nil 30076 30077 (face font-lock-string-face) 30077 30082 (face font-lock-function-name-face) 30082 30083 (face font-lock-string-face) 30083 30097 nil 30097 30098 (face font-lock-string-face) 30098 30109 (face font-lock-function-name-face) 30109 30110 (face font-lock-string-face) 30110 30124 nil 30124 30125 (face font-lock-string-face) 30125 30146 (face font-lock-function-name-face) 30146 30147 (face font-lock-string-face) 30147 30161 nil 30161 30162 (face font-lock-string-face) 30162 30180 (face font-lock-function-name-face) 30180 30181 (face font-lock-string-face) 30181 30206 nil 30206 30207 (face font-lock-string-face) 30207 30214 (face font-lock-keyword-face) 30214 30215 (face font-lock-string-face) 30215 30231 nil 30231 30232 (face font-lock-string-face) 30232 30266 (face font-lock-constant-face) 30266 30267 (face font-lock-string-face) 30267 30281 nil 30281 30282 (face font-lock-string-face) 30282 30321 (face font-lock-constant-face) 30321 30322 (face font-lock-string-face) 30322 30336 nil 30336 30337 (face font-lock-string-face) 30337 30375 (face font-lock-constant-face) 30375 30376 (face font-lock-string-face) 30376 30390 nil 30390 30391 (face font-lock-string-face) 30391 30430 (face font-lock-constant-face) 30430 30431 (face font-lock-string-face) 30431 30445 nil 30445 30446 (face font-lock-string-face) 30446 30484 (face font-lock-constant-face) 30484 30485 (face font-lock-string-face) 30485 30499 nil 30499 30500 (face font-lock-string-face) 30500 30533 (face font-lock-constant-face) 30533 30534 (face font-lock-string-face) 30534 30548 nil 30548 30549 (face font-lock-string-face) 30549 30581 (face font-lock-constant-face) 30581 30582 (face font-lock-string-face) 30582 30596 nil 30596 30597 (face font-lock-string-face) 30597 30626 (face font-lock-constant-face) 30626 30627 (face font-lock-string-face) 30627 30641 nil 30641 30642 (face font-lock-string-face) 30642 30670 (face font-lock-constant-face) 30670 30671 (face font-lock-string-face) 30671 30685 nil 30685 30686 (face font-lock-string-face) 30686 30714 (face font-lock-constant-face) 30714 30715 (face font-lock-string-face) 30715 30729 nil 30729 30730 (face font-lock-string-face) 30730 30757 (face font-lock-constant-face) 30757 30758 (face font-lock-string-face) 30758 30783 nil 30783 30784 (face font-lock-string-face) 30784 30794 (face font-lock-keyword-face) 30794 30795 (face font-lock-string-face) 30795 30812 nil 30812 30813 (face font-lock-string-face) 30813 30834 (face font-lock-variable-name-face) 30834 30835 (face font-lock-string-face) 30835 30853 nil 30853 30854 (face font-lock-string-face) 30854 30866 (face font-lock-keyword-face) 30866 30867 (face font-lock-string-face) 30867 30887 nil 30887 30888 (face font-lock-string-face) 30888 30917 (face font-lock-function-name-face) 30917 30918 (face font-lock-string-face) 30918 30951 nil 30951 30952 (face font-lock-string-face) 30952 30959 (face font-lock-keyword-face) 30959 30960 (face font-lock-string-face) 30960 30980 nil 30980 30981 (face font-lock-string-face) 30981 31015 (face font-lock-constant-face) 31015 31016 (face font-lock-string-face) 31016 31064 nil 31064 31065 (face font-lock-string-face) 31065 31074 (face font-lock-variable-name-face) 31074 31075 (face font-lock-string-face) 31075 31093 nil 31093 31094 (face font-lock-string-face) 31094 31106 (face font-lock-keyword-face) 31106 31107 (face font-lock-string-face) 31107 31127 nil 31127 31128 (face font-lock-string-face) 31128 31175 (face font-lock-function-name-face) 31175 31176 (face font-lock-string-face) 31176 31194 nil 31194 31195 (face font-lock-string-face) 31195 31245 (face font-lock-function-name-face) 31245 31246 (face font-lock-string-face) 31246 31279 nil 31279 31280 (face font-lock-string-face) 31280 31287 (face font-lock-keyword-face) 31287 31288 (face font-lock-string-face) 31288 31308 nil 31308 31309 (face font-lock-string-face) 31309 31341 (face font-lock-constant-face) 31341 31342 (face font-lock-string-face) 31342 31423 nil 31423 31424 (face font-lock-string-face) 31424 31462 (face font-lock-variable-name-face) 31462 31463 (face font-lock-string-face) 31463 31473 nil 31473 31474 (face font-lock-string-face) 31474 31481 (face font-lock-keyword-face) 31481 31482 (face font-lock-string-face) 31482 31506 nil 31506 31507 (face font-lock-string-face) 31507 31518 (face font-lock-keyword-face) 31518 31519 (face font-lock-string-face) 31519 31521 nil 31521 31522 (face font-lock-string-face) 31522 31539 (face font-lock-function-name-face) 31539 31540 (face font-lock-string-face) 31540 31552 nil 31552 31553 (face font-lock-string-face) 31553 31557 (face font-lock-keyword-face) 31557 31558 (face font-lock-string-face) 31558 31560 nil 31560 31561 (face font-lock-string-face) 31561 31571 (face font-lock-type-face) 31571 31572 (face font-lock-string-face) 31572 31584 nil 31584 31585 (face font-lock-string-face) 31585 31597 (face font-lock-keyword-face) 31597 31598 (face font-lock-string-face) 31598 31614 nil 31614 31615 (face font-lock-string-face) 31615 31636 (face font-lock-function-name-face) 31636 31637 (face font-lock-string-face) 31637 31651 nil 31651 31652 (face font-lock-string-face) 31652 31670 (face font-lock-function-name-face) 31670 31671 (face font-lock-string-face) 31671 31696 nil 31696 31697 (face font-lock-string-face) 31697 31706 (face font-lock-keyword-face) 31706 31707 (face font-lock-string-face) 31707 31723 nil 31723 31724 (face font-lock-string-face) 31724 31728 (face font-lock-constant-face) 31728 31729 (face font-lock-string-face) 31729 31743 nil 31743 31744 (face font-lock-string-face) 31744 31748 (face font-lock-constant-face) 31748 31749 (face font-lock-string-face) 31749 31774 nil 31774 31775 (face font-lock-string-face) 31775 31782 (face font-lock-keyword-face) 31782 31783 (face font-lock-string-face) 31783 31799 nil 31799 31800 (face font-lock-string-face) 31800 31844 (face font-lock-constant-face) 31844 31845 (face font-lock-string-face) 31845 31893 nil 31893 31894 (face font-lock-string-face) 31894 31943 (face font-lock-variable-name-face) 31943 31944 (face font-lock-string-face) 31944 31954 nil 31954 31955 (face font-lock-string-face) 31955 31962 (face font-lock-keyword-face) 31962 31963 (face font-lock-string-face) 31963 31987 nil 31987 31988 (face font-lock-string-face) 31988 31999 (face font-lock-keyword-face) 31999 32000 (face font-lock-string-face) 32000 32002 nil 32002 32003 (face font-lock-string-face) 32003 32013 (face font-lock-function-name-face) 32013 32014 (face font-lock-string-face) 32014 32026 nil 32026 32027 (face font-lock-string-face) 32027 32031 (face font-lock-keyword-face) 32031 32032 (face font-lock-string-face) 32032 32034 nil 32034 32035 (face font-lock-string-face) 32035 32045 (face font-lock-type-face) 32045 32046 (face font-lock-string-face) 32046 32058 nil 32058 32059 (face font-lock-string-face) 32059 32071 (face font-lock-keyword-face) 32071 32072 (face font-lock-string-face) 32072 32088 nil 32088 32089 (face font-lock-string-face) 32089 32094 (face font-lock-function-name-face) 32094 32095 (face font-lock-string-face) 32095 32109 nil 32109 32110 (face font-lock-string-face) 32110 32121 (face font-lock-function-name-face) 32121 32122 (face font-lock-string-face) 32122 32136 nil 32136 32137 (face font-lock-string-face) 32137 32158 (face font-lock-function-name-face) 32158 32159 (face font-lock-string-face) 32159 32173 nil 32173 32174 (face font-lock-string-face) 32174 32192 (face font-lock-function-name-face) 32192 32193 (face font-lock-string-face) 32193 32218 nil 32218 32219 (face font-lock-string-face) 32219 32232 (face font-lock-keyword-face) 32232 32233 (face font-lock-string-face) 32233 32249 nil 32249 32250 (face font-lock-string-face) 32250 32259 (face font-lock-keyword-face) 32259 32260 (face font-lock-string-face) 32260 32278 nil 32278 32279 (face font-lock-string-face) 32279 32283 (face font-lock-constant-face) 32283 32284 (face font-lock-string-face) 32284 32300 nil 32300 32301 (face font-lock-string-face) 32301 32306 (face font-lock-constant-face) 32306 32307 (face font-lock-string-face) 32307 32323 nil 32323 32324 (face font-lock-string-face) 32324 32333 (face font-lock-constant-face) 32333 32334 (face font-lock-string-face) 32334 32350 nil 32350 32351 (face font-lock-string-face) 32351 32357 (face font-lock-constant-face) 32357 32358 (face font-lock-string-face) 32358 32398 nil 32398 32399 (face font-lock-string-face) 32399 32406 (face font-lock-keyword-face) 32406 32407 (face font-lock-string-face) 32407 32423 nil 32423 32424 (face font-lock-string-face) 32424 32462 (face font-lock-constant-face) 32462 32463 (face font-lock-string-face) 32463 32477 nil 32477 32478 (face font-lock-string-face) 32478 32515 (face font-lock-constant-face) 32515 32516 (face font-lock-string-face) 32516 32530 nil 32530 32531 (face font-lock-string-face) 32531 32568 (face font-lock-constant-face) 32568 32569 (face font-lock-string-face) 32569 32583 nil 32583 32584 (face font-lock-string-face) 32584 32620 (face font-lock-constant-face) 32620 32621 (face font-lock-string-face) 32621 32635 nil 32635 32636 (face font-lock-string-face) 32636 32666 (face font-lock-constant-face) 32666 32667 (face font-lock-string-face) 32667 32681 nil 32681 32682 (face font-lock-string-face) 32682 32720 (face font-lock-constant-face) 32720 32721 (face font-lock-string-face) 32721 32735 nil 32735 32736 (face font-lock-string-face) 32736 32773 (face font-lock-constant-face) 32773 32774 (face font-lock-string-face) 32774 32822 nil 32822 32823 (face font-lock-string-face) 32823 32838 (face font-lock-variable-name-face) 32838 32839 (face font-lock-string-face) 32839 32849 nil 32849 32850 (face font-lock-string-face) 32850 32857 (face font-lock-keyword-face) 32857 32858 (face font-lock-string-face) 32858 32882 nil 32882 32883 (face font-lock-string-face) 32883 32894 (face font-lock-keyword-face) 32894 32895 (face font-lock-string-face) 32895 32897 nil 32897 32898 (face font-lock-string-face) 32898 32912 (face font-lock-function-name-face) 32912 32913 (face font-lock-string-face) 32913 32925 nil 32925 32926 (face font-lock-string-face) 32926 32930 (face font-lock-keyword-face) 32930 32931 (face font-lock-string-face) 32931 32933 nil 32933 32934 (face font-lock-string-face) 32934 32948 (face font-lock-type-face) 32948 32949 (face font-lock-string-face) 32949 32961 nil 32961 32962 (face font-lock-string-face) 32962 32969 (face font-lock-keyword-face) 32969 32970 (face font-lock-string-face) 32970 32986 nil 32986 32987 (face font-lock-string-face) 32987 33022 (face font-lock-constant-face) 33022 33023 (face font-lock-string-face) 33023 33037 nil 33037 33038 (face font-lock-string-face) 33038 33072 (face font-lock-constant-face) 33072 33073 (face font-lock-string-face) 33073 33098 nil 33098 33099 (face font-lock-string-face) 33099 33111 (face font-lock-keyword-face) 33111 33112 (face font-lock-string-face) 33112 33128 nil 33128 33129 (face font-lock-string-face) 33129 33150 (face font-lock-function-name-face) 33150 33151 (face font-lock-string-face) 33151 33176 nil 33176 33177 (face font-lock-string-face) 33177 33189 (face font-lock-keyword-face) 33189 33190 (face font-lock-string-face) 33190 33206 nil 33206 33207 (face font-lock-string-face) 33207 33209 (face font-lock-constant-face) 33209 33232 (face font-lock-variable-name-face) 33232 33239 (face font-lock-constant-face) 33239 33240 (face font-lock-string-face) 33240 33265 nil 33265 33266 (face font-lock-string-face) 33266 33273 (face font-lock-keyword-face) 33273 33274 (face font-lock-string-face) 33274 33306 nil 33306 33307 (face font-lock-string-face) 33307 33318 (face font-lock-keyword-face) 33318 33319 (face font-lock-string-face) 33319 33321 nil 33321 33322 (face font-lock-string-face) 33322 33342 (face font-lock-function-name-face) 33342 33343 (face font-lock-string-face) 33343 33359 nil 33359 33360 (face font-lock-string-face) 33360 33366 (face font-lock-keyword-face) 33366 33367 (face font-lock-string-face) 33367 33387 nil 33387 33388 (face font-lock-string-face) 33388 33434 (face font-lock-constant-face) 33434 33435 (face font-lock-string-face) 33435 33453 nil 33453 33454 (face font-lock-string-face) 33454 33519 (face font-lock-constant-face) 33519 33520 (face font-lock-string-face) 33520 33553 nil 33553 33554 (face font-lock-string-face) 33554 33561 (face font-lock-keyword-face) 33561 33562 (face font-lock-string-face) 33562 33582 nil 33582 33583 (face font-lock-string-face) 33583 33585 (face font-lock-constant-face) 33585 33608 (face font-lock-variable-name-face) 33608 33647 (face font-lock-constant-face) 33647 33648 (face font-lock-string-face) 33648 33681 nil 33681 33682 (face font-lock-string-face) 33682 33688 (face font-lock-keyword-face) 33688 33689 (face font-lock-string-face) 33689 33709 nil 33709 33710 (face font-lock-string-face) 33710 33716 (face font-lock-constant-face) 33716 33717 (face font-lock-string-face) 33717 33735 nil 33735 33736 (face font-lock-string-face) 33736 33738 (face font-lock-constant-face) 33738 33743 (face font-lock-variable-name-face) 33743 33788 (face font-lock-constant-face) 33788 33789 (face font-lock-string-face) 33789 33807 nil 33807 33808 (face font-lock-string-face) 33808 33810 (face font-lock-constant-face) 33810 33811 (face font-lock-string-face) 33811 33829 nil 33829 33830 (face font-lock-string-face) 33830 33833 (face font-lock-constant-face) 33833 33840 (face font-lock-variable-name-face) 33840 33841 (face font-lock-constant-face) 33841 33842 (face font-lock-string-face) 33842 33860 nil 33860 33861 (face font-lock-string-face) 33861 33864 (face font-lock-constant-face) 33864 33872 (face font-lock-variable-name-face) 33872 33873 (face font-lock-constant-face) 33873 33874 (face font-lock-string-face) 33874 33952 nil 33952 33953 (face font-lock-string-face) 33953 33964 (face font-lock-keyword-face) 33964 33965 (face font-lock-string-face) 33965 33967 nil 33967 33968 (face font-lock-string-face) 33968 33978 (face font-lock-function-name-face) 33978 33979 (face font-lock-string-face) 33979 33991 nil 33991 33992 (face font-lock-string-face) 33992 33996 (face font-lock-keyword-face) 33996 33997 (face font-lock-string-face) 33997 33999 nil 33999 34000 (face font-lock-string-face) 34000 34004 (face font-lock-type-face) 34004 34005 (face font-lock-string-face) 34005 34017 nil 34017 34018 (face font-lock-string-face) 34018 34030 (face font-lock-keyword-face) 34030 34031 (face font-lock-string-face) 34031 34035 nil 34035 34036 (face font-lock-string-face) 34036 34062 (face font-lock-function-name-face) 34062 34063 (face font-lock-string-face) 34063 34077 nil 34077 34078 (face font-lock-string-face) 34078 34087 (face font-lock-keyword-face) 34087 34088 (face font-lock-string-face) 34088 34104 nil 34104 34105 (face font-lock-string-face) 34105 34117 (face font-lock-variable-name-face) 34117 34118 (face font-lock-string-face) 34118 34120 nil 34120 34121 (face font-lock-string-face) 34121 34126 (face font-lock-variable-name-face) 34126 34127 (face font-lock-string-face) 34127 34141 nil 34141 34142 (face font-lock-string-face) 34142 34153 (face font-lock-variable-name-face) 34153 34154 (face font-lock-string-face) 34154 34156 nil 34156 34157 (face font-lock-string-face) 34157 34174 (face font-lock-variable-name-face) 34174 34175 (face font-lock-string-face) 34175 34200 nil 34200 34201 (face font-lock-string-face) 34201 34209 (face font-lock-keyword-face) 34209 34210 (face font-lock-string-face) 34210 34214 nil 34214 34215 (face font-lock-string-face) 34215 34233 (face font-lock-constant-face) 34233 34234 (face font-lock-string-face) 34234 34268 nil 34268 34287 (face font-lock-comment-face) 34287 34293 nil 34293 34365 (face font-lock-comment-face) 34365 34371 nil 34371 34372 (face font-lock-string-face) 34372 34379 (face font-lock-keyword-face) 34379 34380 (face font-lock-string-face) 34380 34404 nil 34404 34405 (face font-lock-string-face) 34405 34416 (face font-lock-keyword-face) 34416 34417 (face font-lock-string-face) 34417 34419 nil 34419 34420 (face font-lock-string-face) 34420 34436 (face font-lock-function-name-face) 34436 34437 (face font-lock-string-face) 34437 34449 nil 34449 34450 (face font-lock-string-face) 34450 34454 (face font-lock-keyword-face) 34454 34455 (face font-lock-string-face) 34455 34457 nil 34457 34458 (face font-lock-string-face) 34458 34468 (face font-lock-type-face) 34468 34469 (face font-lock-string-face) 34469 34481 nil 34481 34482 (face font-lock-string-face) 34482 34494 (face font-lock-keyword-face) 34494 34495 (face font-lock-string-face) 34495 34511 nil 34511 34512 (face font-lock-string-face) 34512 34517 (face font-lock-function-name-face) 34517 34518 (face font-lock-string-face) 34518 34532 nil 34532 34533 (face font-lock-string-face) 34533 34551 (face font-lock-function-name-face) 34551 34552 (face font-lock-string-face) 34552 34566 nil 34566 34567 (face font-lock-string-face) 34567 34588 (face font-lock-function-name-face) 34588 34589 (face font-lock-string-face) 34589 34603 nil 34603 34604 (face font-lock-string-face) 34604 34630 (face font-lock-function-name-face) 34630 34631 (face font-lock-string-face) 34631 34645 nil 34645 34646 (face font-lock-string-face) 34646 34680 (face font-lock-function-name-face) 34680 34681 (face font-lock-string-face) 34681 34695 nil 34695 34696 (face font-lock-string-face) 34696 34730 (face font-lock-function-name-face) 34730 34731 (face font-lock-string-face) 34731 34745 nil 34745 34746 (face font-lock-string-face) 34746 34772 (face font-lock-function-name-face) 34772 34773 (face font-lock-string-face) 34773 34787 nil 34787 34788 (face font-lock-string-face) 34788 34827 (face font-lock-function-name-face) 34827 34828 (face font-lock-string-face) 34828 34853 nil 34853 34854 (face font-lock-string-face) 34854 34861 (face font-lock-keyword-face) 34861 34862 (face font-lock-string-face) 34862 34878 nil 34878 34879 (face font-lock-string-face) 34879 34904 (face font-lock-constant-face) 34904 34905 (face font-lock-string-face) 34905 34930 nil 34930 34931 (face font-lock-string-face) 34931 34941 (face font-lock-keyword-face) 34941 34942 (face font-lock-string-face) 34942 34959 nil 34959 34960 (face font-lock-string-face) 34960 34981 (face font-lock-variable-name-face) 34981 34982 (face font-lock-string-face) 34982 35000 nil 35000 35001 (face font-lock-string-face) 35001 35013 (face font-lock-keyword-face) 35013 35014 (face font-lock-string-face) 35014 35034 nil 35034 35077 (face font-lock-comment-face) 35077 35093 nil 35093 35123 (face font-lock-comment-face) 35123 35139 nil 35139 35164 (face font-lock-comment-face) 35164 35180 nil 35180 35194 (face font-lock-comment-face) 35194 35210 nil 35210 35211 (face font-lock-string-face) 35211 35240 (face font-lock-function-name-face) 35240 35241 (face font-lock-string-face) 35241 35274 nil 35274 35275 (face font-lock-string-face) 35275 35285 (face font-lock-keyword-face) 35285 35286 (face font-lock-string-face) 35286 35307 nil 35307 35308 (face font-lock-string-face) 35308 35329 (face font-lock-variable-name-face) 35329 35330 (face font-lock-string-face) 35330 35352 nil 35352 35353 (face font-lock-string-face) 35353 35365 (face font-lock-keyword-face) 35365 35366 (face font-lock-string-face) 35366 35390 nil 35390 35391 (face font-lock-string-face) 35391 35432 (face font-lock-function-name-face) 35432 35433 (face font-lock-string-face) 35433 35553 nil 35553 35554 (face font-lock-string-face) 35554 35565 (face font-lock-keyword-face) 35565 35566 (face font-lock-string-face) 35566 35568 nil 35568 35569 (face font-lock-string-face) 35569 35592 (face font-lock-function-name-face) 35592 35593 (face font-lock-string-face) 35593 35605 nil 35605 35606 (face font-lock-string-face) 35606 35610 (face font-lock-keyword-face) 35610 35611 (face font-lock-string-face) 35611 35613 nil 35613 35614 (face font-lock-string-face) 35614 35624 (face font-lock-type-face) 35624 35625 (face font-lock-string-face) 35625 35637 nil 35637 35638 (face font-lock-string-face) 35638 35650 (face font-lock-keyword-face) 35650 35651 (face font-lock-string-face) 35651 35667 nil 35667 35668 (face font-lock-string-face) 35668 35673 (face font-lock-function-name-face) 35673 35674 (face font-lock-string-face) 35674 35688 nil 35688 35689 (face font-lock-string-face) 35689 35707 (face font-lock-function-name-face) 35707 35708 (face font-lock-string-face) 35708 35722 nil 35722 35723 (face font-lock-string-face) 35723 35757 (face font-lock-function-name-face) 35757 35758 (face font-lock-string-face) 35758 35772 nil 35772 35773 (face font-lock-string-face) 35773 35799 (face font-lock-function-name-face) 35799 35800 (face font-lock-string-face) 35800 35814 nil 35814 35815 (face font-lock-string-face) 35815 35841 (face font-lock-function-name-face) 35841 35842 (face font-lock-string-face) 35842 35856 nil 35856 35857 (face font-lock-string-face) 35857 35896 (face font-lock-function-name-face) 35896 35897 (face font-lock-string-face) 35897 35922 nil 35922 35923 (face font-lock-string-face) 35923 35930 (face font-lock-keyword-face) 35930 35931 (face font-lock-string-face) 35931 35947 nil 35947 35948 (face font-lock-string-face) 35948 35970 (face font-lock-constant-face) 35970 35971 (face font-lock-string-face) 35971 35985 nil 35985 35986 (face font-lock-string-face) 35986 36011 (face font-lock-constant-face) 36011 36012 (face font-lock-string-face) 36012 36026 nil 36026 36027 (face font-lock-string-face) 36027 36060 (face font-lock-constant-face) 36060 36061 (face font-lock-string-face) 36061 36075 nil 36075 36076 (face font-lock-string-face) 36076 36117 (face font-lock-constant-face) 36117 36118 (face font-lock-string-face) 36118 36143 nil 36143 36144 (face font-lock-string-face) 36144 36154 (face font-lock-keyword-face) 36154 36155 (face font-lock-string-face) 36155 36172 nil 36172 36173 (face font-lock-string-face) 36173 36198 (face font-lock-variable-name-face) 36198 36199 (face font-lock-string-face) 36199 36217 nil 36217 36218 (face font-lock-string-face) 36218 36228 (face font-lock-keyword-face) 36228 36229 (face font-lock-string-face) 36229 36250 nil 36250 36251 (face font-lock-string-face) 36251 36272 (face font-lock-variable-name-face) 36272 36273 (face font-lock-string-face) 36273 36295 nil 36295 36296 (face font-lock-string-face) 36296 36308 (face font-lock-keyword-face) 36308 36309 (face font-lock-string-face) 36309 36333 nil 36333 36334 (face font-lock-string-face) 36334 36375 (face font-lock-function-name-face) 36375 36376 (face font-lock-string-face) 36376 36496 nil 36496 36497 (face font-lock-string-face) 36497 36508 (face font-lock-keyword-face) 36508 36509 (face font-lock-string-face) 36509 36511 nil 36511 36512 (face font-lock-string-face) 36512 36524 (face font-lock-function-name-face) 36524 36525 (face font-lock-string-face) 36525 36537 nil 36537 36538 (face font-lock-string-face) 36538 36542 (face font-lock-keyword-face) 36542 36543 (face font-lock-string-face) 36543 36545 nil 36545 36546 (face font-lock-string-face) 36546 36556 (face font-lock-type-face) 36556 36557 (face font-lock-string-face) 36557 36569 nil 36569 36570 (face font-lock-string-face) 36570 36582 (face font-lock-keyword-face) 36582 36583 (face font-lock-string-face) 36583 36599 nil 36599 36600 (face font-lock-string-face) 36600 36605 (face font-lock-function-name-face) 36605 36606 (face font-lock-string-face) 36606 36620 nil 36620 36621 (face font-lock-string-face) 36621 36642 (face font-lock-function-name-face) 36642 36643 (face font-lock-string-face) 36643 36657 nil 36657 36658 (face font-lock-string-face) 36658 36697 (face font-lock-function-name-face) 36697 36698 (face font-lock-string-face) 36698 36723 nil 36723 36724 (face font-lock-string-face) 36724 36731 (face font-lock-keyword-face) 36731 36732 (face font-lock-string-face) 36732 36748 nil 36748 36749 (face font-lock-string-face) 36749 36782 (face font-lock-constant-face) 36782 36783 (face font-lock-string-face) 36783 36829 nil 36829 36830 (face font-lock-string-face) 36830 36841 (face font-lock-keyword-face) 36841 36842 (face font-lock-string-face) 36842 36844 nil 36844 36845 (face font-lock-string-face) 36845 36856 (face font-lock-function-name-face) 36856 36857 (face font-lock-string-face) 36857 36869 nil 36869 36870 (face font-lock-string-face) 36870 36874 (face font-lock-keyword-face) 36874 36875 (face font-lock-string-face) 36875 36877 nil 36877 36878 (face font-lock-string-face) 36878 36888 (face font-lock-type-face) 36888 36889 (face font-lock-string-face) 36889 36901 nil 36901 36902 (face font-lock-string-face) 36902 36914 (face font-lock-keyword-face) 36914 36915 (face font-lock-string-face) 36915 36931 nil 36931 36932 (face font-lock-string-face) 36932 36937 (face font-lock-function-name-face) 36937 36938 (face font-lock-string-face) 36938 36952 nil 36952 36953 (face font-lock-string-face) 36953 36974 (face font-lock-function-name-face) 36974 36975 (face font-lock-string-face) 36975 36989 nil 36989 36990 (face font-lock-string-face) 36990 37029 (face font-lock-function-name-face) 37029 37030 (face font-lock-string-face) 37030 37055 nil 37055 37056 (face font-lock-string-face) 37056 37063 (face font-lock-keyword-face) 37063 37064 (face font-lock-string-face) 37064 37080 nil 37080 37081 (face font-lock-string-face) 37081 37113 (face font-lock-constant-face) 37113 37114 (face font-lock-string-face) 37114 37163 nil)
diff --git a/gyp/tools/graphviz.py b/gyp/tools/graphviz.py
new file mode 100755 (executable)
index 0000000..326ae22
--- /dev/null
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Using the JSON dumped by the dump-dependency-json generator,
+generate input suitable for graphviz to render a dependency graph of
+targets."""
+
+import collections
+import json
+import sys
+
+
+def ParseTarget(target):
+  target, _, suffix = target.partition('#')
+  filename, _, target = target.partition(':')
+  return filename, target, suffix
+
+
+def LoadEdges(filename, targets):
+  """Load the edges map from the dump file, and filter it to only
+  show targets in |targets| and their depedendents."""
+
+  file = open('dump.json')
+  edges = json.load(file)
+  file.close()
+
+  # Copy out only the edges we're interested in from the full edge list.
+  target_edges = {}
+  to_visit = targets[:]
+  while to_visit:
+    src = to_visit.pop()
+    if src in target_edges:
+      continue
+    target_edges[src] = edges[src]
+    to_visit.extend(edges[src])
+
+  return target_edges
+
+
+def WriteGraph(edges):
+  """Print a graphviz graph to stdout.
+  |edges| is a map of target to a list of other targets it depends on."""
+
+  # Bucket targets by file.
+  files = collections.defaultdict(list)
+  for src, dst in edges.items():
+    build_file, target_name, toolset = ParseTarget(src)
+    files[build_file].append(src)
+
+  print 'digraph D {'
+  print '  fontsize=8'  # Used by subgraphs.
+  print '  node [fontsize=8]'
+
+  # Output nodes by file.  We must first write out each node within
+  # its file grouping before writing out any edges that may refer
+  # to those nodes.
+  for filename, targets in files.items():
+    if len(targets) == 1:
+      # If there's only one node for this file, simplify
+      # the display by making it a box without an internal node.
+      target = targets[0]
+      build_file, target_name, toolset = ParseTarget(target)
+      print '  "%s" [shape=box, label="%s\\n%s"]' % (target, filename,
+                                                     target_name)
+    else:
+      # Group multiple nodes together in a subgraph.
+      print '  subgraph "cluster_%s" {' % filename
+      print '    label = "%s"' % filename
+      for target in targets:
+        build_file, target_name, toolset = ParseTarget(target)
+        print '    "%s" [label="%s"]' % (target, target_name)
+      print '  }'
+
+  # Now that we've placed all the nodes within subgraphs, output all
+  # the edges between nodes.
+  for src, dsts in edges.items():
+    for dst in dsts:
+      print '  "%s" -> "%s"' % (src, dst)
+
+  print '}'
+
+
+def main():
+  if len(sys.argv) < 2:
+    print >>sys.stderr, __doc__
+    print >>sys.stderr
+    print >>sys.stderr, 'usage: %s target1 target2...' % (sys.argv[0])
+    return 1
+
+  edges = LoadEdges('dump.json', sys.argv[1:])
+
+  WriteGraph(edges)
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/gyp/tools/pretty_gyp.py b/gyp/tools/pretty_gyp.py
new file mode 100755 (executable)
index 0000000..c51d358
--- /dev/null
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Pretty-prints the contents of a GYP file."""
+
+import sys
+import re
+
+
+# Regex to remove comments when we're counting braces.
+COMMENT_RE = re.compile(r'\s*#.*')
+
+# Regex to remove quoted strings when we're counting braces.
+# It takes into account quoted quotes, and makes sure that the quotes match.
+# NOTE: It does not handle quotes that span more than one line, or
+# cases where an escaped quote is preceeded by an escaped backslash.
+QUOTE_RE_STR = r'(?P<q>[\'"])(.*?)(?<![^\\][\\])(?P=q)'
+QUOTE_RE = re.compile(QUOTE_RE_STR)
+
+
+def comment_replace(matchobj):
+  return matchobj.group(1) + matchobj.group(2) + '#' * len(matchobj.group(3))
+
+
+def mask_comments(input):
+  """Mask the quoted strings so we skip braces inside quoted strings."""
+  search_re = re.compile(r'(.*?)(#)(.*)')
+  return [search_re.sub(comment_replace, line) for line in input]
+
+
+def quote_replace(matchobj):
+  return "%s%s%s%s" % (matchobj.group(1),
+                       matchobj.group(2),
+                       'x'*len(matchobj.group(3)),
+                       matchobj.group(2))
+
+
+def mask_quotes(input):
+  """Mask the quoted strings so we skip braces inside quoted strings."""
+  search_re = re.compile(r'(.*?)' + QUOTE_RE_STR)
+  return [search_re.sub(quote_replace, line) for line in input]
+
+
+def do_split(input, masked_input, search_re):
+  output = []
+  mask_output = []
+  for (line, masked_line) in zip(input, masked_input):
+    m = search_re.match(masked_line)
+    while m:
+      split = len(m.group(1))
+      line = line[:split] + r'\n' + line[split:]
+      masked_line = masked_line[:split] + r'\n' + masked_line[split:]
+      m = search_re.match(masked_line)
+    output.extend(line.split(r'\n'))
+    mask_output.extend(masked_line.split(r'\n'))
+  return (output, mask_output)
+
+
+def split_double_braces(input):
+  """Masks out the quotes and comments, and then splits appropriate
+  lines (lines that matche the double_*_brace re's above) before
+  indenting them below.
+
+  These are used to split lines which have multiple braces on them, so
+  that the indentation looks prettier when all laid out (e.g. closing
+  braces make a nice diagonal line).
+  """
+  double_open_brace_re = re.compile(r'(.*?[\[\{\(,])(\s*)([\[\{\(])')
+  double_close_brace_re = re.compile(r'(.*?[\]\}\)],?)(\s*)([\]\}\)])')
+
+  masked_input = mask_quotes(input)
+  masked_input = mask_comments(masked_input)
+
+  (output, mask_output) = do_split(input, masked_input, double_open_brace_re)
+  (output, mask_output) = do_split(output, mask_output, double_close_brace_re)
+
+  return output
+
+
+def count_braces(line):
+  """keeps track of the number of braces on a given line and returns the result.
+
+  It starts at zero and subtracts for closed braces, and adds for open braces.
+  """
+  open_braces = ['[', '(', '{']
+  close_braces = [']', ')', '}']
+  closing_prefix_re = re.compile(r'(.*?[^\s\]\}\)]+.*?)([\]\}\)],?)\s*$')
+  cnt = 0
+  stripline = COMMENT_RE.sub(r'', line)
+  stripline = QUOTE_RE.sub(r"''", stripline)
+  for char in stripline:
+    for brace in open_braces:
+      if char == brace:
+        cnt += 1
+    for brace in close_braces:
+      if char == brace:
+        cnt -= 1
+
+  after = False
+  if cnt > 0:
+    after = True
+
+  # This catches the special case of a closing brace having something
+  # other than just whitespace ahead of it -- we don't want to
+  # unindent that until after this line is printed so it stays with
+  # the previous indentation level.
+  if cnt < 0 and closing_prefix_re.match(stripline):
+    after = True
+  return (cnt, after)
+
+
+def prettyprint_input(lines):
+  """Does the main work of indenting the input based on the brace counts."""
+  indent = 0
+  basic_offset = 2
+  last_line = ""
+  for line in lines:
+    if COMMENT_RE.match(line):
+      print line
+    else:
+      line = line.strip('\r\n\t ')  # Otherwise doesn't strip \r on Unix.
+      if len(line) > 0:
+        (brace_diff, after) = count_braces(line)
+        if brace_diff != 0:
+          if after:
+            print " " * (basic_offset * indent) + line
+            indent += brace_diff
+          else:
+            indent += brace_diff
+            print " " * (basic_offset * indent) + line
+        else:
+          print " " * (basic_offset * indent) + line
+      else:
+        print ""
+      last_line = line
+
+
+def main():
+  if len(sys.argv) > 1:
+    data = open(sys.argv[1]).read().splitlines()
+  else:
+    data = sys.stdin.read().splitlines()
+  # Split up the double braces.
+  lines = split_double_braces(data)
+
+  # Indent and print the output.
+  prettyprint_input(lines)
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/gyp/tools/pretty_sln.py b/gyp/tools/pretty_sln.py
new file mode 100755 (executable)
index 0000000..3195d85
--- /dev/null
@@ -0,0 +1,168 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Prints the information in a sln file in a diffable way.
+
+   It first outputs each projects in alphabetical order with their
+   dependencies.
+
+   Then it outputs a possible build order.
+"""
+
+__author__ = 'nsylvain (Nicolas Sylvain)'
+
+import os
+import re
+import sys
+import pretty_vcproj
+
+def BuildProject(project, built, projects, deps):
+  # if all dependencies are done, we can build it, otherwise we try to build the
+  # dependency.
+  # This is not infinite-recursion proof.
+  for dep in deps[project]:
+    if dep not in built:
+      BuildProject(dep, built, projects, deps)
+  print project
+  built.append(project)
+
+def ParseSolution(solution_file):
+  # All projects, their clsid and paths.
+  projects = dict()
+
+  # A list of dependencies associated with a project.
+  dependencies = dict()
+
+  # Regular expressions that matches the SLN format.
+  # The first line of a project definition.
+  begin_project = re.compile(('^Project\("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
+                              '}"\) = "(.*)", "(.*)", "(.*)"$'))
+  # The last line of a project definition.
+  end_project = re.compile('^EndProject$')
+  # The first line of a dependency list.
+  begin_dep = re.compile('ProjectSection\(ProjectDependencies\) = postProject$')
+  # The last line of a dependency list.
+  end_dep = re.compile('EndProjectSection$')
+  # A line describing a dependency.
+  dep_line = re.compile(' *({.*}) = ({.*})$')
+
+  in_deps = False
+  solution = open(solution_file)
+  for line in solution:
+    results = begin_project.search(line)
+    if results:
+      # Hack to remove icu because the diff is too different.
+      if results.group(1).find('icu') != -1:
+        continue
+      # We remove "_gyp" from the names because it helps to diff them.
+      current_project = results.group(1).replace('_gyp', '')
+      projects[current_project] = [results.group(2).replace('_gyp', ''),
+                                   results.group(3),
+                                   results.group(2)]
+      dependencies[current_project] = []
+      continue
+
+    results = end_project.search(line)
+    if results:
+      current_project = None
+      continue
+
+    results = begin_dep.search(line)
+    if results:
+      in_deps = True
+      continue
+
+    results = end_dep.search(line)
+    if results:
+      in_deps = False
+      continue
+
+    results = dep_line.search(line)
+    if results and in_deps and current_project:
+      dependencies[current_project].append(results.group(1))
+      continue
+
+  # Change all dependencies clsid to name instead.
+  for project in dependencies:
+    # For each dependencies in this project
+    new_dep_array = []
+    for dep in dependencies[project]:
+      # Look for the project name matching this cldis
+      for project_info in projects:
+        if projects[project_info][1] == dep:
+          new_dep_array.append(project_info)
+    dependencies[project] = sorted(new_dep_array)
+
+  return (projects, dependencies)
+
+def PrintDependencies(projects, deps):
+  print "---------------------------------------"
+  print "Dependencies for all projects"
+  print "---------------------------------------"
+  print "--                                   --"
+
+  for (project, dep_list) in sorted(deps.items()):
+    print "Project : %s" % project
+    print "Path : %s" % projects[project][0]
+    if dep_list:
+      for dep in dep_list:
+        print "  - %s" % dep
+    print ""
+
+  print "--                                   --"
+
+def PrintBuildOrder(projects, deps):
+  print "---------------------------------------"
+  print "Build order                            "
+  print "---------------------------------------"
+  print "--                                   --"
+
+  built = []
+  for (project, _) in sorted(deps.items()):
+    if project not in built:
+      BuildProject(project, built, projects, deps)
+
+  print "--                                   --"
+
+def PrintVCProj(projects):
+
+  for project in projects:
+    print "-------------------------------------"
+    print "-------------------------------------"
+    print project
+    print project
+    print project
+    print "-------------------------------------"
+    print "-------------------------------------"
+
+    project_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[1]),
+                                                projects[project][2]))
+
+    pretty = pretty_vcproj
+    argv = [ '',
+             project_path,
+             '$(SolutionDir)=%s\\' % os.path.dirname(sys.argv[1]),
+           ]
+    argv.extend(sys.argv[3:])
+    pretty.main(argv)
+
+def main():
+  # check if we have exactly 1 parameter.
+  if len(sys.argv) < 2:
+    print 'Usage: %s "c:\\path\\to\\project.sln"' % sys.argv[0]
+    return 1
+
+  (projects, deps) = ParseSolution(sys.argv[1])
+  PrintDependencies(projects, deps)
+  PrintBuildOrder(projects, deps)
+
+  if '--recursive' in sys.argv:
+    PrintVCProj(projects)
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/gyp/tools/pretty_vcproj.py b/gyp/tools/pretty_vcproj.py
new file mode 100755 (executable)
index 0000000..6099bd7
--- /dev/null
@@ -0,0 +1,329 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Make the format of a vcproj really pretty.
+
+   This script normalize and sort an xml. It also fetches all the properties
+   inside linked vsprops and include them explicitly in the vcproj.
+
+   It outputs the resulting xml to stdout.
+"""
+
+__author__ = 'nsylvain (Nicolas Sylvain)'
+
+import os
+import sys
+
+from xml.dom.minidom import parse
+from xml.dom.minidom import Node
+
+REPLACEMENTS = dict()
+ARGUMENTS = None
+
+
+class CmpTuple(object):
+  """Compare function between 2 tuple."""
+  def __call__(self, x, y):
+    return cmp(x[0], y[0])
+
+
+class CmpNode(object):
+  """Compare function between 2 xml nodes."""
+
+  def __call__(self, x, y):
+    def get_string(node):
+      node_string = "node"
+      node_string += node.nodeName
+      if node.nodeValue:
+        node_string += node.nodeValue
+
+      if node.attributes:
+        # We first sort by name, if present.
+        node_string += node.getAttribute("Name")
+
+        all_nodes = []
+        for (name, value) in node.attributes.items():
+          all_nodes.append((name, value))
+
+        all_nodes.sort(CmpTuple())
+        for (name, value) in all_nodes:
+          node_string += name
+          node_string += value
+
+      return node_string
+
+    return cmp(get_string(x), get_string(y))
+
+
+def PrettyPrintNode(node, indent=0):
+  if node.nodeType == Node.TEXT_NODE:
+    if node.data.strip():
+      print '%s%s' % (' '*indent, node.data.strip())
+    return
+
+  if node.childNodes:
+    node.normalize()
+  # Get the number of attributes
+  attr_count = 0
+  if node.attributes:
+    attr_count = node.attributes.length
+
+  # Print the main tag
+  if attr_count == 0:
+    print '%s<%s>' % (' '*indent, node.nodeName)
+  else:
+    print '%s<%s' % (' '*indent, node.nodeName)
+
+    all_attributes = []
+    for (name, value) in node.attributes.items():
+      all_attributes.append((name, value))
+      all_attributes.sort(CmpTuple())
+    for (name, value) in all_attributes:
+      print '%s  %s="%s"' % (' '*indent, name, value)
+    print '%s>' % (' '*indent)
+  if node.nodeValue:
+    print '%s  %s' % (' '*indent, node.nodeValue)
+
+  for sub_node in node.childNodes:
+    PrettyPrintNode(sub_node, indent=indent+2)
+  print '%s</%s>' % (' '*indent, node.nodeName)
+
+
+def FlattenFilter(node):
+  """Returns a list of all the node and sub nodes."""
+  node_list = []
+
+  if (node.attributes and
+      node.getAttribute('Name') == '_excluded_files'):
+      # We don't add the "_excluded_files" filter.
+    return []
+
+  for current in node.childNodes:
+    if current.nodeName == 'Filter':
+      node_list.extend(FlattenFilter(current))
+    else:
+      node_list.append(current)
+
+  return node_list
+
+
+def FixFilenames(filenames, current_directory):
+  new_list = []
+  for filename in filenames:
+    if filename:
+      for key in REPLACEMENTS:
+        filename = filename.replace(key, REPLACEMENTS[key])
+      os.chdir(current_directory)
+      filename = filename.strip('"\' ')
+      if filename.startswith('$'):
+        new_list.append(filename)
+      else:
+        new_list.append(os.path.abspath(filename))
+  return new_list
+
+
+def AbsoluteNode(node):
+  """Makes all the properties we know about in this node absolute."""
+  if node.attributes:
+    for (name, value) in node.attributes.items():
+      if name in ['InheritedPropertySheets', 'RelativePath',
+                  'AdditionalIncludeDirectories',
+                  'IntermediateDirectory', 'OutputDirectory',
+                  'AdditionalLibraryDirectories']:
+        # We want to fix up these paths
+        path_list = value.split(';')
+        new_list = FixFilenames(path_list, os.path.dirname(ARGUMENTS[1]))
+        node.setAttribute(name, ';'.join(new_list))
+      if not value:
+        node.removeAttribute(name)
+
+
+def CleanupVcproj(node):
+  """For each sub node, we call recursively this function."""
+  for sub_node in node.childNodes:
+    AbsoluteNode(sub_node)
+    CleanupVcproj(sub_node)
+
+  # Normalize the node, and remove all extranous whitespaces.
+  for sub_node in node.childNodes:
+    if sub_node.nodeType == Node.TEXT_NODE:
+      sub_node.data = sub_node.data.replace("\r", "")
+      sub_node.data = sub_node.data.replace("\n", "")
+      sub_node.data = sub_node.data.rstrip()
+
+  # Fix all the semicolon separated attributes to be sorted, and we also
+  # remove the dups.
+  if node.attributes:
+    for (name, value) in node.attributes.items():
+      sorted_list = sorted(value.split(';'))
+      unique_list = []
+      for i in sorted_list:
+        if not unique_list.count(i):
+          unique_list.append(i)
+      node.setAttribute(name, ';'.join(unique_list))
+      if not value:
+        node.removeAttribute(name)
+
+  if node.childNodes:
+    node.normalize()
+
+  # For each node, take a copy, and remove it from the list.
+  node_array = []
+  while node.childNodes and node.childNodes[0]:
+    # Take a copy of the node and remove it from the list.
+    current = node.childNodes[0]
+    node.removeChild(current)
+
+    # If the child is a filter, we want to append all its children
+    # to this same list.
+    if current.nodeName == 'Filter':
+      node_array.extend(FlattenFilter(current))
+    else:
+      node_array.append(current)
+
+
+  # Sort the list.
+  node_array.sort(CmpNode())
+
+  # Insert the nodes in the correct order.
+  for new_node in node_array:
+    # But don't append empty tool node.
+    if new_node.nodeName == 'Tool':
+      if new_node.attributes and new_node.attributes.length == 1:
+        # This one was empty.
+        continue
+    if new_node.nodeName == 'UserMacro':
+      continue
+    node.appendChild(new_node)
+
+
+def GetConfiguationNodes(vcproj):
+  #TODO(nsylvain): Find a better way to navigate the xml.
+  nodes = []
+  for node in vcproj.childNodes:
+    if node.nodeName == "Configurations":
+      for sub_node in node.childNodes:
+        if sub_node.nodeName == "Configuration":
+          nodes.append(sub_node)
+
+  return nodes
+
+
+def GetChildrenVsprops(filename):
+  dom = parse(filename)
+  if dom.documentElement.attributes:
+    vsprops = dom.documentElement.getAttribute('InheritedPropertySheets')
+    return FixFilenames(vsprops.split(';'), os.path.dirname(filename))
+  return []
+
+def SeekToNode(node1, child2):
+  # A text node does not have properties.
+  if child2.nodeType == Node.TEXT_NODE:
+    return None
+
+  # Get the name of the current node.
+  current_name = child2.getAttribute("Name")
+  if not current_name:
+    # There is no name. We don't know how to merge.
+    return None
+
+  # Look through all the nodes to find a match.
+  for sub_node in node1.childNodes:
+    if sub_node.nodeName == child2.nodeName:
+      name = sub_node.getAttribute("Name")
+      if name == current_name:
+        return sub_node
+
+  # No match. We give up.
+  return None
+
+
+def MergeAttributes(node1, node2):
+  # No attributes to merge?
+  if not node2.attributes:
+    return
+
+  for (name, value2) in node2.attributes.items():
+    # Don't merge the 'Name' attribute.
+    if name == 'Name':
+      continue
+    value1 = node1.getAttribute(name)
+    if value1:
+      # The attribute exist in the main node. If it's equal, we leave it
+      # untouched, otherwise we concatenate it.
+      if value1 != value2:
+        node1.setAttribute(name, ';'.join([value1, value2]))
+    else:
+      # The attribute does nto exist in the main node. We append this one.
+      node1.setAttribute(name, value2)
+
+    # If the attribute was a property sheet attributes, we remove it, since
+    # they are useless.
+    if name == 'InheritedPropertySheets':
+      node1.removeAttribute(name)
+
+
+def MergeProperties(node1, node2):
+  MergeAttributes(node1, node2)
+  for child2 in node2.childNodes:
+    child1 = SeekToNode(node1, child2)
+    if child1:
+      MergeProperties(child1, child2)
+    else:
+      node1.appendChild(child2.cloneNode(True))
+
+
+def main(argv):
+  """Main function of this vcproj prettifier."""
+  global ARGUMENTS
+  ARGUMENTS = argv
+
+  # check if we have exactly 1 parameter.
+  if len(argv) < 2:
+    print ('Usage: %s "c:\\path\\to\\vcproj.vcproj" [key1=value1] '
+           '[key2=value2]' % argv[0])
+    return 1
+
+  # Parse the keys
+  for i in range(2, len(argv)):
+    (key, value) = argv[i].split('=')
+    REPLACEMENTS[key] = value
+
+  # Open the vcproj and parse the xml.
+  dom = parse(argv[1])
+
+  # First thing we need to do is find the Configuration Node and merge them
+  # with the vsprops they include.
+  for configuration_node in GetConfiguationNodes(dom.documentElement):
+    # Get the property sheets associated with this configuration.
+    vsprops = configuration_node.getAttribute('InheritedPropertySheets')
+
+    # Fix the filenames to be absolute.
+    vsprops_list = FixFilenames(vsprops.strip().split(';'),
+                                os.path.dirname(argv[1]))
+
+    # Extend the list of vsprops with all vsprops contained in the current
+    # vsprops.
+    for current_vsprops in vsprops_list:
+      vsprops_list.extend(GetChildrenVsprops(current_vsprops))
+
+    # Now that we have all the vsprops, we need to merge them.
+    for current_vsprops in vsprops_list:
+      MergeProperties(configuration_node,
+                      parse(current_vsprops).documentElement)
+
+  # Now that everything is merged, we need to cleanup the xml.
+  CleanupVcproj(dom.documentElement)
+
+  # Finally, we use the prett xml function to print the vcproj back to the
+  # user.
+  #print dom.toprettyxml(newl="\n")
+  PrettyPrintNode(dom.documentElement)
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))