diff --git a/Makefile b/Makefile index f642c7e..81c19eb 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,323 @@ BUILDTYPE ?= Release all: out/Makefile - tools/gyp_node -f make $(MAKE) -C out BUILDTYPE=$(BUILDTYPE) -ln -fs out/Release/node node -ln -fs out/Debug/node node_g out/Release/node: all -out/Makefile: node.gyp deps/uv/uv.gyp +out/Makefile: common.gypi deps/uv/uv.gyp deps/http_parser/http_parser.gyp deps/zlib/zlib.gyp deps/v8/build/common.gypi deps/v8/tools/gyp/v8.gyp node.gyp options.gypi + tools/gyp_node -f make + +install uninstall: + @echo '`make $(@)` is not implemented yet. Bug bnoordhuis about it in #node.js' clean: rm -rf out distclean: - rm -rf out + -rm -rf out + -rm options.gypi + +test: all + python tools/test.py --mode=release simple message + +test-http1: all + python tools/test.py --mode=release --use-http1 simple message + +test-valgrind: all + python tools/test.py --mode=release --valgrind simple message + +test-all: all + python tools/test.py --mode=debug,release + +test-all-http1: all + python tools/test.py --mode=debug,release --use-http1 + +test-all-valgrind: all + python tools/test.py --mode=debug,release --valgrind + +test-release: all + python tools/test.py --mode=release + +test-debug: all + python tools/test.py --mode=debug + +test-message: all + python tools/test.py message + +test-simple: all + python tools/test.py simple + +test-pummel: all + python tools/test.py pummel + +test-internet: all + python tools/test.py internet + +UVTEST += simple/test-assert +UVTEST += simple/test-buffer +UVTEST += simple/test-c-ares +UVTEST += simple/test-chdir +UVTEST += simple/test-delayed-require +UVTEST += simple/test-eio-race2 +UVTEST += simple/test-eio-race4 +UVTEST += simple/test-event-emitter-add-listeners +UVTEST += simple/test-event-emitter-modify-in-emit +UVTEST += simple/test-event-emitter-num-args +UVTEST += simple/test-event-emitter-once +UVTEST += simple/test-event-emitter-remove-all-listeners +UVTEST += simple/test-event-emitter-remove-listeners +UVTEST += simple/test-exception-handler +UVTEST += simple/test-exception-handler2 +UVTEST += simple/test-exception-handler +UVTEST += simple/test-executable-path +UVTEST += simple/test-file-read-noexist +UVTEST += simple/test-file-write-stream +UVTEST += simple/test-fs-fsync +UVTEST += simple/test-fs-open +UVTEST += simple/test-fs-readfile-empty +UVTEST += simple/test-fs-read-file-sync +UVTEST += simple/test-fs-read-file-sync-hostname +UVTEST += simple/test-fs-sir-writes-alot +UVTEST += simple/test-fs-write +UVTEST += simple/test-fs-write-buffer +UVTEST += simple/test-fs-write-file +UVTEST += simple/test-fs-write-file-buffer +UVTEST += simple/test-fs-write-stream +UVTEST += simple/test-fs-write-stream-end +UVTEST += simple/test-fs-write-sync +UVTEST += simple/test-global +UVTEST += simple/test-http +UVTEST += simple/test-http-1.0 +UVTEST += simple/test-http-abort-client +UVTEST += simple/test-http-allow-req-after-204-res +UVTEST += simple/test-http-blank-header +UVTEST += simple/test-http-buffer-sanity +UVTEST += simple/test-http-cat +UVTEST += simple/test-http-chunked +UVTEST += simple/test-http-client-abort +UVTEST += simple/test-http-client-parse-error +UVTEST += simple/test-http-client-race +UVTEST += simple/test-http-client-race-2 +UVTEST += simple/test-http-client-upload +UVTEST += simple/test-http-client-upload-buf +UVTEST += simple/test-http-contentLength0 +UVTEST += simple/test-http-default-encoding +UVTEST += simple/test-http-dns-fail +UVTEST += simple/test-http-eof-on-connect +UVTEST += simple/test-http-exceptions +UVTEST += simple/test-http-expect-continue +UVTEST += simple/test-http-extra-response +UVTEST += simple/test-http-head-request +UVTEST += simple/test-http-head-response-has-no-body +UVTEST += simple/test-http-keep-alive +UVTEST += simple/test-http-keep-alive-close-on-header +UVTEST += simple/test-http-malformed-request +UVTEST += simple/test-http-many-keep-alive-connections +UVTEST += simple/test-http-mutable-headers +UVTEST += simple/test-http-parser +UVTEST += simple/test-http-proxy +UVTEST += simple/test-http-request-end +UVTEST += simple/test-http-response-close +UVTEST += simple/test-http-response-readable +UVTEST += simple/test-http-unix-socket +UVTEST += simple/test-http-server +UVTEST += simple/test-http-server-multiheaders +UVTEST += simple/test-http-set-cookies +UVTEST += simple/test-http-set-timeout +UVTEST += simple/test-http-set-trailers +UVTEST += simple/test-http-upgrade-agent +UVTEST += simple/test-http-upgrade-client +UVTEST += simple/test-http-upgrade-client2 +UVTEST += simple/test-http-upgrade-server +UVTEST += simple/test-http-upgrade-server2 +UVTEST += simple/test-http-wget +UVTEST += simple/test-http-write-empty-string +UVTEST += simple/test-http-wget +UVTEST += simple/test-mkdir-rmdir +UVTEST += simple/test-net-binary +UVTEST += simple/test-net-pingpong +UVTEST += simple/test-net-can-reset-timeout +UVTEST += simple/test-net-connect-buffer +UVTEST += simple/test-net-connect-timeout +UVTEST += simple/test-net-create-connection +UVTEST += simple/test-net-eaddrinuse +UVTEST += simple/test-net-isip +UVTEST += simple/test-net-keepalive +UVTEST += simple/test-net-pingpong +UVTEST += simple/test-net-reconnect +UVTEST += simple/test-net-remote-address-port +UVTEST += simple/test-net-server-bind +UVTEST += simple/test-net-server-max-connections +UVTEST += simple/test-net-server-try-ports +UVTEST += simple/test-net-stream +UVTEST += simple/test-net-socket-timeout +UVTEST += simple/test-next-tick +UVTEST += simple/test-next-tick-doesnt-hang +UVTEST += simple/test-next-tick-errors +UVTEST += simple/test-next-tick-ordering +UVTEST += simple/test-next-tick-ordering2 +UVTEST += simple/test-next-tick-starvation +UVTEST += simple/test-module-load-list +UVTEST += simple/test-path +UVTEST += simple/test-pipe-stream +UVTEST += simple/test-pump-file2tcp +UVTEST += simple/test-pump-file2tcp-noexist +UVTEST += simple/test-punycode +UVTEST += simple/test-querystring +UVTEST += simple/test-readdir +UVTEST += simple/test-readdouble +UVTEST += simple/test-readfloat +UVTEST += simple/test-readint +UVTEST += simple/test-readuint +UVTEST += simple/test-regress-GH-819 +UVTEST += simple/test-regress-GH-897 +UVTEST += simple/test-regression-object-prototype +UVTEST += simple/test-require-cache +UVTEST += simple/test-require-cache-without-stat +UVTEST += simple/test-require-exceptions +UVTEST += simple/test-require-resolve +UVTEST += simple/test-script-context +UVTEST += simple/test-script-new +UVTEST += simple/test-script-static-context +UVTEST += simple/test-script-static-new +UVTEST += simple/test-script-static-this +UVTEST += simple/test-script-this +UVTEST += simple/test-stream-pipe-cleanup +UVTEST += simple/test-stream-pipe-error-handling +UVTEST += simple/test-stream-pipe-event +UVTEST += simple/test-stream-pipe-multi +UVTEST += simple/test-string-decoder +UVTEST += simple/test-sys +UVTEST += simple/test-tcp-wrap +UVTEST += simple/test-tcp-wrap-connect +UVTEST += simple/test-tcp-wrap-listen +UVTEST += simple/test-timers-linked-list +UVTEST += simple/test-tty-stdout-end +UVTEST += simple/test-url +UVTEST += simple/test-utf8-scripts +UVTEST += simple/test-vm-create-context-circular-reference +UVTEST += simple/test-writedouble +UVTEST += simple/test-writefloat +UVTEST += simple/test-writeint +UVTEST += simple/test-writeuint +UVTEST += simple/test-zerolengthbufferbug +UVTEST += pummel/test-http-client-reconnect-bug +UVTEST += pummel/test-http-upload-timeout +UVTEST += pummel/test-net-many-clients +UVTEST += pummel/test-net-pause +UVTEST += pummel/test-net-pingpong-delay +UVTEST += pummel/test-net-timeout +UVTEST += pummel/test-timers +UVTEST += pummel/test-timer-wrap +UVTEST += pummel/test-timer-wrap2 +UVTEST += pummel/test-vm-memleak +UVTEST += internet/test-dns +UVTEST += simple/test-tls-client-abort +UVTEST += simple/test-tls-client-verify +UVTEST += simple/test-tls-connect +#UVTEST += simple/test-tls-ext-key-usage # broken +UVTEST += simple/test-tls-junk-closes-server +UVTEST += simple/test-tls-npn-server-client +UVTEST += simple/test-tls-request-timeout +#UVTEST += simple/test-tls-securepair-client # broken +UVTEST += simple/test-tls-securepair-server +#UVTEST += simple/test-tls-server-verify # broken +UVTEST += simple/test-tls-set-encoding + +# child_process +UVTEST += simple/test-child-process-exit-code +UVTEST += simple/test-child-process-buffering +UVTEST += simple/test-child-process-exec-cwd +UVTEST += simple/test-child-process-cwd +UVTEST += simple/test-child-process-env +UVTEST += simple/test-child-process-stdin +UVTEST += simple/test-child-process-ipc +UVTEST += simple/test-child-process-deprecated-api + + +test-uv: all + NODE_USE_UV=1 python tools/test.py $(UVTEST) + +test-uv-debug: all + NODE_USE_UV=1 python tools/test.py --mode=debug $(UVTEST) + + +apidoc_sources = $(wildcard doc/api/*.markdown) +apidocs = $(addprefix out/,$(apidoc_sources:.markdown=.html)) + +apidoc_dirs = out/doc out/doc/api/ out/doc/api/assets + +apiassets = $(subst api_assets,api/assets,$(addprefix out/,$(wildcard doc/api_assets/*))) + +website_files = \ + out/doc/index.html \ + out/doc/v0.4_announcement.html \ + out/doc/cla.html \ + out/doc/sh_main.js \ + out/doc/sh_javascript.min.js \ + out/doc/sh_vim-dark.css \ + out/doc/logo.png \ + out/doc/sponsored.png \ + out/doc/favicon.ico \ + out/doc/pipe.css + +doc: out/Release/node $(apidoc_dirs) $(website_files) $(apiassets) $(apidocs) + +$(apidoc_dirs): + mkdir -p $@ + +out/doc/api/assets/%: doc/api_assets/% out/doc/api/assets/ + cp $< $@ + +out/doc/%: doc/% + cp $< $@ + +out/doc/api/%.html: doc/api/%.markdown out/Release/node $(apidoc_dirs) $(apiassets) tools/doctool/doctool.js + out/Release/node tools/doctool/doctool.js doc/template.html $< > $@ + +out/doc/%: + +website-upload: doc + scp -r out/doc/* $(web_root) + +docopen: out/doc/api/all.html + -google-chrome out/doc/api/all.html + +docclean: + -rm -rf out/doc + +VERSION=$(shell git describe) +TARNAME=node-$(VERSION) + +#dist: doc/node.1 doc/api +dist: doc + git archive --format=tar --prefix=$(TARNAME)/ HEAD | tar xf - + mkdir -p $(TARNAME)/doc + cp doc/node.1 $(TARNAME)/doc/node.1 + cp -r out/doc/api $(TARNAME)/doc/api + rm -rf $(TARNAME)/deps/v8/test # too big + rm -rf $(TARNAME)/doc/logos # too big + tar -cf $(TARNAME).tar $(TARNAME) + rm -rf $(TARNAME) + gzip -f -9 $(TARNAME).tar + +bench: + benchmark/http_simple_bench.sh + +bench-idle: + ./node benchmark/idle_server.js & + sleep 1 + ./node benchmark/idle_clients.js & + +jslint: + PYTHONPATH=tools/closure_linter/ python tools/closure_linter/closure_linter/gjslint.py --unix_mode --strict --nojsdoc -r lib/ -r src/ -r test/ + +cpplint: + @python tools/cpplint.py $(wildcard src/*.cc src/*.h src/*.c) + +lint: jslint cpplint -.PHONY: clean distclean all +.PHONY: lint cpplint jslint bench clean docopen docclean doc dist distclean check uninstall install all program staticlib dynamiclib test test-all website-upload diff --git a/common.gypi b/common.gypi index f528f08..c3eae70 100644 --- a/common.gypi +++ b/common.gypi @@ -106,6 +106,13 @@ # ... or that C implementations shouldn't use # POSIX names '_CRT_NONSTDC_NO_DEPRECATE', + 'BUILDING_V8_SHARED=1', + 'BUILDING_UV_SHARED=1', + ], + }, { + 'defines': [ + '_LARGEFILE_SOURCE', + '_FILE_OFFSET_BITS=64', ], }], [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { diff --git a/configure b/configure index 0ec745c..d767508 100755 --- a/configure +++ b/configure @@ -3,6 +3,7 @@ import optparse import os import json +import subprocess import sys root_dir = os.path.dirname(__file__) @@ -102,6 +103,14 @@ parser.add_option("--dest-cpu", (options, args) = parser.parse_args() +def b(value): + """Returns the string 'true' if value is truthy, 'false' otherwise.""" + if value: + return 'true' + else: + return 'false' + + def pkg_config(pkg): cmd = os.popen('pkg-config --libs %s' % pkg, 'r') libs = cmd.readline().strip() @@ -145,9 +154,9 @@ def target_arch(): def configure_node(o): # TODO add gdb and dest_cpu - o['variables']['node_debug'] = 'true' if options.debug else 'false' + o['variables']['node_debug'] = b(options.debug) o['variables']['node_prefix'] = options.prefix if options.prefix else '' - o['variables']['node_use_dtrace'] = 'true' if options.with_dtrace else 'false' + o['variables']['node_use_dtrace'] = b(options.with_dtrace) o['variables']['host_arch'] = host_arch() o['variables']['target_arch'] = target_arch() @@ -161,8 +170,8 @@ def configure_libz(o): def configure_v8(o): - o['variables']['v8_use_snapshot'] = 'true' if not options.without_snapshot else 'false' - o['variables']['node_shared_v8'] = 'true' if options.shared_v8 else 'false' + o['variables']['v8_use_snapshot'] = b(not options.without_snapshot) + o['variables']['node_shared_v8'] = b(options.shared_v8) # assume shared_v8 if one of these is set? if options.shared_v8_libpath: @@ -174,7 +183,7 @@ def configure_v8(o): def configure_cares(o): - o['variables']['node_shared_cares'] = 'true' if options.shared_cares else 'false' + o['variables']['node_shared_cares'] = b(options.shared_cares) # assume shared_cares if one of these is set? if options.shared_cares_libpath: @@ -184,7 +193,7 @@ def configure_cares(o): def configure_openssl(o): - o['variables']['node_use_openssl'] = 'false' if options.without_ssl else 'true' + o['variables']['node_use_openssl'] = b(not options.without_ssl) if options.without_ssl: return @@ -205,10 +214,8 @@ def configure_openssl(o): else: o['cflags'] += cflags.split() - if libs or cflags or options.openssl_libpath or options.openssl_includes: - o['variables']['node_use_system_openssl'] = 'true' - else: - o['variables']['node_use_system_openssl'] = 'false' + o['variables']['node_use_system_openssl'] = b( + libs or cflags or options.openssl_libpath or options.openssl_includes) print "configure options:", options @@ -245,3 +252,4 @@ json.dump(output, f, indent=2, skipkeys=True) f.write("\n") f.close() +subprocess.call(['tools/gyp_node','-f', 'make']) diff --git a/node.gyp b/node.gyp index 14aa245..a400d56 100644 --- a/node.gyp +++ b/node.gyp @@ -103,8 +103,6 @@ 'defines': [ 'ARCH="<(target_arch)"', 'PLATFORM="<(OS)"', - '_LARGEFILE_SOURCE', - '_FILE_OFFSET_BITS=64', ], 'conditions': [ diff --git a/tools/gyp/PRESUBMIT.py b/tools/gyp/PRESUBMIT.py old mode 100755 new mode 100644 index 737584b..146327d --- a/tools/gyp/PRESUBMIT.py +++ b/tools/gyp/PRESUBMIT.py @@ -34,6 +34,16 @@ def CheckChangeOnCommit(input_api, output_api): input_api, output_api, 'http://gyp-status.appspot.com/status', 'http://gyp-status.appspot.com/current')) + + import sys + old_sys_path = sys.path + try: + sys.path = ['pylib', 'test/lib'] + sys.path + report.extend(input_api.canned_checks.RunPylint( + input_api, + output_api)) + finally: + sys.path = old_sys_path return report diff --git a/tools/gyp/buildbot/buildbot_run.py b/tools/gyp/buildbot/buildbot_run.py index adad7f9..df1cc8a 100755 --- a/tools/gyp/buildbot/buildbot_run.py +++ b/tools/gyp/buildbot/buildbot_run.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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. diff --git a/tools/gyp/pylib/gyp/MSVSNew.py b/tools/gyp/pylib/gyp/MSVSNew.py index ae8cbee..6906c7b 100644 --- a/tools/gyp/pylib/gyp/MSVSNew.py +++ b/tools/gyp/pylib/gyp/MSVSNew.py @@ -1,6 +1,4 @@ -#!/usr/bin/python2.4 - -# Copyright (c) 2009 Google Inc. All rights reserved. +# 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. @@ -62,7 +60,7 @@ def MakeGuid(name, seed='msvs_new'): #------------------------------------------------------------------------------ -class MSVSFolder: +class MSVSFolder(object): """Folder in a Visual Studio project or solution.""" def __init__(self, path, name = None, entries = None, @@ -103,7 +101,7 @@ def get_guid(self): #------------------------------------------------------------------------------ -class MSVSProject: +class MSVSProject(object): """Visual Studio project.""" def __init__(self, path, name = None, dependencies = None, guid = None, diff --git a/tools/gyp/pylib/gyp/MSVSProject.py b/tools/gyp/pylib/gyp/MSVSProject.py index fab11f9..4713787 100644 --- a/tools/gyp/pylib/gyp/MSVSProject.py +++ b/tools/gyp/pylib/gyp/MSVSProject.py @@ -1,6 +1,4 @@ -#!/usr/bin/python2.4 - -# Copyright (c) 2009 Google Inc. All rights reserved. +# 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. @@ -208,5 +206,3 @@ def WriteIfChanged(self): ] easy_xml.WriteXmlIfChanged(content, self.project_path, encoding="Windows-1252") - -#------------------------------------------------------------------------------ diff --git a/tools/gyp/pylib/gyp/MSVSSettings.py b/tools/gyp/pylib/gyp/MSVSSettings.py index 6b36482..bf3cc73 100644 --- a/tools/gyp/pylib/gyp/MSVSSettings.py +++ b/tools/gyp/pylib/gyp/MSVSSettings.py @@ -1,4 +1,3 @@ -#!/usr/bin/python # 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. diff --git a/tools/gyp/pylib/gyp/MSVSSettings_test.py b/tools/gyp/pylib/gyp/MSVSSettings_test.py old mode 100644 new mode 100755 index 199f98b..49e8a1d --- a/tools/gyp/pylib/gyp/MSVSSettings_test.py +++ b/tools/gyp/pylib/gyp/MSVSSettings_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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 @@ -1476,5 +1476,6 @@ def testConvertToMSBuildSettings_actual(self): self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) self._ExpectedWarnings([]) + if __name__ == '__main__': unittest.main() diff --git a/tools/gyp/pylib/gyp/MSVSToolFile.py b/tools/gyp/pylib/gyp/MSVSToolFile.py index fcad90a..25d97a1 100644 --- a/tools/gyp/pylib/gyp/MSVSToolFile.py +++ b/tools/gyp/pylib/gyp/MSVSToolFile.py @@ -1,5 +1,3 @@ -#!/usr/bin/python2.4 - # 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. diff --git a/tools/gyp/pylib/gyp/MSVSUserFile.py b/tools/gyp/pylib/gyp/MSVSUserFile.py index 423649f..8cc5def 100644 --- a/tools/gyp/pylib/gyp/MSVSUserFile.py +++ b/tools/gyp/pylib/gyp/MSVSUserFile.py @@ -1,5 +1,3 @@ -#!/usr/bin/python2.4 - # 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. diff --git a/tools/gyp/pylib/gyp/MSVSVersion.py b/tools/gyp/pylib/gyp/MSVSVersion.py old mode 100755 new mode 100644 index fd3e191..4958ee0 --- a/tools/gyp/pylib/gyp/MSVSVersion.py +++ b/tools/gyp/pylib/gyp/MSVSVersion.py @@ -1,4 +1,3 @@ -#!/usr/bin/python # 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. @@ -12,7 +11,7 @@ import sys -class VisualStudioVersion: +class VisualStudioVersion(object): """Information regarding a version of Visual Studio.""" def __init__(self, short_name, description, @@ -80,6 +79,7 @@ def _RegistryQueryBase(sysdir, key, value): return None return text + def _RegistryQuery(key, value=None): """Use reg.exe to read a particular key through _RegistryQueryBase. @@ -107,6 +107,7 @@ def _RegistryQuery(key, value=None): raise return text + def _RegistryGetValue(key, value): """Use reg.exe to obtain the value of a registry key. @@ -125,6 +126,7 @@ def _RegistryGetValue(key, value): return None return match.group(1) + def _RegistryKeyExists(key): """Use reg.exe to see if a key exists. diff --git a/tools/gyp/pylib/gyp/SCons.py b/tools/gyp/pylib/gyp/SCons.py index 9c57bcb..568645d 100644 --- a/tools/gyp/pylib/gyp/SCons.py +++ b/tools/gyp/pylib/gyp/SCons.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python - -# Copyright (c) 2009 Google Inc. All rights reserved. +# 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. @@ -196,5 +194,6 @@ class LoadableModuleTarget(CompilableSourcesTargetBase): 'loadable_module' : LoadableModuleTarget, } + def Target(spec): return TargetMap[spec.get('type')](spec) diff --git a/tools/gyp/pylib/gyp/__init__.py b/tools/gyp/pylib/gyp/__init__.py old mode 100644 new mode 100755 index 36d1b99..1402713 --- a/tools/gyp/pylib/gyp/__init__.py +++ b/tools/gyp/pylib/gyp/__init__.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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 @@ -11,6 +11,7 @@ import re import shlex import sys +import traceback # Default debug modes for GYP debug = {} @@ -20,9 +21,18 @@ DEBUG_VARIABLES = 'variables' DEBUG_INCLUDES = 'includes' + def DebugOutput(mode, message): - if mode in gyp.debug.keys(): - print "%s: %s" % (mode.upper(), message) + if 'all' in gyp.debug.keys() or mode in gyp.debug.keys(): + ctx = ('unknown', 0, 'unknown') + try: + f = traceback.extract_stack(limit=2) + if f: + ctx = f[0][:3] + except: + pass + print '%s:%s:%d:%s %s' % (mode.upper(), os.path.basename(ctx[0]), + ctx[1], ctx[2], message) def FindBuildFiles(): extension = '.gyp' @@ -266,8 +276,8 @@ def main(args): help='set DEPTH gyp variable to a relative path to PATH') 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" ' - 'and "general"') + 'mode for debugging GYP. Supported modes are "variables", ' + '"includes" and "general" or "all" for all of them.') parser.add_option('-S', '--suffix', dest='suffix', default='', help='suffix to add to generated files') parser.add_option('-G', dest='generator_flags', action='append', default=[], @@ -327,16 +337,12 @@ def main(args): options.formats = generate_formats else: # Nothing in the variable, default based on platform. - options.formats = [ {'darwin': 'xcode', - 'win32': 'msvs', - 'cygwin': 'msvs', - 'freebsd7': 'make', - 'freebsd8': 'make', - 'linux2': 'make', - 'linux3': 'make', - 'openbsd4': 'make', - 'openbsd5': 'make', - 'sunos5': 'make',}[sys.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') diff --git a/tools/gyp/pylib/gyp/common.py b/tools/gyp/pylib/gyp/common.py index 880820e..b5a6e82 100644 --- a/tools/gyp/pylib/gyp/common.py +++ b/tools/gyp/pylib/gyp/common.py @@ -1,6 +1,4 @@ -#!/usr/bin/python - -# Copyright (c) 2009 Google Inc. All rights reserved. +# 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. diff --git a/tools/gyp/pylib/gyp/easy_xml.py b/tools/gyp/pylib/gyp/easy_xml.py index 6624175..db54aad 100644 --- a/tools/gyp/pylib/gyp/easy_xml.py +++ b/tools/gyp/pylib/gyp/easy_xml.py @@ -1,5 +1,3 @@ -#!/usr/bin/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. diff --git a/tools/gyp/pylib/gyp/easy_xml_test.py b/tools/gyp/pylib/gyp/easy_xml_test.py old mode 100644 new mode 100755 index 9e59559..a2aa4f2 --- a/tools/gyp/pylib/gyp/easy_xml_test.py +++ b/tools/gyp/pylib/gyp/easy_xml_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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 diff --git a/tools/gyp/pylib/gyp/generator/dump_dependency_json.py b/tools/gyp/pylib/gyp/generator/dump_dependency_json.py index ebb7ff9..ada1d35 100644 --- a/tools/gyp/pylib/gyp/generator/dump_dependency_json.py +++ b/tools/gyp/pylib/gyp/generator/dump_dependency_json.py @@ -1,5 +1,3 @@ -#!/usr/bin/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. @@ -8,18 +6,18 @@ import gyp import gyp.common import json +import sys generator_wants_static_library_dependencies_adjusted = False generator_default_variables = { - 'OS': 'linux', } 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_EXT', + 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT', 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX', 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX', 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX', @@ -27,9 +25,21 @@ generator_default_variables[unused] = '' +def GetFlavor(params): + """Returns |params.flavor| if it's set, the system's default flavor else.""" + flavors = { + 'darwin': 'mac', + 'sunos5': 'solaris', + 'freebsd7': 'freebsd', + 'freebsd8': 'freebsd', + } + flavor = flavors.get(sys.platform, 'linux') + return params.get('flavor', flavor) + + def CalculateVariables(default_variables, params): generator_flags = params.get('generator_flags', {}) - default_variables['OS'] = generator_flags.get('os', 'linux') + default_variables['OS'] = generator_flags.get('os', GetFlavor(params)) def CalculateGeneratorInputInfo(params): diff --git a/tools/gyp/pylib/gyp/generator/gypd.py b/tools/gyp/pylib/gyp/generator/gypd.py index eeb8d57..22ef57f 100644 --- a/tools/gyp/pylib/gyp/generator/gypd.py +++ b/tools/gyp/pylib/gyp/generator/gypd.py @@ -1,5 +1,3 @@ -#!/usr/bin/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. diff --git a/tools/gyp/pylib/gyp/generator/gypsh.py b/tools/gyp/pylib/gyp/generator/gypsh.py index 75d20f5..bd405f4 100644 --- a/tools/gyp/pylib/gyp/generator/gypsh.py +++ b/tools/gyp/pylib/gyp/generator/gypsh.py @@ -1,5 +1,3 @@ -#!/usr/bin/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. diff --git a/tools/gyp/pylib/gyp/generator/make.py b/tools/gyp/pylib/gyp/generator/make.py index 1007672..3971360 100644 --- a/tools/gyp/pylib/gyp/generator/make.py +++ b/tools/gyp/pylib/gyp/generator/make.py @@ -1,5 +1,3 @@ -#!/usr/bin/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. @@ -26,21 +24,18 @@ import gyp import gyp.common import gyp.system_test -import os.path import os +import re +import shlex import sys -# Debugging-related imports -- remove me once we're solid. -import code -import pprint - generator_default_variables = { 'EXECUTABLE_PREFIX': '', 'EXECUTABLE_SUFFIX': '', 'STATIC_LIB_PREFIX': 'lib', 'SHARED_LIB_PREFIX': 'lib', 'STATIC_LIB_SUFFIX': '.a', - 'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/geni', + '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. @@ -452,10 +447,10 @@ def ensure_directory_exists(path): ) endef -# Declare "all" target first so it is the default, even though we don't have the -# deps yet. -.PHONY: all -all: +# 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: # Use FORCE_DO_CMD to force a target to run. Should be coupled with # do_cmd. @@ -489,6 +484,9 @@ def ensure_directory_exists(path): 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 "$@" """ SHARED_HEADER_SUN_COMMANDS = """ @@ -901,8 +899,6 @@ def GetCflags(self, configname): self._WarnUnimplemented('GCC_DEBUGGING_SYMBOLS') self._WarnUnimplemented('GCC_ENABLE_OBJC_EXCEPTIONS') self._WarnUnimplemented('GCC_ENABLE_OBJC_GC') - self._WarnUnimplemented('INFOPLIST_PREPROCESS') - self._WarnUnimplemented('INFOPLIST_PREPROCESSOR_DEFINITIONS') # TODO: This is exported correctly, but assigning to it is not supported. self._WarnUnimplemented('MACH_O_TYPE') @@ -917,7 +913,7 @@ def GetCflags(self, configname): config = self.spec['configurations'][self.configname] framework_dirs = config.get('mac_framework_dirs', []) for directory in framework_dirs: - cflags.append('-F ' + os.path.join(sdk_root, directory)) + cflags.append('-F ' + directory.replace('$(SDKROOT)', sdk_root)) self.configname = None return cflags @@ -1499,6 +1495,12 @@ def WriteActions(self, actions, extra_sources, extra_outputs, 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 @@ -1618,6 +1620,15 @@ def WriteRules(self, rules, extra_sources, extra_outputs, 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. + 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 @@ -1629,7 +1640,7 @@ def WriteRules(self, rules, extra_sources, extra_outputs, "$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; " "export LD_LIBRARY_PATH; " "%(cd_action)s%(mkdirs)s%(action)s" % { - 'action': gyp.common.EncodePOSIXShellList(action), + 'action': action, 'cd_action': cd_action, 'count': count, 'mkdirs': mkdirs, @@ -1666,6 +1677,7 @@ def WriteCopies(self, copies, extra_outputs, part_of_all, spec): outputs = [] for copy in copies: for path in copy['files']: + # Absolutify() calls normpath, stripping trailing slashes. path = Sourceify(self.Absolutify(path)) filename = os.path.split(path)[1] output = Sourceify(self.Absolutify(os.path.join(copy['destination'], @@ -1731,10 +1743,29 @@ def WriteMacInfoPlist(self, info_plist, bundle_deps, spec): assert ' ' not in info_plist, ( "Spaces in resource filenames not supported (%s)" % info_plist) info_plist = self.Absolutify(info_plist) + settings = self.xcode_settings + + # If explicilty set to preprocess the plist, invoke the C preprocessor and + # specify any defines as -D flags. + if settings.GetPerTargetSetting('INFOPLIST_PREPROCESS', 'NO') == 'YES': + # Create an intermediate file based on the path. + intermediate_plist = ('$(obj).$(TOOLSET)/$(TARGET)/' + + os.path.basename(info_plist)) + defines = shlex.split(settings.GetPerTargetSetting( + 'INFOPLIST_PREPROCESSOR_DEFINITIONS', '')) + 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 + path = generator_default_variables['PRODUCT_DIR'] - dest_plist = os.path.join(path, self.xcode_settings.GetBundlePlistPath()) + dest_plist = os.path.join(path, settings.GetBundlePlistPath()) dest_plist = QuoteSpaces(dest_plist) - extra_settings = self.xcode_settings.GetPerTargetSettings() + extra_settings = settings.GetPerTargetSettings() # plists can contain envvars and substitute them into the file.. self.WriteXcodeEnv(dest_plist, spec, additional_settings=extra_settings) self.WriteDoCmd([dest_plist], [info_plist], 'mac_tool,,,copy-info-plist', @@ -2007,6 +2038,8 @@ def WriteTarget(self, spec, configs, deps, link_deps, bundle_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) self.WriteList(ldflags, 'LDFLAGS_%s' % configname) libraries = spec.get('libraries') if libraries: @@ -2409,6 +2442,7 @@ def StripProductDir(s): # See /Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX\ Product\ Types.xcspec for FULL_PRODUCT_NAME 'FULL_PRODUCT_NAME' : 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, @@ -2453,14 +2487,66 @@ def WriteXcodeEnv(self, # GetXcodeEnv() for the full rationale. keys_to_not_absolutify = ('PRODUCT_NAME', 'FULL_PRODUCT_NAME') - # Perform some transformations that are required to mimic Xcode behavior. - for k in env: - # Values that are not strings but are, for example, lists or tuples such - # as LDFLAGS or CFLAGS, should not be written out because they are - # not needed and it's undefined how multi-valued keys should be written. - if not isinstance(env[k], str): + # First sort the list of keys, removing any non-string values. + # Values that are not strings but are, for example, lists or tuples such + # as LDFLAGS or CFLAGS, should not be written out because they are + # not needed and it's undefined how multi-valued keys should be written. + key_list = env.keys() + key_list.sort() + key_list = [k for k in key_list if isinstance(env[k], str)] + + # 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\-_]+)\)') + + # Phase 1: Create a set of edges of (DEPENDEE, DEPENDER) where in the graph, + # DEPENDEE -> DEPENDER. Also create sets of dependers and dependees. + edges = set() + dependees = set() + dependers = set() + for k in key_list: + matches = regex.findall(env[k]) + if not len(matches): continue + dependers.add(k) + for dependee in matches: + if dependee in env: + edges.add((dependee, k)) + dependees.add(dependee) + + # Phase 2: Create a list of graph nodes with no incoming edges. + sorted_nodes = [] + edgeless_nodes = dependees - dependers + + # Phase 3: Perform Kahn topological sort. + while len(edgeless_nodes): + # Find a node with no incoming edges, add it to the sorted list, and + # remove it from the list of nodes that aren't part of the graph. + node = edgeless_nodes.pop() + sorted_nodes.append(node) + key_list.remove(node) + + # Find all the edges between |node| and other nodes. + edges_to_node = [e for e in edges if e[0] == node] + for edge in edges_to_node: + edges.remove(edge) + # If the node connected to |node| by |edge| has no other incoming edges, + # add it to |edgeless_nodes|. + if not len([e for e in edges if e[1] == edge[1]]): + edgeless_nodes.add(edge[1]) + + # Any remaining edges indicate a cycle. + if len(edges): + raise Exception('Xcode environment variables are cyclically dependent: ' + + str(edges)) + + # Append the "nodes" not in the graph to those that were just sorted. + sorted_nodes.extend(key_list) + + # Perform some transformations that are required to mimic Xcode behavior. + for k in sorted_nodes: # For # foo := a\ b # the escaped space does the right thing. For @@ -2498,7 +2584,9 @@ def Absolutify(self, path): """Convert a subdirectory-relative path into a base-relative path. Skips over paths that contain variables.""" if '$(' in path: - return path + # path is no existing file in this case, but calling normpath is still + # important for trimming trailing slashes. + return os.path.normpath(path) return os.path.normpath(os.path.join(self.path, path)) @@ -2634,6 +2722,7 @@ def GenerateOutput(target_list, target_dicts, data, 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.""" @@ -2675,6 +2764,7 @@ def CalculateMakefilePath(build_file, base_name): flock_command= 'flock' header_params = { + 'default_target': default_target, 'builddir': builddir_name, 'default_configuration': default_configuration, 'flock': flock_command, @@ -2714,7 +2804,8 @@ def CalculateMakefilePath(build_file, base_name): if value[0] != '$': value = '$(abspath %s)' % value if key == 'LINK': - make_global_settings += '%s ?= %s %s\n' % (flock_command, key, value) + make_global_settings += ('%s ?= %s $(builddir)/linker.lock %s\n' % + (key, flock_command, value)) elif key in ['CC', 'CXX']: make_global_settings += ( 'ifneq (,$(filter $(origin %s), undefined default))\n' % key) diff --git a/tools/gyp/pylib/gyp/generator/msvs.py b/tools/gyp/pylib/gyp/generator/msvs.py index 0efea70..e9ead80 100644 --- a/tools/gyp/pylib/gyp/generator/msvs.py +++ b/tools/gyp/pylib/gyp/generator/msvs.py @@ -1,5 +1,3 @@ -#!/usr/bin/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. diff --git a/tools/gyp/pylib/gyp/generator/msvs_test.py b/tools/gyp/pylib/gyp/generator/msvs_test.py old mode 100644 new mode 100755 index 60d25ab..5a69c1c --- a/tools/gyp/pylib/gyp/generator/msvs_test.py +++ b/tools/gyp/pylib/gyp/generator/msvs_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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 diff --git a/tools/gyp/pylib/gyp/generator/ninja.py b/tools/gyp/pylib/gyp/generator/ninja.py index f044f37..b307da6 100644 --- a/tools/gyp/pylib/gyp/generator/ninja.py +++ b/tools/gyp/pylib/gyp/generator/ninja.py @@ -1,5 +1,3 @@ -#!/usr/bin/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. @@ -65,12 +63,6 @@ def QuoteShellArgument(arg): return "'" + arg.replace("'", "'" + '"\'"' + "'") + "'" -def MaybeQuoteShellArgument(arg): - if '"' in arg or ' ' in arg: - return QuoteShellArgument(arg) - return arg - - def InvertRelativePath(path): """Given a relative path like foo/bar, return the inverse relative path: the path from the relative path back to the origin dir. @@ -154,6 +146,15 @@ def ExpandSpecial(self, path, product_dir=None): return path + def ExpandRuleVariables(self, path, root, dirname, source, ext, 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): """Translate a gyp path to a ninja path. @@ -211,7 +212,8 @@ def WriteCollapsedDependencies(self, name, targets): def WriteSpec(self, spec, config): """The main entry point for NinjaWriter: write the build rules for a spec. - Returns the path to the build output, or None.""" + Returns the path to the build output, or None, and a list of targets for + dependencies of its compile steps.""" self.name = spec['target_name'] self.toolset = spec['toolset'] @@ -226,43 +228,56 @@ def WriteSpec(self, spec, config): spec['type'] = 'none' # Compute predepends for all rules. - # prebuild is the dependencies this target depends on before - # running any of its internal steps. - prebuild = [] + # 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 = [] if 'dependencies' in spec: for dep in spec['dependencies']: if dep in self.target_outputs: - prebuild.append(self.target_outputs[dep][0]) - prebuild = self.WriteCollapsedDependencies('predepends', prebuild) + input, precompile_input, linkable = self.target_outputs[dep] + actions_depends.append(input) + compile_depends.extend(precompile_input) + actions_depends = self.WriteCollapsedDependencies('actions_depends', + actions_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 = [] - sources_predepends = self.WriteActionsRulesCopies(spec, extra_sources, - prebuild) + sources_depends = self.WriteActionsRulesCopies(spec, extra_sources, + actions_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 = self.WriteCollapsedDependencies('compile_depends', + sources_depends or compile_depends) # Write out the compilation steps, if any. link_deps = [] sources = spec.get('sources', []) + extra_sources if sources: - link_deps = self.WriteSources(config, sources, - sources_predepends or prebuild) + link_deps = self.WriteSources(config, sources, compile_depends) # Some actions/rules output 'sources' that are already object files. link_deps += [self.GypPathToNinja(f) for f in sources if f.endswith('.o')] # The final output of our target depends on the last output of the # above steps. output = None - final_deps = link_deps or sources_predepends or prebuild + final_deps = link_deps or sources_depends or actions_depends if final_deps: - output = self.WriteTarget(spec, config, final_deps) + output = self.WriteTarget(spec, config, final_deps, + order_only=actions_depends) if self.name != output and self.toolset == 'target': # 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. self.ninja.build(self.name, 'phony', output) - return output + return output, compile_depends def WriteActionsRulesCopies(self, spec, extra_sources, prebuild): """Write out the Actions, Rules, and Copies steps. Return any outputs @@ -351,9 +366,8 @@ def WriteRules(self, rules, extra_sources, prebuild): # Gather the list of outputs, expanding $vars if possible. outputs = [] for output in rule['outputs']: - outputs.append(output.replace( - generator_default_variables['RULE_INPUT_ROOT'], root).replace( - generator_default_variables['RULE_INPUT_DIRNAME'], dirname)) + outputs.append(self.ExpandRuleVariables(output, root, dirname, + source, ext, basename)) if int(rule.get('process_outputs_as_sources', False)): extra_sources += outputs @@ -409,14 +423,17 @@ def WriteSources(self, config, sources, predepends): self.ninja.variable('cxx', '$cxx_host') self.WriteVariableList('defines', - ['-D' + MaybeQuoteShellArgument(ninja_syntax.escape(d)) + [QuoteShellArgument(ninja_syntax.escape('-D' + d)) for d in config.get('defines', [])]) self.WriteVariableList('includes', ['-I' + self.GypPathToNinja(i) for i in config.get('include_dirs', [])]) - self.WriteVariableList('cflags', config.get('cflags')) - self.WriteVariableList('cflags_c', config.get('cflags_c')) - self.WriteVariableList('cflags_cc', config.get('cflags_cc')) + self.WriteVariableList('cflags', map(self.ExpandSpecial, + config.get('cflags', []))) + self.WriteVariableList('cflags_c', map(self.ExpandSpecial, + config.get('cflags_c', []))) + self.WriteVariableList('cflags_cc', map(self.ExpandSpecial, + config.get('cflags_cc', []))) self.ninja.newline() outputs = [] for source in sources: @@ -437,7 +454,7 @@ def WriteSources(self, config, sources, predepends): self.ninja.newline() return outputs - def WriteTarget(self, spec, config, final_deps): + def WriteTarget(self, spec, config, final_deps, order_only): if spec['type'] == 'none': # This target doesn't have any explicit final output, but is instead # used for its effects before the final output (e.g. copies steps). @@ -460,7 +477,7 @@ def WriteTarget(self, spec, config, final_deps): if output_uses_linker: extra_deps = set() for dep in spec['dependencies']: - input, linkable = self.target_outputs.get(dep, (None, False)) + input, _, linkable = self.target_outputs.get(dep, (None, [], False)) if not input: continue if linkable: @@ -494,6 +511,7 @@ def WriteTarget(self, spec, config, final_deps): self.ninja.build(output, command, final_deps, implicit=list(implicit_deps), + order_only=order_only, variables=extra_bindings) return output @@ -711,10 +729,10 @@ def GenerateOutput(target_list, target_dicts, data, params): output_file))) master_ninja.subninja(output_file) - output = writer.WriteSpec(spec, config) + output, compile_depends = writer.WriteSpec(spec, config) if output: linkable = spec['type'] in ('static_library', 'shared_library') - target_outputs[qualified_target] = (output, linkable) + target_outputs[qualified_target] = (output, compile_depends, linkable) if qualified_target in all_targets: all_outputs.add(output) diff --git a/tools/gyp/pylib/gyp/generator/scons.py b/tools/gyp/pylib/gyp/generator/scons.py index 623c6d5..9041887 100644 --- a/tools/gyp/pylib/gyp/generator/scons.py +++ b/tools/gyp/pylib/gyp/generator/scons.py @@ -1,5 +1,3 @@ -#!/usr/bin/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. diff --git a/tools/gyp/pylib/gyp/generator/xcode.py b/tools/gyp/pylib/gyp/generator/xcode.py index 066bb9f..8b17517 100644 --- a/tools/gyp/pylib/gyp/generator/xcode.py +++ b/tools/gyp/pylib/gyp/generator/xcode.py @@ -1,5 +1,3 @@ -#!/usr/bin/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. diff --git a/tools/gyp/pylib/gyp/input.py b/tools/gyp/pylib/gyp/input.py index 4204f63..ef30efa 100644 --- a/tools/gyp/pylib/gyp/input.py +++ b/tools/gyp/pylib/gyp/input.py @@ -1,5 +1,3 @@ -#!/usr/bin/python - # 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. diff --git a/tools/gyp/pylib/gyp/mac_tool.py b/tools/gyp/pylib/gyp/mac_tool.py old mode 100644 new mode 100755 index b64ea98..6470776 --- a/tools/gyp/pylib/gyp/mac_tool.py +++ b/tools/gyp/pylib/gyp/mac_tool.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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. @@ -16,10 +16,12 @@ import subprocess import sys + def main(args): executor = MacTool() executor.Dispatch(args) + class MacTool(object): """This class performs all the Mac tooling steps. The methods can either be executed directly, or dispatched from an argument list.""" @@ -185,5 +187,6 @@ def _DetectInputEncoding(self, file_name): else: return None + if __name__ == '__main__': sys.exit(main(sys.argv[1:])) diff --git a/tools/gyp/pylib/gyp/ninja_syntax.py b/tools/gyp/pylib/gyp/ninja_syntax.py index a873522..d4776fb 100644 --- a/tools/gyp/pylib/gyp/ninja_syntax.py +++ b/tools/gyp/pylib/gyp/ninja_syntax.py @@ -1,5 +1,3 @@ -#!/usr/bin/python - # This file comes from # https://github.com/martine/ninja/blob/master/misc/ninja_syntax.py # Do not edit! Edit the upstream one instead. diff --git a/tools/gyp/pylib/gyp/sun_tool.py b/tools/gyp/pylib/gyp/sun_tool.py old mode 100644 new mode 100755 index fe5d97d..90d59c8 --- a/tools/gyp/pylib/gyp/sun_tool.py +++ b/tools/gyp/pylib/gyp/sun_tool.py @@ -12,58 +12,12 @@ import subprocess import sys -def main(args): - executor = SunTool() - executor.Dispatch(args) - -class SunTool(object): - """This class performs all the SunOS 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]) - 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:])) -#!/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-sun-tool when using the Makefile -generator.""" - -import fcntl -import os -import struct -import subprocess -import sys def main(args): executor = SunTool() executor.Dispatch(args) + class SunTool(object): """This class performs all the SunOS tooling steps. The methods can either be executed directly, or dispatched from an argument list.""" @@ -92,5 +46,6 @@ def ExecFlock(self, lockfile, *cmd_list): fcntl.fcntl(fd, fcntl.F_SETLK, op) return subprocess.call(cmd_list) + if __name__ == '__main__': sys.exit(main(sys.argv[1:])) diff --git a/tools/gyp/pylib/gyp/system_test.py b/tools/gyp/pylib/gyp/system_test.py old mode 100644 new mode 100755 index 887d57d..4245f86 --- a/tools/gyp/pylib/gyp/system_test.py +++ b/tools/gyp/pylib/gyp/system_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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 @@ -9,6 +9,7 @@ import shutil import subprocess + def TestCommands(commands, files={}, env={}): """Run commands in a temporary directory, returning true if they all succeed. Return false on failures or if any commands produce output. @@ -64,7 +65,7 @@ def TestLinkerSupportsICF(cc_command='cc'): env={'cc': cc_command}) -if __name__ == '__main__': +def main(): # Run the various test functions and print the results. def RunTest(description, function, **kwargs): print "Testing " + description + ':', @@ -75,3 +76,8 @@ def RunTest(description, function, **kwargs): RunTest("ar 'T' flag", TestArSupportsT) RunTest("ar 'T' flag with ccache", TestArSupportsT, cc_command='ccache cc') RunTest("ld --threads", TestLinkerSupportsThreads) + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/gyp/pylib/gyp/xcodeproj_file.py b/tools/gyp/pylib/gyp/xcodeproj_file.py index fcf9abf..f6ee765 100644 --- a/tools/gyp/pylib/gyp/xcodeproj_file.py +++ b/tools/gyp/pylib/gyp/xcodeproj_file.py @@ -1,5 +1,3 @@ -#!/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. @@ -13,8 +11,8 @@ XCODE PROJECT FILES -The generator targets the file format as written by Xcode 3.1 (specifically, -3.1.2), but past experience has taught that the format has not changed +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. @@ -2444,7 +2442,7 @@ class PBXProject(XCContainerPortal): 'attributes': [0, dict, 0, 0], 'buildConfigurationList': [0, XCConfigurationList, 1, 1, XCConfigurationList()], - 'compatibilityVersion': [0, str, 0, 1, 'Xcode 3.1'], + '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, ''], diff --git a/tools/gyp/pylib/gyp/xml_fix.py b/tools/gyp/pylib/gyp/xml_fix.py index 20f782d..5de8481 100644 --- a/tools/gyp/pylib/gyp/xml_fix.py +++ b/tools/gyp/pylib/gyp/xml_fix.py @@ -1,4 +1,3 @@ -#!/usr/bin/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. diff --git a/tools/gyp/pylintrc b/tools/gyp/pylintrc new file mode 100644 index 0000000..d7c23d2 --- /dev/null +++ b/tools/gyp/pylintrc @@ -0,0 +1,307 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). +# C0103: Invalid name "NN" (should match [a-z_][a-z0-9_]{2,30}$) +# C0111: Missing docstring +# C0302: Too many lines in module (NN) +# R0902: Too many instance attributes (N/7) +# R0903: Too few public methods (N/2) +# R0904: Too many public methods (NN/20) +# R0912: Too many branches (NN/12) +# R0913: Too many arguments (N/5) +# R0914: Too many local variables (NN/15) +# R0915: Too many statements (NN/50) +# W0141: Used builtin function 'map' +# W0142: Used * or ** magic +# W0232: Class has no __init__ method +# W0511: TODO +# W0603: Using the global statement +# +# These should be enabled eventually: +# C0112: Empty docstring +# C0301: Line too long (NN/80) +# C0321: More than one statement on single line +# C0322: Operator not preceded by a space +# C0323: Operator not followed by a space +# C0324: Comma not followed by a space +# E0101: Explicit return in __init__ +# E0102: function already defined line NN +# E1002: Use of super on an old style class +# E1101: Instance of 'XX' has no 'YY' member +# E1103: Instance of 'XX' has no 'XX' member (but some types could not be inferred) +# E0602: Undefined variable 'XX' +# F0401: Unable to import 'XX' +# R0201: Method could be a function +# R0801: Similar lines in N files +# W0102: Dangerous default value {} as argument +# W0104: Statement seems to have no effect +# W0105: String statement has no effect +# W0108: Lambda may not be necessary +# W0201: Attribute 'XX' defined outside __init__ +# W0212: Access to a protected member XX of a client class +# W0221: Arguments number differs from overridden method +# W0223: Method 'XX' is abstract in class 'YY' but is not overridden +# W0231: __init__ method from base class 'XX' is not called +# W0301: Unnecessary semicolon +# W0311: Bad indentation. Found NN spaces, expected NN +# W0401: Wildcard import XX +# W0402: Uses of a deprecated module 'string' +# W0403: Relative import 'XX', should be 'YY.XX' +# W0404: Reimport 'XX' (imported line NN) +# W0601: Global variable 'XX' undefined at the module level +# W0602: Using global for 'XX' but no assignment is done +# W0611: Unused import pprint +# W0612: Unused variable 'XX' +# W0613: Unused argument 'XX' +# W0614: Unused import XX from wildcard import +# W0621: Redefining name 'XX' from outer scope (line NN) +# W0622: Redefining built-in 'NN' +# W0631: Using possibly undefined loop variable 'XX' +# W0701: Raising a string exception +# W0702: No exception type(s) specified +disable=C0103,C0111,C0302,R0902,R0903,R0904,R0912,R0913,R0914,R0915,W0141,W0142,W0232,W0511,W0603,C0112,C0301,C0321,C0322,C0323,C0324,E0101,E0102,E1002,E1101,E1103,E0602,F0401,R0201,R0801,W0102,W0104,W0105,W0108,W0201,W0212,W0221,W0223,W0231,W0301,W0311,W0401,W0402,W0403,W0404,W0601,W0602,W0611,W0612,W0613,W0614,W0621,W0622,W0631,W0701,W0702 + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html +output-format=text + +# Include message's id in output +include-ids=yes + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (RP0004). +comment=no + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the beginning of the name of dummy variables +# (i.e. not used). +dummy-variables-rgx=_|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/tools/gyp/test/actions-bare/gyptest-bare.py b/tools/gyp/test/actions-bare/gyptest-bare.py new file mode 100755 index 0000000..b0c1093 --- /dev/null +++ b/tools/gyp/test/actions-bare/gyptest-bare.py @@ -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/tools/gyp/test/actions-bare/src/bare.gyp b/tools/gyp/test/actions-bare/src/bare.gyp new file mode 100644 index 0000000..3d28f09 --- /dev/null +++ b/tools/gyp/test/actions-bare/src/bare.gyp @@ -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/tools/gyp/test/actions-bare/src/bare.py b/tools/gyp/test/actions-bare/src/bare.py new file mode 100755 index 0000000..1230750 --- /dev/null +++ b/tools/gyp/test/actions-bare/src/bare.py @@ -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/tools/gyp/test/actions-multiple/gyptest-all.py b/tools/gyp/test/actions-multiple/gyptest-all.py new file mode 100755 index 0000000..7b94fef --- /dev/null +++ b/tools/gyp/test/actions-multiple/gyptest-all.py @@ -0,0 +1,42 @@ +#!/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 two actions can be attached to the same input files. +""" + +import TestGyp + +test = TestGyp.TestGyp() + +test.run_gyp('actions.gyp', chdir='src') + +test.relocate('src', 'relocate/src') + +# 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/tools/gyp/test/actions-multiple/src/actions.gyp b/tools/gyp/test/actions-multiple/src/actions.gyp new file mode 100644 index 0000000..2d721ff --- /dev/null +++ b/tools/gyp/test/actions-multiple/src/actions.gyp @@ -0,0 +1,165 @@ +# 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, + }, + ], + }, + ], +} diff --git a/tools/gyp/test/actions-multiple/src/copy.py b/tools/gyp/test/actions-multiple/src/copy.py new file mode 100755 index 0000000..0774679 --- /dev/null +++ b/tools/gyp/test/actions-multiple/src/copy.py @@ -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/tools/gyp/test/actions-multiple/src/filter.py b/tools/gyp/test/actions-multiple/src/filter.py new file mode 100755 index 0000000..f61a5fa --- /dev/null +++ b/tools/gyp/test/actions-multiple/src/filter.py @@ -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/tools/gyp/test/actions-multiple/src/foo.c b/tools/gyp/test/actions-multiple/src/foo.c new file mode 100644 index 0000000..23c4ef7 --- /dev/null +++ b/tools/gyp/test/actions-multiple/src/foo.c @@ -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 + +void foo(void) { + printf("foo\n"); +} diff --git a/tools/gyp/test/actions-multiple/src/input.txt b/tools/gyp/test/actions-multiple/src/input.txt new file mode 100644 index 0000000..c7c7da3 --- /dev/null +++ b/tools/gyp/test/actions-multiple/src/input.txt @@ -0,0 +1 @@ +hello there diff --git a/tools/gyp/test/actions-multiple/src/main.c b/tools/gyp/test/actions-multiple/src/main.c new file mode 100644 index 0000000..0a420b9 --- /dev/null +++ b/tools/gyp/test/actions-multiple/src/main.c @@ -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 + +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/tools/gyp/test/actions-subdir/gyptest-action.py b/tools/gyp/test/actions-subdir/gyptest-action.py new file mode 100755 index 0000000..09cfef1 --- /dev/null +++ b/tools/gyp/test/actions-subdir/gyptest-action.py @@ -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/tools/gyp/test/actions-subdir/src/make-file.py b/tools/gyp/test/actions-subdir/src/make-file.py new file mode 100755 index 0000000..74e5581 --- /dev/null +++ b/tools/gyp/test/actions-subdir/src/make-file.py @@ -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/tools/gyp/test/actions-subdir/src/none.gyp b/tools/gyp/test/actions-subdir/src/none.gyp new file mode 100644 index 0000000..23f8d25 --- /dev/null +++ b/tools/gyp/test/actions-subdir/src/none.gyp @@ -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/tools/gyp/test/actions-subdir/src/subdir/make-subdir-file.py b/tools/gyp/test/actions-subdir/src/subdir/make-subdir-file.py new file mode 100755 index 0000000..80ce19a --- /dev/null +++ b/tools/gyp/test/actions-subdir/src/subdir/make-subdir-file.py @@ -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/tools/gyp/test/actions-subdir/src/subdir/subdir.gyp b/tools/gyp/test/actions-subdir/src/subdir/subdir.gyp new file mode 100644 index 0000000..0315d4e --- /dev/null +++ b/tools/gyp/test/actions-subdir/src/subdir/subdir.gyp @@ -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/tools/gyp/test/actions/gyptest-all.py b/tools/gyp/test/actions/gyptest-all.py new file mode 100755 index 0000000..ad04f1f --- /dev/null +++ b/tools/gyp/test/actions/gyptest-all.py @@ -0,0 +1,101 @@ +#!/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 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. +if test.format == 'ninja': + 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/tools/gyp/test/actions/gyptest-default.py b/tools/gyp/test/actions/gyptest-default.py new file mode 100755 index 0000000..b5bf7e9 --- /dev/null +++ b/tools/gyp/test/actions/gyptest-default.py @@ -0,0 +1,68 @@ +#!/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 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. +if test.format == 'ninja': + 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/tools/gyp/test/actions/gyptest-errors.py b/tools/gyp/test/actions/gyptest-errors.py new file mode 100755 index 0000000..e1ef883 --- /dev/null +++ b/tools/gyp/test/actions/gyptest-errors.py @@ -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/tools/gyp/test/actions/src/action_missing_name.gyp b/tools/gyp/test/actions/src/action_missing_name.gyp new file mode 100644 index 0000000..00424c3 --- /dev/null +++ b/tools/gyp/test/actions/src/action_missing_name.gyp @@ -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/tools/gyp/test/actions/src/actions.gyp b/tools/gyp/test/actions/src/actions.gyp new file mode 100644 index 0000000..5d2db19 --- /dev/null +++ b/tools/gyp/test/actions/src/actions.gyp @@ -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/tools/gyp/test/actions/src/confirm-dep-files.py b/tools/gyp/test/actions/src/confirm-dep-files.py new file mode 100755 index 0000000..3b84630 --- /dev/null +++ b/tools/gyp/test/actions/src/confirm-dep-files.py @@ -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/tools/gyp/test/actions/src/subdir1/counter.py b/tools/gyp/test/actions/src/subdir1/counter.py new file mode 100755 index 0000000..3612d7d --- /dev/null +++ b/tools/gyp/test/actions/src/subdir1/counter.py @@ -0,0 +1,46 @@ +#!/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, scons deletes any declared +# outputs, so we would lose our count if we just wrote to the given output file. +# (The other option is to use Precious() in the scons generator, but that seems +# too heavy-handed just to support this somewhat unrealistic test case, and +# might lead to unintended side-effects). +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/tools/gyp/test/actions/src/subdir1/executable.gyp b/tools/gyp/test/actions/src/subdir1/executable.gyp new file mode 100644 index 0000000..6a1ce4f --- /dev/null +++ b/tools/gyp/test/actions/src/subdir1/executable.gyp @@ -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/tools/gyp/test/actions/src/subdir1/make-prog1.py b/tools/gyp/test/actions/src/subdir1/make-prog1.py new file mode 100755 index 0000000..7ea1d8a --- /dev/null +++ b/tools/gyp/test/actions/src/subdir1/make-prog1.py @@ -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 + +void prog1(void) +{ + printf("Hello from make-prog1.py\n"); +} +""" + +open(sys.argv[1], 'w').write(contents) + +sys.exit(0) diff --git a/tools/gyp/test/actions/src/subdir1/make-prog2.py b/tools/gyp/test/actions/src/subdir1/make-prog2.py new file mode 100755 index 0000000..0bfe497 --- /dev/null +++ b/tools/gyp/test/actions/src/subdir1/make-prog2.py @@ -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 + +void prog2(void) +{ + printf("Hello from make-prog2.py\n"); +} +""" + +open(sys.argv[1], 'w').write(contents) + +sys.exit(0) diff --git a/tools/gyp/test/actions/src/subdir1/program.c b/tools/gyp/test/actions/src/subdir1/program.c new file mode 100644 index 0000000..d5f661d --- /dev/null +++ b/tools/gyp/test/actions/src/subdir1/program.c @@ -0,0 +1,12 @@ +#include + +extern void prog1(void); +extern void prog2(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from program.c\n"); + prog1(); + prog2(); + return 0; +} diff --git a/tools/gyp/test/actions/src/subdir2/make-file.py b/tools/gyp/test/actions/src/subdir2/make-file.py new file mode 100755 index 0000000..fff0653 --- /dev/null +++ b/tools/gyp/test/actions/src/subdir2/make-file.py @@ -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/tools/gyp/test/actions/src/subdir2/none.gyp b/tools/gyp/test/actions/src/subdir2/none.gyp new file mode 100644 index 0000000..2caa97d --- /dev/null +++ b/tools/gyp/test/actions/src/subdir2/none.gyp @@ -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/tools/gyp/test/actions/src/subdir3/generate_main.py b/tools/gyp/test/actions/src/subdir3/generate_main.py new file mode 100755 index 0000000..b90b3aa --- /dev/null +++ b/tools/gyp/test/actions/src/subdir3/generate_main.py @@ -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 + +int main(int argc, char *argv[]) +{ + printf("Hello from generate_main.py\\n"); + return 0; +} +""" + +open(sys.argv[1], 'w').write(contents) + +sys.exit(0) diff --git a/tools/gyp/test/actions/src/subdir3/null_input.gyp b/tools/gyp/test/actions/src/subdir3/null_input.gyp new file mode 100644 index 0000000..9b0bea5 --- /dev/null +++ b/tools/gyp/test/actions/src/subdir3/null_input.gyp @@ -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/tools/gyp/test/additional-targets/gyptest-additional.py b/tools/gyp/test/additional-targets/gyptest-additional.py new file mode 100755 index 0000000..af35b33 --- /dev/null +++ b/tools/gyp/test/additional-targets/gyptest-additional.py @@ -0,0 +1,55 @@ +#!/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 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 scons, with 'dir1' before 'out/Default'? +if test.format in ('make', 'ninja'): + 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) + +test.pass_test() diff --git a/tools/gyp/test/additional-targets/src/all.gyp b/tools/gyp/test/additional-targets/src/all.gyp new file mode 100644 index 0000000..21c8308 --- /dev/null +++ b/tools/gyp/test/additional-targets/src/all.gyp @@ -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/tools/gyp/test/additional-targets/src/dir1/actions.gyp b/tools/gyp/test/additional-targets/src/dir1/actions.gyp new file mode 100644 index 0000000..5089c80 --- /dev/null +++ b/tools/gyp/test/additional-targets/src/dir1/actions.gyp @@ -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/tools/gyp/test/additional-targets/src/dir1/emit.py b/tools/gyp/test/additional-targets/src/dir1/emit.py new file mode 100755 index 0000000..fd31387 --- /dev/null +++ b/tools/gyp/test/additional-targets/src/dir1/emit.py @@ -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/tools/gyp/test/additional-targets/src/dir1/lib1.c b/tools/gyp/test/additional-targets/src/dir1/lib1.c new file mode 100644 index 0000000..df4cb10 --- /dev/null +++ b/tools/gyp/test/additional-targets/src/dir1/lib1.c @@ -0,0 +1,6 @@ +#ifdef _WIN32 +__declspec(dllexport) +#endif +int func1(void) { + return 42; +} diff --git a/tools/gyp/test/assembly/gyptest-assembly.py b/tools/gyp/test/assembly/gyptest-assembly.py new file mode 100755 index 0000000..09d612b --- /dev/null +++ b/tools/gyp/test/assembly/gyptest-assembly.py @@ -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 .hpp files are ignored when included in the source list on all +platforms. +""" + +import sys +import TestGyp + +# TODO(bradnelson): get this working for windows. +test = TestGyp.TestGyp(formats=['make', 'ninja', 'scons', 'xcode']) + +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/tools/gyp/test/assembly/src/as.bat b/tools/gyp/test/assembly/src/as.bat new file mode 100644 index 0000000..0a47382 --- /dev/null +++ b/tools/gyp/test/assembly/src/as.bat @@ -0,0 +1,4 @@ +@echo off +:: Mock windows assembler. +cl /c %1 /Fo"%2" + diff --git a/tools/gyp/test/assembly/src/assembly.gyp b/tools/gyp/test/assembly/src/assembly.gyp new file mode 100644 index 0000000..872dd5e --- /dev/null +++ b/tools/gyp/test/assembly/src/assembly.gyp @@ -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. + +{ + 'target_defaults': { + 'conditions': [ + ['OS=="win"', { + 'defines': ['PLATFORM_WIN'], + }], + ['OS=="mac"', { + 'defines': ['PLATFORM_MAC'], + }], + ['OS=="linux"', { + 'defines': ['PLATFORM_LINUX'], + }], + ], + }, + '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/tools/gyp/test/assembly/src/lib1.S b/tools/gyp/test/assembly/src/lib1.S new file mode 100644 index 0000000..e7102bf --- /dev/null +++ b/tools/gyp/test/assembly/src/lib1.S @@ -0,0 +1,10 @@ +#if PLATFORM_WINDOWS || PLATFORM_MAC +# define IDENTIFIER(n) _##n +#else /* Linux */ +# define IDENTIFIER(n) n +#endif + +.globl IDENTIFIER(lib1_function) +IDENTIFIER(lib1_function): + movl $42, %eax + ret diff --git a/tools/gyp/test/assembly/src/lib1.c b/tools/gyp/test/assembly/src/lib1.c new file mode 100644 index 0000000..be21ecd --- /dev/null +++ b/tools/gyp/test/assembly/src/lib1.c @@ -0,0 +1,3 @@ +int lib1_function(void) { + return 42; +} diff --git a/tools/gyp/test/assembly/src/program.c b/tools/gyp/test/assembly/src/program.c new file mode 100644 index 0000000..ecce3b0 --- /dev/null +++ b/tools/gyp/test/assembly/src/program.c @@ -0,0 +1,12 @@ +#include + +extern int lib1_function(void); + +int main(int argc, char *argv[]) +{ + fprintf(stdout, "Hello from program.c\n"); + fflush(stdout); + fprintf(stdout, "Got %d.\n", lib1_function()); + fflush(stdout); + return 0; +} diff --git a/tools/gyp/test/builddir/gyptest-all.py b/tools/gyp/test/builddir/gyptest-all.py new file mode 100755 index 0000000..885d680 --- /dev/null +++ b/tools/gyp/test/builddir/gyptest-all.py @@ -0,0 +1,77 @@ +#!/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 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. +test = TestGyp.TestGyp(formats=['!make', '!ninja']) + +test.run_gyp('prog1.gyp', '--depth=..', chdir='src') + +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/tools/gyp/test/builddir/gyptest-default.py b/tools/gyp/test/builddir/gyptest-default.py new file mode 100755 index 0000000..8c63026 --- /dev/null +++ b/tools/gyp/test/builddir/gyptest-default.py @@ -0,0 +1,77 @@ +#!/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 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. +test = TestGyp.TestGyp(formats=['!make', '!ninja']) + +test.run_gyp('prog1.gyp', '--depth=..', chdir='src') + +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/tools/gyp/test/builddir/src/builddir.gypi b/tools/gyp/test/builddir/src/builddir.gypi new file mode 100644 index 0000000..e3c6147 --- /dev/null +++ b/tools/gyp/test/builddir/src/builddir.gypi @@ -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. + +{ + 'target_defaults': { + 'configurations': { + 'Default': { + 'msvs_configuration_attributes': { + 'OutputDirectory': '<(DEPTH)\\builddir\Default', + }, + }, + }, + }, + 'scons_settings': { + 'sconsbuild_dir': '<(DEPTH)/builddir', + }, + 'xcode_settings': { + 'SYMROOT': '<(DEPTH)/builddir', + }, +} diff --git a/tools/gyp/test/builddir/src/func1.c b/tools/gyp/test/builddir/src/func1.c new file mode 100644 index 0000000..b8e6a06 --- /dev/null +++ b/tools/gyp/test/builddir/src/func1.c @@ -0,0 +1,6 @@ +#include + +void func1(void) +{ + printf("Hello from func1.c\n"); +} diff --git a/tools/gyp/test/builddir/src/func2.c b/tools/gyp/test/builddir/src/func2.c new file mode 100644 index 0000000..14aabac --- /dev/null +++ b/tools/gyp/test/builddir/src/func2.c @@ -0,0 +1,6 @@ +#include + +void func2(void) +{ + printf("Hello from func2.c\n"); +} diff --git a/tools/gyp/test/builddir/src/func3.c b/tools/gyp/test/builddir/src/func3.c new file mode 100644 index 0000000..3b4edea --- /dev/null +++ b/tools/gyp/test/builddir/src/func3.c @@ -0,0 +1,6 @@ +#include + +void func3(void) +{ + printf("Hello from func3.c\n"); +} diff --git a/tools/gyp/test/builddir/src/func4.c b/tools/gyp/test/builddir/src/func4.c new file mode 100644 index 0000000..732891b --- /dev/null +++ b/tools/gyp/test/builddir/src/func4.c @@ -0,0 +1,6 @@ +#include + +void func4(void) +{ + printf("Hello from func4.c\n"); +} diff --git a/tools/gyp/test/builddir/src/func5.c b/tools/gyp/test/builddir/src/func5.c new file mode 100644 index 0000000..18fdfab --- /dev/null +++ b/tools/gyp/test/builddir/src/func5.c @@ -0,0 +1,6 @@ +#include + +void func5(void) +{ + printf("Hello from func5.c\n"); +} diff --git a/tools/gyp/test/builddir/src/prog1.c b/tools/gyp/test/builddir/src/prog1.c new file mode 100644 index 0000000..674ca74 --- /dev/null +++ b/tools/gyp/test/builddir/src/prog1.c @@ -0,0 +1,10 @@ +#include + +extern void func1(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from prog1.c\n"); + func1(); + return 0; +} diff --git a/tools/gyp/test/builddir/src/prog1.gyp b/tools/gyp/test/builddir/src/prog1.gyp new file mode 100644 index 0000000..5b96f03 --- /dev/null +++ b/tools/gyp/test/builddir/src/prog1.gyp @@ -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/tools/gyp/test/builddir/src/subdir2/prog2.c b/tools/gyp/test/builddir/src/subdir2/prog2.c new file mode 100644 index 0000000..bbdf4f0 --- /dev/null +++ b/tools/gyp/test/builddir/src/subdir2/prog2.c @@ -0,0 +1,10 @@ +#include + +extern void func2(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from subdir2/prog2.c\n"); + func2(); + return 0; +} diff --git a/tools/gyp/test/builddir/src/subdir2/prog2.gyp b/tools/gyp/test/builddir/src/subdir2/prog2.gyp new file mode 100644 index 0000000..96299b6 --- /dev/null +++ b/tools/gyp/test/builddir/src/subdir2/prog2.gyp @@ -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/tools/gyp/test/builddir/src/subdir2/subdir3/prog3.c b/tools/gyp/test/builddir/src/subdir2/subdir3/prog3.c new file mode 100644 index 0000000..10c530b --- /dev/null +++ b/tools/gyp/test/builddir/src/subdir2/subdir3/prog3.c @@ -0,0 +1,10 @@ +#include + +extern void func3(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from subdir2/subdir3/prog3.c\n"); + func3(); + return 0; +} diff --git a/tools/gyp/test/builddir/src/subdir2/subdir3/prog3.gyp b/tools/gyp/test/builddir/src/subdir2/subdir3/prog3.gyp new file mode 100644 index 0000000..d7df43c --- /dev/null +++ b/tools/gyp/test/builddir/src/subdir2/subdir3/prog3.gyp @@ -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/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c b/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c new file mode 100644 index 0000000..dcba9a9 --- /dev/null +++ b/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c @@ -0,0 +1,10 @@ +#include + +extern void func4(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from subdir2/subdir3/subdir4/prog4.c\n"); + func4(); + return 0; +} diff --git a/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.gyp b/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.gyp new file mode 100644 index 0000000..862a8a1 --- /dev/null +++ b/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.gyp @@ -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/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c b/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c new file mode 100644 index 0000000..69132e5 --- /dev/null +++ b/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c @@ -0,0 +1,10 @@ +#include + +extern void func5(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from subdir2/subdir3/subdir4/subdir5/prog5.c\n"); + func5(); + return 0; +} diff --git a/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.gyp b/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.gyp new file mode 100644 index 0000000..fe1c9cb --- /dev/null +++ b/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.gyp @@ -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/tools/gyp/test/cflags/cflags.c b/tools/gyp/test/cflags/cflags.c new file mode 100644 index 0000000..c1e2452 --- /dev/null +++ b/tools/gyp/test/cflags/cflags.c @@ -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 + +int main(int argc, char *argv[]) +{ +#ifdef __OPTIMIZE__ + printf("Using an optimization flag\n"); +#else + printf("Using no optimization flag\n"); +#endif + return 0; +} diff --git a/tools/gyp/test/cflags/cflags.gyp b/tools/gyp/test/cflags/cflags.gyp new file mode 100644 index 0000000..9003fb1 --- /dev/null +++ b/tools/gyp/test/cflags/cflags.gyp @@ -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': 'cflags', + 'type': 'executable', + 'opt': '-Os', + 'sources': [ + 'cflags.c', + ], + }, + ], +} diff --git a/tools/gyp/test/cflags/gyptest-cflags.py b/tools/gyp/test/cflags/gyptest-cflags.py new file mode 100755 index 0000000..acc424a --- /dev/null +++ b/tools/gyp/test/cflags/gyptest-cflags.py @@ -0,0 +1,65 @@ +#!/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, and +the use of the environment during regeneration when the gyp file changes. +""" + +import os +import TestGyp + +env_stack = [] + + +def PushEnv(): + env_copy = os.environ.copy() + env_stack.append(env_copy) + +def PopEnv(): + os.eniron=env_stack.pop() + +# Regenerating build files when a gyp file changes is currently only supported +# by the make generator. +test = TestGyp.TestGyp(formats=['make']) + +try: + PushEnv() + os.environ['CFLAGS'] = '-O0' + test.run_gyp('cflags.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. + PopEnv() + +test.build('cflags.gyp') + +expect = """\ +Using no optimization flag +""" +test.run_built_executable('cflags', stdout=expect) + +test.sleep() + +try: + PushEnv() + os.environ['CFLAGS'] = '-O2' + test.run_gyp('cflags.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. + PopEnv() + +test.build('cflags.gyp') + +expect = """\ +Using an optimization flag +""" +test.run_built_executable('cflags', stdout=expect) + +test.pass_test() diff --git a/tools/gyp/test/compilable/gyptest-headers.py b/tools/gyp/test/compilable/gyptest-headers.py new file mode 100755 index 0000000..9176021 --- /dev/null +++ b/tools/gyp/test/compilable/gyptest-headers.py @@ -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/tools/gyp/test/compilable/src/headers.gyp b/tools/gyp/test/compilable/src/headers.gyp new file mode 100644 index 0000000..b6c2a88 --- /dev/null +++ b/tools/gyp/test/compilable/src/headers.gyp @@ -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/tools/gyp/test/compilable/src/lib1.cpp b/tools/gyp/test/compilable/src/lib1.cpp new file mode 100644 index 0000000..51bc31a --- /dev/null +++ b/tools/gyp/test/compilable/src/lib1.cpp @@ -0,0 +1,7 @@ +#include +#include "lib1.hpp" + +void lib1_function(void) { + fprintf(stdout, "Hello from lib1.c\n"); + fflush(stdout); +} diff --git a/tools/gyp/test/compilable/src/lib1.hpp b/tools/gyp/test/compilable/src/lib1.hpp new file mode 100644 index 0000000..72e63e8 --- /dev/null +++ b/tools/gyp/test/compilable/src/lib1.hpp @@ -0,0 +1,6 @@ +#ifndef _lib1_hpp +#define _lib1_hpp + +extern void lib1_function(void); + +#endif diff --git a/tools/gyp/test/compilable/src/program.cpp b/tools/gyp/test/compilable/src/program.cpp new file mode 100644 index 0000000..81420ba --- /dev/null +++ b/tools/gyp/test/compilable/src/program.cpp @@ -0,0 +1,9 @@ +#include +#include "lib1.hpp" + +int main(int argc, char *argv[]) { + fprintf(stdout, "Hello from program.c\n"); + fflush(stdout); + lib1_function(); + return 0; +} diff --git a/tools/gyp/test/configurations/basics/configurations.c b/tools/gyp/test/configurations/basics/configurations.c new file mode 100644 index 0000000..6c1f900 --- /dev/null +++ b/tools/gyp/test/configurations/basics/configurations.c @@ -0,0 +1,15 @@ +#include + +int main(int argc, char *argv[]) +{ +#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/tools/gyp/test/configurations/basics/configurations.gyp b/tools/gyp/test/configurations/basics/configurations.gyp new file mode 100644 index 0000000..93f1d8d --- /dev/null +++ b/tools/gyp/test/configurations/basics/configurations.gyp @@ -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/tools/gyp/test/configurations/basics/gyptest-configurations.py b/tools/gyp/test/configurations/basics/gyptest-configurations.py new file mode 100755 index 0000000..27cd2e8 --- /dev/null +++ b/tools/gyp/test/configurations/basics/gyptest-configurations.py @@ -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 build of an executable in three different configurations. +""" + +import TestGyp + +test = TestGyp.TestGyp() + +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/tools/gyp/test/configurations/inheritance/configurations.c b/tools/gyp/test/configurations/inheritance/configurations.c new file mode 100644 index 0000000..2d5565e --- /dev/null +++ b/tools/gyp/test/configurations/inheritance/configurations.c @@ -0,0 +1,21 @@ +#include + +int main(int argc, char *argv[]) +{ +#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/tools/gyp/test/configurations/inheritance/configurations.gyp b/tools/gyp/test/configurations/inheritance/configurations.gyp new file mode 100644 index 0000000..9441376 --- /dev/null +++ b/tools/gyp/test/configurations/inheritance/configurations.gyp @@ -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/tools/gyp/test/configurations/inheritance/gyptest-inheritance.py b/tools/gyp/test/configurations/inheritance/gyptest-inheritance.py new file mode 100755 index 0000000..22c73a3 --- /dev/null +++ b/tools/gyp/test/configurations/inheritance/gyptest-inheritance.py @@ -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. + +""" +Verifies build of an executable in three different configurations. +""" + +import TestGyp + +test = TestGyp.TestGyp() + +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/tools/gyp/test/configurations/invalid/actions.gyp b/tools/gyp/test/configurations/invalid/actions.gyp new file mode 100644 index 0000000..a6e4208 --- /dev/null +++ b/tools/gyp/test/configurations/invalid/actions.gyp @@ -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/tools/gyp/test/configurations/invalid/all_dependent_settings.gyp b/tools/gyp/test/configurations/invalid/all_dependent_settings.gyp new file mode 100644 index 0000000..b16a245 --- /dev/null +++ b/tools/gyp/test/configurations/invalid/all_dependent_settings.gyp @@ -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/tools/gyp/test/configurations/invalid/configurations.gyp b/tools/gyp/test/configurations/invalid/configurations.gyp new file mode 100644 index 0000000..2cfc960 --- /dev/null +++ b/tools/gyp/test/configurations/invalid/configurations.gyp @@ -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/tools/gyp/test/configurations/invalid/dependencies.gyp b/tools/gyp/test/configurations/invalid/dependencies.gyp new file mode 100644 index 0000000..74633f3 --- /dev/null +++ b/tools/gyp/test/configurations/invalid/dependencies.gyp @@ -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/tools/gyp/test/configurations/invalid/direct_dependent_settings.gyp b/tools/gyp/test/configurations/invalid/direct_dependent_settings.gyp new file mode 100644 index 0000000..8a0f2e9 --- /dev/null +++ b/tools/gyp/test/configurations/invalid/direct_dependent_settings.gyp @@ -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/tools/gyp/test/configurations/invalid/gyptest-configurations.py b/tools/gyp/test/configurations/invalid/gyptest-configurations.py new file mode 100755 index 0000000..d76cded --- /dev/null +++ b/tools/gyp/test/configurations/invalid/gyptest-configurations.py @@ -0,0 +1,38 @@ +#!/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', + 'target_name', + 'type', +] + +test = TestGyp.TestGyp() + +if test.format == 'scons': + test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n') + +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/tools/gyp/test/configurations/invalid/libraries.gyp b/tools/gyp/test/configurations/invalid/libraries.gyp new file mode 100644 index 0000000..c4014ed --- /dev/null +++ b/tools/gyp/test/configurations/invalid/libraries.gyp @@ -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/tools/gyp/test/configurations/invalid/link_settings.gyp b/tools/gyp/test/configurations/invalid/link_settings.gyp new file mode 100644 index 0000000..2f0e1c4 --- /dev/null +++ b/tools/gyp/test/configurations/invalid/link_settings.gyp @@ -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/tools/gyp/test/configurations/invalid/sources.gyp b/tools/gyp/test/configurations/invalid/sources.gyp new file mode 100644 index 0000000..b38cca0 --- /dev/null +++ b/tools/gyp/test/configurations/invalid/sources.gyp @@ -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/tools/gyp/test/configurations/invalid/target_name.gyp b/tools/gyp/test/configurations/invalid/target_name.gyp new file mode 100644 index 0000000..83baad9 --- /dev/null +++ b/tools/gyp/test/configurations/invalid/target_name.gyp @@ -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/tools/gyp/test/configurations/invalid/type.gyp b/tools/gyp/test/configurations/invalid/type.gyp new file mode 100644 index 0000000..bc55898 --- /dev/null +++ b/tools/gyp/test/configurations/invalid/type.gyp @@ -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/tools/gyp/test/configurations/target_platform/configurations.gyp b/tools/gyp/test/configurations/target_platform/configurations.gyp new file mode 100644 index 0000000..d15429f --- /dev/null +++ b/tools/gyp/test/configurations/target_platform/configurations.gyp @@ -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/tools/gyp/test/configurations/target_platform/front.c b/tools/gyp/test/configurations/target_platform/front.c new file mode 100644 index 0000000..12b1d0a --- /dev/null +++ b/tools/gyp/test/configurations/target_platform/front.c @@ -0,0 +1,8 @@ +#include + +const char *message(void); + +int main(int argc, char *argv[]) { + printf("%s\n", message()); + return 0; +} diff --git a/tools/gyp/test/configurations/target_platform/gyptest-target_platform.py b/tools/gyp/test/configurations/target_platform/gyptest-target_platform.py new file mode 100755 index 0000000..ae4e9e5 --- /dev/null +++ b/tools/gyp/test/configurations/target_platform/gyptest-target_platform.py @@ -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/tools/gyp/test/configurations/target_platform/left.c b/tools/gyp/test/configurations/target_platform/left.c new file mode 100644 index 0000000..1ce2ea1 --- /dev/null +++ b/tools/gyp/test/configurations/target_platform/left.c @@ -0,0 +1,3 @@ +const char *message(void) { + return "left"; +} diff --git a/tools/gyp/test/configurations/target_platform/right.c b/tools/gyp/test/configurations/target_platform/right.c new file mode 100644 index 0000000..b157849 --- /dev/null +++ b/tools/gyp/test/configurations/target_platform/right.c @@ -0,0 +1,3 @@ +const char *message(void) { + return "right"; +} diff --git a/tools/gyp/test/configurations/x64/configurations.c b/tools/gyp/test/configurations/x64/configurations.c new file mode 100644 index 0000000..72c97e3 --- /dev/null +++ b/tools/gyp/test/configurations/x64/configurations.c @@ -0,0 +1,12 @@ +#include + +int main(int argc, char *argv[]) { + 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/tools/gyp/test/configurations/x64/configurations.gyp b/tools/gyp/test/configurations/x64/configurations.gyp new file mode 100644 index 0000000..06ffa37 --- /dev/null +++ b/tools/gyp/test/configurations/x64/configurations.gyp @@ -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. + +{ + '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', + ], + }, + ], +} diff --git a/tools/gyp/test/configurations/x64/gyptest-x86.py b/tools/gyp/test/configurations/x64/gyptest-x86.py new file mode 100755 index 0000000..254ea6f --- /dev/null +++ b/tools/gyp/test/configurations/x64/gyptest-x86.py @@ -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 build of an executable in three different configurations. +""" + +import TestGyp + +test = TestGyp.TestGyp(formats=['msvs']) + +test.run_gyp('configurations.gyp') + +for platform in ['Win32', 'x64']: + test.set_configuration('Debug|%s' % platform) + test.build('configurations.gyp', rebuild=True) + try: + test.run_built_executable('configurations', + stdout=('Running %s\n' % platform)) + except WindowsError, e: + # Assume the exe is 64-bit if it can't load on 32-bit systems. + if platform == 'x64' and (e.errno == 193 or '[Error 193]' in str(e)): + continue + raise + +test.pass_test() diff --git a/tools/gyp/test/copies/gyptest-all.py b/tools/gyp/test/copies/gyptest-all.py new file mode 100755 index 0000000..8542ab7 --- /dev/null +++ b/tools/gyp/test/copies/gyptest-all.py @@ -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/tools/gyp/test/copies/gyptest-default.py b/tools/gyp/test/copies/gyptest-default.py new file mode 100755 index 0000000..a5d1bf9 --- /dev/null +++ b/tools/gyp/test/copies/gyptest-default.py @@ -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/tools/gyp/test/copies/gyptest-slash.py b/tools/gyp/test/copies/gyptest-slash.py new file mode 100755 index 0000000..81a4f42 --- /dev/null +++ b/tools/gyp/test/copies/gyptest-slash.py @@ -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/tools/gyp/test/copies/src/copies-slash.gyp b/tools/gyp/test/copies/src/copies-slash.gyp new file mode 100644 index 0000000..9bf54bd --- /dev/null +++ b/tools/gyp/test/copies/src/copies-slash.gyp @@ -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/tools/gyp/test/copies/src/copies.gyp b/tools/gyp/test/copies/src/copies.gyp new file mode 100644 index 0000000..ce2e0ca --- /dev/null +++ b/tools/gyp/test/copies/src/copies.gyp @@ -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/tools/gyp/test/copies/src/directory/file3 b/tools/gyp/test/copies/src/directory/file3 new file mode 100644 index 0000000..43f16f3 --- /dev/null +++ b/tools/gyp/test/copies/src/directory/file3 @@ -0,0 +1 @@ +file3 contents diff --git a/tools/gyp/test/copies/src/directory/file4 b/tools/gyp/test/copies/src/directory/file4 new file mode 100644 index 0000000..5f7270a --- /dev/null +++ b/tools/gyp/test/copies/src/directory/file4 @@ -0,0 +1 @@ +file4 contents diff --git a/tools/gyp/test/copies/src/directory/subdir/file5 b/tools/gyp/test/copies/src/directory/subdir/file5 new file mode 100644 index 0000000..41f4718 --- /dev/null +++ b/tools/gyp/test/copies/src/directory/subdir/file5 @@ -0,0 +1 @@ +file5 contents diff --git a/tools/gyp/test/copies/src/file1 b/tools/gyp/test/copies/src/file1 new file mode 100644 index 0000000..84d55c5 --- /dev/null +++ b/tools/gyp/test/copies/src/file1 @@ -0,0 +1 @@ +file1 contents diff --git a/tools/gyp/test/copies/src/file2 b/tools/gyp/test/copies/src/file2 new file mode 100644 index 0000000..af1b8ae --- /dev/null +++ b/tools/gyp/test/copies/src/file2 @@ -0,0 +1 @@ +file2 contents diff --git a/tools/gyp/test/copies/src/parentdir/subdir/file6 b/tools/gyp/test/copies/src/parentdir/subdir/file6 new file mode 100644 index 0000000..f5d5757 --- /dev/null +++ b/tools/gyp/test/copies/src/parentdir/subdir/file6 @@ -0,0 +1 @@ +file6 contents diff --git a/tools/gyp/test/cxxflags/cxxflags.cc b/tools/gyp/test/cxxflags/cxxflags.cc new file mode 100644 index 0000000..c1e2452 --- /dev/null +++ b/tools/gyp/test/cxxflags/cxxflags.cc @@ -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 + +int main(int argc, char *argv[]) +{ +#ifdef __OPTIMIZE__ + printf("Using an optimization flag\n"); +#else + printf("Using no optimization flag\n"); +#endif + return 0; +} diff --git a/tools/gyp/test/cxxflags/cxxflags.gyp b/tools/gyp/test/cxxflags/cxxflags.gyp new file mode 100644 index 0000000..24d883a --- /dev/null +++ b/tools/gyp/test/cxxflags/cxxflags.gyp @@ -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': 'cxxflags', + 'type': 'executable', + 'opt': '-Os', + 'sources': [ + 'cxxflags.cc', + ], + }, + ], +} diff --git a/tools/gyp/test/cxxflags/gyptest-cxxflags.py b/tools/gyp/test/cxxflags/gyptest-cxxflags.py new file mode 100755 index 0000000..2e5a6d9 --- /dev/null +++ b/tools/gyp/test/cxxflags/gyptest-cxxflags.py @@ -0,0 +1,65 @@ +#!/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, and +the use of the environment during regeneration when the gyp file changes. +""" + +import os +import TestGyp + +env_stack = [] + + +def PushEnv(): + env_copy = os.environ.copy() + env_stack.append(env_copy) + +def PopEnv(): + os.eniron=env_stack.pop() + +# Regenerating build files when a gyp file changes is currently only supported +# by the make generator. +test = TestGyp.TestGyp(formats=['make']) + +try: + PushEnv() + os.environ['CXXFLAGS'] = '-O0' + test.run_gyp('cxxflags.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. + PopEnv() + +test.build('cxxflags.gyp') + +expect = """\ +Using no optimization flag +""" +test.run_built_executable('cxxflags', stdout=expect) + +test.sleep() + +try: + PushEnv() + os.environ['CXXFLAGS'] = '-O2' + test.run_gyp('cxxflags.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. + PopEnv() + +test.build('cxxflags.gyp') + +expect = """\ +Using an optimization flag +""" +test.run_built_executable('cxxflags', stdout=expect) + +test.pass_test() diff --git a/tools/gyp/test/defines-escaping/defines-escaping.c b/tools/gyp/test/defines-escaping/defines-escaping.c new file mode 100644 index 0000000..4407572 --- /dev/null +++ b/tools/gyp/test/defines-escaping/defines-escaping.c @@ -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 + +int main(int argc, char *argv[]) +{ + printf(TEST_FORMAT, TEST_ARGS); + return 0; +} diff --git a/tools/gyp/test/defines-escaping/defines-escaping.gyp b/tools/gyp/test/defines-escaping/defines-escaping.gyp new file mode 100644 index 0000000..6f0f3fd --- /dev/null +++ b/tools/gyp/test/defines-escaping/defines-escaping.gyp @@ -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/tools/gyp/test/defines-escaping/gyptest-defines-escaping.py b/tools/gyp/test/defines-escaping/gyptest-defines-escaping.py new file mode 100755 index 0000000..eb18a3d --- /dev/null +++ b/tools/gyp/test/defines-escaping/gyptest-defines-escaping.py @@ -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, " `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, " `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/tools/gyp/test/defines/defines-env.gyp b/tools/gyp/test/defines/defines-env.gyp new file mode 100644 index 0000000..1781546 --- /dev/null +++ b/tools/gyp/test/defines/defines-env.gyp @@ -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/tools/gyp/test/defines/defines.c b/tools/gyp/test/defines/defines.c new file mode 100644 index 0000000..4721549 --- /dev/null +++ b/tools/gyp/test/defines/defines.c @@ -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. */ + +#include + +int main(int argc, char *argv[]) +{ +#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 + return 0; +} diff --git a/tools/gyp/test/defines/defines.gyp b/tools/gyp/test/defines/defines.gyp new file mode 100644 index 0000000..25d8c41 --- /dev/null +++ b/tools/gyp/test/defines/defines.gyp @@ -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': 'defines', + 'type': 'executable', + 'sources': [ + 'defines.c', + ], + 'defines': [ + 'FOO', + 'VALUE=1', + 'PAREN_VALUE=(1+2+3)', + ], + }, + ], + 'conditions': [ + ['OS=="fakeos"', { + 'targets': [ + { + 'target_name': 'fakeosprogram', + 'type': 'executable', + 'sources': [ + 'defines.c', + ], + 'defines': [ + 'FOO', + 'VALUE=1', + ], + }, + ], + }], + ], +} diff --git a/tools/gyp/test/defines/gyptest-define-override.py b/tools/gyp/test/defines/gyptest-define-override.py new file mode 100755 index 0000000..82e325a --- /dev/null +++ b/tools/gyp/test/defines/gyptest-define-override.py @@ -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. + +""" +Verifies that a default gyp define can be overridden. +""" + +import os +import TestGyp + +test = TestGyp.TestGyp() + +# Command-line define +test.run_gyp('defines.gyp', '-D', 'OS=fakeos') +test.build('defines.gyp') +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') +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') +test.built_file_must_exist('fakeosprogram', type=test.EXECUTABLE) + +test.pass_test() diff --git a/tools/gyp/test/defines/gyptest-defines-env-regyp.py b/tools/gyp/test/defines/gyptest-defines-env-regyp.py new file mode 100755 index 0000000..57ca42b --- /dev/null +++ b/tools/gyp/test/defines/gyptest-defines-env-regyp.py @@ -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 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 +""" +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/tools/gyp/test/defines/gyptest-defines-env.py b/tools/gyp/test/defines/gyptest-defines-env.py new file mode 100755 index 0000000..6b4e717 --- /dev/null +++ b/tools/gyp/test/defines/gyptest-defines-env.py @@ -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/tools/gyp/test/defines/gyptest-defines.py b/tools/gyp/test/defines/gyptest-defines.py new file mode 100755 index 0000000..0b6d64b --- /dev/null +++ b/tools/gyp/test/defines/gyptest-defines.py @@ -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 build of an executable with C++ defines. +""" + +import TestGyp + +test = TestGyp.TestGyp() + +test.run_gyp('defines.gyp') + +test.build('defines.gyp') + +expect = """\ +FOO is defined +VALUE is 1 +2*PAREN_VALUE is 12 +""" +test.run_built_executable('defines', stdout=expect) + +test.pass_test() diff --git a/tools/gyp/test/dependencies/a.c b/tools/gyp/test/dependencies/a.c new file mode 100755 index 0000000..3bba111 --- /dev/null +++ b/tools/gyp/test/dependencies/a.c @@ -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/tools/gyp/test/dependencies/b/b.c b/tools/gyp/test/dependencies/b/b.c new file mode 100755 index 0000000..b5e771b --- /dev/null +++ b/tools/gyp/test/dependencies/b/b.c @@ -0,0 +1,3 @@ +int funcB() { + return 2; +} diff --git a/tools/gyp/test/dependencies/b/b.gyp b/tools/gyp/test/dependencies/b/b.gyp new file mode 100755 index 0000000..f09e1ff --- /dev/null +++ b/tools/gyp/test/dependencies/b/b.gyp @@ -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': 'b', + 'type': 'static_library', + 'sources': [ + 'b.c', + ], + }, + ], +} diff --git a/tools/gyp/test/dependencies/c/c.c b/tools/gyp/test/dependencies/c/c.c new file mode 100644 index 0000000..4949daf --- /dev/null +++ b/tools/gyp/test/dependencies/c/c.c @@ -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/tools/gyp/test/dependencies/c/c.gyp b/tools/gyp/test/dependencies/c/c.gyp new file mode 100644 index 0000000..eabebea --- /dev/null +++ b/tools/gyp/test/dependencies/c/c.gyp @@ -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/tools/gyp/test/dependencies/c/d.c b/tools/gyp/test/dependencies/c/d.c new file mode 100644 index 0000000..05465fc --- /dev/null +++ b/tools/gyp/test/dependencies/c/d.c @@ -0,0 +1,3 @@ +int funcD() { + return 4; +} diff --git a/tools/gyp/test/dependencies/extra_targets.gyp b/tools/gyp/test/dependencies/extra_targets.gyp new file mode 100644 index 0000000..c1a26de --- /dev/null +++ b/tools/gyp/test/dependencies/extra_targets.gyp @@ -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/tools/gyp/test/dependencies/gyptest-extra-targets.py b/tools/gyp/test/dependencies/gyptest-extra-targets.py new file mode 100755 index 0000000..3752f74 --- /dev/null +++ b/tools/gyp/test/dependencies/gyptest-extra-targets.py @@ -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/tools/gyp/test/dependencies/gyptest-lib-only.py b/tools/gyp/test/dependencies/gyptest-lib-only.py new file mode 100755 index 0000000..4355d57 --- /dev/null +++ b/tools/gyp/test/dependencies/gyptest-lib-only.py @@ -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 sln/_main.scons, 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 == 'make' + 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/tools/gyp/test/dependencies/lib_only.gyp b/tools/gyp/test/dependencies/lib_only.gyp new file mode 100755 index 0000000..f6c84de --- /dev/null +++ b/tools/gyp/test/dependencies/lib_only.gyp @@ -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/tools/gyp/test/dependency-copy/gyptest-copy.py b/tools/gyp/test/dependency-copy/gyptest-copy.py new file mode 100755 index 0000000..5ba7c73 --- /dev/null +++ b/tools/gyp/test/dependency-copy/gyptest-copy.py @@ -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/tools/gyp/test/dependency-copy/src/copies.gyp b/tools/gyp/test/dependency-copy/src/copies.gyp new file mode 100644 index 0000000..4176b18 --- /dev/null +++ b/tools/gyp/test/dependency-copy/src/copies.gyp @@ -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/tools/gyp/test/dependency-copy/src/file1.c b/tools/gyp/test/dependency-copy/src/file1.c new file mode 100644 index 0000000..3caf5d6 --- /dev/null +++ b/tools/gyp/test/dependency-copy/src/file1.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("Hello from file1.c\n"); + return 0; +} diff --git a/tools/gyp/test/dependency-copy/src/file2.c b/tools/gyp/test/dependency-copy/src/file2.c new file mode 100644 index 0000000..ed45cc0 --- /dev/null +++ b/tools/gyp/test/dependency-copy/src/file2.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("Hello from file2.c\n"); + return 0; +} diff --git a/tools/gyp/test/exclusion/exclusion.gyp b/tools/gyp/test/exclusion/exclusion.gyp new file mode 100644 index 0000000..1232dab --- /dev/null +++ b/tools/gyp/test/exclusion/exclusion.gyp @@ -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/tools/gyp/test/exclusion/gyptest-exclusion.py b/tools/gyp/test/exclusion/gyptest-exclusion.py new file mode 100755 index 0000000..1fc32bf --- /dev/null +++ b/tools/gyp/test/exclusion/gyptest-exclusion.py @@ -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/tools/gyp/test/exclusion/hello.c b/tools/gyp/test/exclusion/hello.c new file mode 100644 index 0000000..30e8d54 --- /dev/null +++ b/tools/gyp/test/exclusion/hello.c @@ -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 + +int func1(void) { + return 42; +} + +int main(int argc, char *argv[]) { + printf("Hello, world!\n"); + printf("%d\n", func1()); + return 0; +} diff --git a/tools/gyp/test/generator-output/actions/actions.gyp b/tools/gyp/test/generator-output/actions/actions.gyp new file mode 100644 index 0000000..dded59a --- /dev/null +++ b/tools/gyp/test/generator-output/actions/actions.gyp @@ -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/tools/gyp/test/generator-output/actions/build/README.txt b/tools/gyp/test/generator-output/actions/build/README.txt new file mode 100644 index 0000000..1b052c9 --- /dev/null +++ b/tools/gyp/test/generator-output/actions/build/README.txt @@ -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/tools/gyp/test/generator-output/actions/subdir1/actions-out/README.txt b/tools/gyp/test/generator-output/actions/subdir1/actions-out/README.txt new file mode 100644 index 0000000..1b052c9 --- /dev/null +++ b/tools/gyp/test/generator-output/actions/subdir1/actions-out/README.txt @@ -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/tools/gyp/test/generator-output/actions/subdir1/build/README.txt b/tools/gyp/test/generator-output/actions/subdir1/build/README.txt new file mode 100644 index 0000000..1b052c9 --- /dev/null +++ b/tools/gyp/test/generator-output/actions/subdir1/build/README.txt @@ -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/tools/gyp/test/generator-output/actions/subdir1/executable.gyp b/tools/gyp/test/generator-output/actions/subdir1/executable.gyp new file mode 100644 index 0000000..6bdd60a --- /dev/null +++ b/tools/gyp/test/generator-output/actions/subdir1/executable.gyp @@ -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/tools/gyp/test/generator-output/actions/subdir1/make-prog1.py b/tools/gyp/test/generator-output/actions/subdir1/make-prog1.py new file mode 100755 index 0000000..7ea1d8a --- /dev/null +++ b/tools/gyp/test/generator-output/actions/subdir1/make-prog1.py @@ -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 + +void prog1(void) +{ + printf("Hello from make-prog1.py\n"); +} +""" + +open(sys.argv[1], 'w').write(contents) + +sys.exit(0) diff --git a/tools/gyp/test/generator-output/actions/subdir1/make-prog2.py b/tools/gyp/test/generator-output/actions/subdir1/make-prog2.py new file mode 100755 index 0000000..0bfe497 --- /dev/null +++ b/tools/gyp/test/generator-output/actions/subdir1/make-prog2.py @@ -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 + +void prog2(void) +{ + printf("Hello from make-prog2.py\n"); +} +""" + +open(sys.argv[1], 'w').write(contents) + +sys.exit(0) diff --git a/tools/gyp/test/generator-output/actions/subdir1/program.c b/tools/gyp/test/generator-output/actions/subdir1/program.c new file mode 100644 index 0000000..d5f661d --- /dev/null +++ b/tools/gyp/test/generator-output/actions/subdir1/program.c @@ -0,0 +1,12 @@ +#include + +extern void prog1(void); +extern void prog2(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from program.c\n"); + prog1(); + prog2(); + return 0; +} diff --git a/tools/gyp/test/generator-output/actions/subdir2/actions-out/README.txt b/tools/gyp/test/generator-output/actions/subdir2/actions-out/README.txt new file mode 100644 index 0000000..1b052c9 --- /dev/null +++ b/tools/gyp/test/generator-output/actions/subdir2/actions-out/README.txt @@ -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/tools/gyp/test/generator-output/actions/subdir2/build/README.txt b/tools/gyp/test/generator-output/actions/subdir2/build/README.txt new file mode 100644 index 0000000..1b052c9 --- /dev/null +++ b/tools/gyp/test/generator-output/actions/subdir2/build/README.txt @@ -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/tools/gyp/test/generator-output/actions/subdir2/make-file.py b/tools/gyp/test/generator-output/actions/subdir2/make-file.py new file mode 100755 index 0000000..fff0653 --- /dev/null +++ b/tools/gyp/test/generator-output/actions/subdir2/make-file.py @@ -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/tools/gyp/test/generator-output/actions/subdir2/none.gyp b/tools/gyp/test/generator-output/actions/subdir2/none.gyp new file mode 100644 index 0000000..f98f527 --- /dev/null +++ b/tools/gyp/test/generator-output/actions/subdir2/none.gyp @@ -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/tools/gyp/test/generator-output/copies/build/README.txt b/tools/gyp/test/generator-output/copies/build/README.txt new file mode 100644 index 0000000..90ef886 --- /dev/null +++ b/tools/gyp/test/generator-output/copies/build/README.txt @@ -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/tools/gyp/test/generator-output/copies/copies-out/README.txt b/tools/gyp/test/generator-output/copies/copies-out/README.txt new file mode 100644 index 0000000..90ef886 --- /dev/null +++ b/tools/gyp/test/generator-output/copies/copies-out/README.txt @@ -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/tools/gyp/test/generator-output/copies/copies.gyp b/tools/gyp/test/generator-output/copies/copies.gyp new file mode 100644 index 0000000..479a3d9 --- /dev/null +++ b/tools/gyp/test/generator-output/copies/copies.gyp @@ -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/tools/gyp/test/generator-output/copies/file1 b/tools/gyp/test/generator-output/copies/file1 new file mode 100644 index 0000000..84d55c5 --- /dev/null +++ b/tools/gyp/test/generator-output/copies/file1 @@ -0,0 +1 @@ +file1 contents diff --git a/tools/gyp/test/generator-output/copies/file2 b/tools/gyp/test/generator-output/copies/file2 new file mode 100644 index 0000000..af1b8ae --- /dev/null +++ b/tools/gyp/test/generator-output/copies/file2 @@ -0,0 +1 @@ +file2 contents diff --git a/tools/gyp/test/generator-output/copies/subdir/build/README.txt b/tools/gyp/test/generator-output/copies/subdir/build/README.txt new file mode 100644 index 0000000..90ef886 --- /dev/null +++ b/tools/gyp/test/generator-output/copies/subdir/build/README.txt @@ -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/tools/gyp/test/generator-output/copies/subdir/copies-out/README.txt b/tools/gyp/test/generator-output/copies/subdir/copies-out/README.txt new file mode 100644 index 0000000..90ef886 --- /dev/null +++ b/tools/gyp/test/generator-output/copies/subdir/copies-out/README.txt @@ -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/tools/gyp/test/generator-output/copies/subdir/file3 b/tools/gyp/test/generator-output/copies/subdir/file3 new file mode 100644 index 0000000..43f16f3 --- /dev/null +++ b/tools/gyp/test/generator-output/copies/subdir/file3 @@ -0,0 +1 @@ +file3 contents diff --git a/tools/gyp/test/generator-output/copies/subdir/file4 b/tools/gyp/test/generator-output/copies/subdir/file4 new file mode 100644 index 0000000..5f7270a --- /dev/null +++ b/tools/gyp/test/generator-output/copies/subdir/file4 @@ -0,0 +1 @@ +file4 contents diff --git a/tools/gyp/test/generator-output/copies/subdir/subdir.gyp b/tools/gyp/test/generator-output/copies/subdir/subdir.gyp new file mode 100644 index 0000000..af031d2 --- /dev/null +++ b/tools/gyp/test/generator-output/copies/subdir/subdir.gyp @@ -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/tools/gyp/test/generator-output/gyptest-actions.py b/tools/gyp/test/generator-output/gyptest-actions.py new file mode 100755 index 0000000..6e62720 --- /dev/null +++ b/tools/gyp/test/generator-output/gyptest-actions.py @@ -0,0 +1,58 @@ +#!/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 --generator-output= behavior when using actions. +""" + +import TestGyp + +# Ninja doesn't support --generator-output. +test = TestGyp.TestGyp(formats=['!ninja']) + +# 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'), + 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/tools/gyp/test/generator-output/gyptest-copies.py b/tools/gyp/test/generator-output/gyptest-copies.py new file mode 100755 index 0000000..83ba013 --- /dev/null +++ b/tools/gyp/test/generator-output/gyptest-copies.py @@ -0,0 +1,59 @@ +#!/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 with --generator-output using an explicit build +target of 'all'. +""" + +import TestGyp + +# Ninja doesn't support --generator-output. +test = TestGyp.TestGyp(formats=['!ninja']) + +test.writable(test.workpath('copies'), False) + +test.run_gyp('copies.gyp', + '--generator-output=' + test.workpath('gypfiles'), + 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 == 'make': + 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 == 'make': + 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/tools/gyp/test/generator-output/gyptest-relocate.py b/tools/gyp/test/generator-output/gyptest-relocate.py new file mode 100755 index 0000000..31a98ea --- /dev/null +++ b/tools/gyp/test/generator-output/gyptest-relocate.py @@ -0,0 +1,60 @@ +#!/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 project hierarchy created with the --generator-output= +option can be built even when it's relocated to a different path. +""" + +import TestGyp + +# Ninja doesn't support --generator-output. +test = TestGyp.TestGyp(formats=['!ninja']) + +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/tools/gyp/test/generator-output/gyptest-rules.py b/tools/gyp/test/generator-output/gyptest-rules.py new file mode 100755 index 0000000..678416a --- /dev/null +++ b/tools/gyp/test/generator-output/gyptest-rules.py @@ -0,0 +1,58 @@ +#!/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 --generator-output= behavior when using rules. +""" + +import TestGyp + +test = TestGyp.TestGyp(formats=['!ninja']) + +test.writable(test.workpath('rules'), False) + +test.run_gyp('rules.gyp', + '--generator-output=' + test.workpath('gypfiles'), + 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/tools/gyp/test/generator-output/gyptest-subdir2-deep.py b/tools/gyp/test/generator-output/gyptest-subdir2-deep.py new file mode 100755 index 0000000..cb5ea15 --- /dev/null +++ b/tools/gyp/test/generator-output/gyptest-subdir2-deep.py @@ -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 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 + +test = TestGyp.TestGyp(formats=['!ninja']) + +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/tools/gyp/test/generator-output/gyptest-top-all.py b/tools/gyp/test/generator-output/gyptest-top-all.py new file mode 100755 index 0000000..4841f9b --- /dev/null +++ b/tools/gyp/test/generator-output/gyptest-top-all.py @@ -0,0 +1,53 @@ +#!/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 hierarchy created when the --generator-output= +option is used to put the build configuration files in a separate +directory tree. +""" + +import TestGyp + +test = TestGyp.TestGyp(formats=['!ninja']) + +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/tools/gyp/test/generator-output/rules/build/README.txt b/tools/gyp/test/generator-output/rules/build/README.txt new file mode 100644 index 0000000..1b052c9 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/build/README.txt @@ -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/tools/gyp/test/generator-output/rules/copy-file.py b/tools/gyp/test/generator-output/rules/copy-file.py new file mode 100755 index 0000000..938c336 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/copy-file.py @@ -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/tools/gyp/test/generator-output/rules/rules.gyp b/tools/gyp/test/generator-output/rules/rules.gyp new file mode 100644 index 0000000..dded59a --- /dev/null +++ b/tools/gyp/test/generator-output/rules/rules.gyp @@ -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/tools/gyp/test/generator-output/rules/subdir1/build/README.txt b/tools/gyp/test/generator-output/rules/subdir1/build/README.txt new file mode 100644 index 0000000..1b052c9 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir1/build/README.txt @@ -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/tools/gyp/test/generator-output/rules/subdir1/define3.in0 b/tools/gyp/test/generator-output/rules/subdir1/define3.in0 new file mode 100644 index 0000000..cc29c64 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir1/define3.in0 @@ -0,0 +1 @@ +#define STRING3 "Hello from define3.in0\n" diff --git a/tools/gyp/test/generator-output/rules/subdir1/define4.in0 b/tools/gyp/test/generator-output/rules/subdir1/define4.in0 new file mode 100644 index 0000000..c9b0467 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir1/define4.in0 @@ -0,0 +1 @@ +#define STRING4 "Hello from define4.in0\n" diff --git a/tools/gyp/test/generator-output/rules/subdir1/executable.gyp b/tools/gyp/test/generator-output/rules/subdir1/executable.gyp new file mode 100644 index 0000000..2fd89a0 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir1/executable.gyp @@ -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 SCons and 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 SCons and 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/tools/gyp/test/generator-output/rules/subdir1/function1.in1 b/tools/gyp/test/generator-output/rules/subdir1/function1.in1 new file mode 100644 index 0000000..545e7ca --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir1/function1.in1 @@ -0,0 +1,6 @@ +#include + +void function1(void) +{ + printf("Hello from function1.in1\n"); +} diff --git a/tools/gyp/test/generator-output/rules/subdir1/function2.in1 b/tools/gyp/test/generator-output/rules/subdir1/function2.in1 new file mode 100644 index 0000000..6bad43f --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir1/function2.in1 @@ -0,0 +1,6 @@ +#include + +void function2(void) +{ + printf("Hello from function2.in1\n"); +} diff --git a/tools/gyp/test/generator-output/rules/subdir1/program.c b/tools/gyp/test/generator-output/rules/subdir1/program.c new file mode 100644 index 0000000..27fd31e --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir1/program.c @@ -0,0 +1,18 @@ +#include +#include "define3.h" +#include "define4.h" + +extern void function1(void); +extern void function2(void); +extern void function3(void); +extern void function4(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from program.c\n"); + function1(); + function2(); + printf("%s", STRING3); + printf("%s", STRING4); + return 0; +} diff --git a/tools/gyp/test/generator-output/rules/subdir2/build/README.txt b/tools/gyp/test/generator-output/rules/subdir2/build/README.txt new file mode 100644 index 0000000..1b052c9 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir2/build/README.txt @@ -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/tools/gyp/test/generator-output/rules/subdir2/file1.in0 b/tools/gyp/test/generator-output/rules/subdir2/file1.in0 new file mode 100644 index 0000000..7aca64f --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir2/file1.in0 @@ -0,0 +1 @@ +Hello from file1.in0 diff --git a/tools/gyp/test/generator-output/rules/subdir2/file2.in0 b/tools/gyp/test/generator-output/rules/subdir2/file2.in0 new file mode 100644 index 0000000..80a281a --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir2/file2.in0 @@ -0,0 +1 @@ +Hello from file2.in0 diff --git a/tools/gyp/test/generator-output/rules/subdir2/file3.in1 b/tools/gyp/test/generator-output/rules/subdir2/file3.in1 new file mode 100644 index 0000000..60ae2e7 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir2/file3.in1 @@ -0,0 +1 @@ +Hello from file3.in1 diff --git a/tools/gyp/test/generator-output/rules/subdir2/file4.in1 b/tools/gyp/test/generator-output/rules/subdir2/file4.in1 new file mode 100644 index 0000000..5a3c307 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir2/file4.in1 @@ -0,0 +1 @@ +Hello from file4.in1 diff --git a/tools/gyp/test/generator-output/rules/subdir2/none.gyp b/tools/gyp/test/generator-output/rules/subdir2/none.gyp new file mode 100644 index 0000000..664cbd9 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir2/none.gyp @@ -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/tools/gyp/test/generator-output/rules/subdir2/rules-out/README.txt b/tools/gyp/test/generator-output/rules/subdir2/rules-out/README.txt new file mode 100644 index 0000000..1b052c9 --- /dev/null +++ b/tools/gyp/test/generator-output/rules/subdir2/rules-out/README.txt @@ -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/tools/gyp/test/generator-output/src/build/README.txt b/tools/gyp/test/generator-output/src/build/README.txt new file mode 100644 index 0000000..90ef886 --- /dev/null +++ b/tools/gyp/test/generator-output/src/build/README.txt @@ -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/tools/gyp/test/generator-output/src/inc.h b/tools/gyp/test/generator-output/src/inc.h new file mode 100644 index 0000000..57aa1a5 --- /dev/null +++ b/tools/gyp/test/generator-output/src/inc.h @@ -0,0 +1 @@ +#define INC_STRING "inc.h" diff --git a/tools/gyp/test/generator-output/src/inc1/include1.h b/tools/gyp/test/generator-output/src/inc1/include1.h new file mode 100644 index 0000000..1d59065 --- /dev/null +++ b/tools/gyp/test/generator-output/src/inc1/include1.h @@ -0,0 +1 @@ +#define INCLUDE1_STRING "inc1/include1.h" diff --git a/tools/gyp/test/generator-output/src/prog1.c b/tools/gyp/test/generator-output/src/prog1.c new file mode 100644 index 0000000..656f81d --- /dev/null +++ b/tools/gyp/test/generator-output/src/prog1.c @@ -0,0 +1,18 @@ +#include + +#include "inc.h" +#include "include1.h" +#include "include2.h" +#include "include3.h" +#include "deeper.h" + +int main(int argc, char *argv[]) +{ + 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/tools/gyp/test/generator-output/src/prog1.gyp b/tools/gyp/test/generator-output/src/prog1.gyp new file mode 100644 index 0000000..d50e6fb --- /dev/null +++ b/tools/gyp/test/generator-output/src/prog1.gyp @@ -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/tools/gyp/test/generator-output/src/subdir2/build/README.txt b/tools/gyp/test/generator-output/src/subdir2/build/README.txt new file mode 100644 index 0000000..90ef886 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir2/build/README.txt @@ -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/tools/gyp/test/generator-output/src/subdir2/deeper/build/README.txt b/tools/gyp/test/generator-output/src/subdir2/deeper/build/README.txt new file mode 100644 index 0000000..90ef886 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir2/deeper/build/README.txt @@ -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/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.c b/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.c new file mode 100644 index 0000000..56c49d1 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("Hello from deeper.c\n"); + return 0; +} diff --git a/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.gyp b/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.gyp new file mode 100644 index 0000000..8648770 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.gyp @@ -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/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.h b/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.h new file mode 100644 index 0000000..f6484a0 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.h @@ -0,0 +1 @@ +#define DEEPER_STRING "subdir2/deeper/deeper.h" diff --git a/tools/gyp/test/generator-output/src/subdir2/inc2/include2.h b/tools/gyp/test/generator-output/src/subdir2/inc2/include2.h new file mode 100644 index 0000000..1ccfa5d --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir2/inc2/include2.h @@ -0,0 +1 @@ +#define INCLUDE2_STRING "inc2/include2.h" diff --git a/tools/gyp/test/generator-output/src/subdir2/prog2.c b/tools/gyp/test/generator-output/src/subdir2/prog2.c new file mode 100644 index 0000000..38d6c84 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir2/prog2.c @@ -0,0 +1,18 @@ +#include + +#include "inc.h" +#include "include1.h" +#include "include2.h" +#include "include3.h" +#include "deeper.h" + +int main(int argc, char *argv[]) +{ + 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/tools/gyp/test/generator-output/src/subdir2/prog2.gyp b/tools/gyp/test/generator-output/src/subdir2/prog2.gyp new file mode 100644 index 0000000..7176ed8 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir2/prog2.gyp @@ -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/tools/gyp/test/generator-output/src/subdir3/build/README.txt b/tools/gyp/test/generator-output/src/subdir3/build/README.txt new file mode 100644 index 0000000..90ef886 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir3/build/README.txt @@ -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/tools/gyp/test/generator-output/src/subdir3/inc3/include3.h b/tools/gyp/test/generator-output/src/subdir3/inc3/include3.h new file mode 100644 index 0000000..bf53bf1 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir3/inc3/include3.h @@ -0,0 +1 @@ +#define INCLUDE3_STRING "inc3/include3.h" diff --git a/tools/gyp/test/generator-output/src/subdir3/prog3.c b/tools/gyp/test/generator-output/src/subdir3/prog3.c new file mode 100644 index 0000000..7848b45 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir3/prog3.c @@ -0,0 +1,18 @@ +#include + +#include "inc.h" +#include "include1.h" +#include "include2.h" +#include "include3.h" +#include "deeper.h" + +int main(int argc, char *argv[]) +{ + 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/tools/gyp/test/generator-output/src/subdir3/prog3.gyp b/tools/gyp/test/generator-output/src/subdir3/prog3.gyp new file mode 100644 index 0000000..46c5e00 --- /dev/null +++ b/tools/gyp/test/generator-output/src/subdir3/prog3.gyp @@ -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/tools/gyp/test/generator-output/src/symroot.gypi b/tools/gyp/test/generator-output/src/symroot.gypi new file mode 100644 index 0000000..5199164 --- /dev/null +++ b/tools/gyp/test/generator-output/src/symroot.gypi @@ -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/tools/gyp/test/hard_dependency/gyptest-exported-hard-dependency.py b/tools/gyp/test/hard_dependency/gyptest-exported-hard-dependency.py new file mode 100755 index 0000000..ba51528 --- /dev/null +++ b/tools/gyp/test/hard_dependency/gyptest-exported-hard-dependency.py @@ -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/tools/gyp/test/hard_dependency/gyptest-no-exported-hard-dependency.py b/tools/gyp/test/hard_dependency/gyptest-no-exported-hard-dependency.py new file mode 100755 index 0000000..10774ca --- /dev/null +++ b/tools/gyp/test/hard_dependency/gyptest-no-exported-hard-dependency.py @@ -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/tools/gyp/test/hard_dependency/src/a.c b/tools/gyp/test/hard_dependency/src/a.c new file mode 100644 index 0000000..0fa0223 --- /dev/null +++ b/tools/gyp/test/hard_dependency/src/a.c @@ -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/tools/gyp/test/hard_dependency/src/a.h b/tools/gyp/test/hard_dependency/src/a.h new file mode 100644 index 0000000..854a065 --- /dev/null +++ b/tools/gyp/test/hard_dependency/src/a.h @@ -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/tools/gyp/test/hard_dependency/src/b.c b/tools/gyp/test/hard_dependency/src/b.c new file mode 100644 index 0000000..0baace9 --- /dev/null +++ b/tools/gyp/test/hard_dependency/src/b.c @@ -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/tools/gyp/test/hard_dependency/src/b.h b/tools/gyp/test/hard_dependency/src/b.h new file mode 100644 index 0000000..22b48ce --- /dev/null +++ b/tools/gyp/test/hard_dependency/src/b.h @@ -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/tools/gyp/test/hard_dependency/src/c.c b/tools/gyp/test/hard_dependency/src/c.c new file mode 100644 index 0000000..b0e0fb1 --- /dev/null +++ b/tools/gyp/test/hard_dependency/src/c.c @@ -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 "c.h" + +int funcC() { + return funcB(); +} diff --git a/tools/gyp/test/hard_dependency/src/c.h b/tools/gyp/test/hard_dependency/src/c.h new file mode 100644 index 0000000..f4ea7fe --- /dev/null +++ b/tools/gyp/test/hard_dependency/src/c.h @@ -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/tools/gyp/test/hard_dependency/src/d.c b/tools/gyp/test/hard_dependency/src/d.c new file mode 100644 index 0000000..d016c3c --- /dev/null +++ b/tools/gyp/test/hard_dependency/src/d.c @@ -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/tools/gyp/test/hard_dependency/src/emit.py b/tools/gyp/test/hard_dependency/src/emit.py new file mode 100755 index 0000000..2df74b7 --- /dev/null +++ b/tools/gyp/test/hard_dependency/src/emit.py @@ -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/tools/gyp/test/hard_dependency/src/hard_dependency.gyp b/tools/gyp/test/hard_dependency/src/hard_dependency.gyp new file mode 100644 index 0000000..4479c5f --- /dev/null +++ b/tools/gyp/test/hard_dependency/src/hard_dependency.gyp @@ -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/tools/gyp/test/hello/gyptest-all.py b/tools/gyp/test/hello/gyptest-all.py new file mode 100755 index 0000000..1739b68 --- /dev/null +++ b/tools/gyp/test/hello/gyptest-all.py @@ -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/tools/gyp/test/hello/gyptest-default.py b/tools/gyp/test/hello/gyptest-default.py new file mode 100755 index 0000000..22377e7 --- /dev/null +++ b/tools/gyp/test/hello/gyptest-default.py @@ -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/tools/gyp/test/hello/gyptest-disable-regyp.py b/tools/gyp/test/hello/gyptest-disable-regyp.py new file mode 100755 index 0000000..1e4b306 --- /dev/null +++ b/tools/gyp/test/hello/gyptest-disable-regyp.py @@ -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/tools/gyp/test/hello/gyptest-regyp.py b/tools/gyp/test/hello/gyptest-regyp.py new file mode 100755 index 0000000..827c723 --- /dev/null +++ b/tools/gyp/test/hello/gyptest-regyp.py @@ -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 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/tools/gyp/test/hello/gyptest-target.py b/tools/gyp/test/hello/gyptest-target.py new file mode 100755 index 0000000..1abaf70 --- /dev/null +++ b/tools/gyp/test/hello/gyptest-target.py @@ -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/tools/gyp/test/hello/hello.c b/tools/gyp/test/hello/hello.c new file mode 100644 index 0000000..8dbecc0 --- /dev/null +++ b/tools/gyp/test/hello/hello.c @@ -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 + +int main(int argc, char *argv[]) +{ + printf("Hello, world!\n"); + return 0; +} diff --git a/tools/gyp/test/hello/hello.gyp b/tools/gyp/test/hello/hello.gyp new file mode 100644 index 0000000..1974d51 --- /dev/null +++ b/tools/gyp/test/hello/hello.gyp @@ -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/tools/gyp/test/hello/hello2.c b/tools/gyp/test/hello/hello2.c new file mode 100644 index 0000000..19ef3fb --- /dev/null +++ b/tools/gyp/test/hello/hello2.c @@ -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 + +int main(int argc, char *argv[]) +{ + printf("Hello, two!\n"); + return 0; +} diff --git a/tools/gyp/test/hello/hello2.gyp b/tools/gyp/test/hello/hello2.gyp new file mode 100644 index 0000000..25b08ca --- /dev/null +++ b/tools/gyp/test/hello/hello2.gyp @@ -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/tools/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py b/tools/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py new file mode 100755 index 0000000..974db7f --- /dev/null +++ b/tools/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py @@ -0,0 +1,44 @@ +#!/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/includes.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/includes.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/includes.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/tools/gyp/test/home_dot_gyp/gyptest-home-includes.py b/tools/gyp/test/home_dot_gyp/gyptest-home-includes.py new file mode 100755 index 0000000..3131e2d --- /dev/null +++ b/tools/gyp/test/home_dot_gyp/gyptest-home-includes.py @@ -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/includes.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/includes.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/tools/gyp/test/home_dot_gyp/home/.gyp/include.gypi b/tools/gyp/test/home_dot_gyp/home/.gyp/include.gypi new file mode 100644 index 0000000..fcfb39b --- /dev/null +++ b/tools/gyp/test/home_dot_gyp/home/.gyp/include.gypi @@ -0,0 +1,5 @@ +{ + 'variables': { + 'foo': '"fromhome"', + }, +} diff --git a/tools/gyp/test/home_dot_gyp/home2/.gyp/include.gypi b/tools/gyp/test/home_dot_gyp/home2/.gyp/include.gypi new file mode 100644 index 0000000..f0d84b3 --- /dev/null +++ b/tools/gyp/test/home_dot_gyp/home2/.gyp/include.gypi @@ -0,0 +1,5 @@ +{ + 'variables': { + 'foo': '"fromhome2"', + }, +} diff --git a/tools/gyp/test/home_dot_gyp/src/all.gyp b/tools/gyp/test/home_dot_gyp/src/all.gyp new file mode 100644 index 0000000..14b6aea --- /dev/null +++ b/tools/gyp/test/home_dot_gyp/src/all.gyp @@ -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/tools/gyp/test/home_dot_gyp/src/printfoo.c b/tools/gyp/test/home_dot_gyp/src/printfoo.c new file mode 100644 index 0000000..92d2cba --- /dev/null +++ b/tools/gyp/test/home_dot_gyp/src/printfoo.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("FOO is %s\n", FOO); + return 0; +} diff --git a/tools/gyp/test/include_dirs/gyptest-all.py b/tools/gyp/test/include_dirs/gyptest-all.py new file mode 100755 index 0000000..94a1338 --- /dev/null +++ b/tools/gyp/test/include_dirs/gyptest-all.py @@ -0,0 +1,46 @@ +#!/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() + +if test.format == 'scons': + test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n') + +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/tools/gyp/test/include_dirs/gyptest-default.py b/tools/gyp/test/include_dirs/gyptest-default.py new file mode 100755 index 0000000..42acd1f --- /dev/null +++ b/tools/gyp/test/include_dirs/gyptest-default.py @@ -0,0 +1,46 @@ +#!/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() + +if test.format == 'scons': + test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n') + +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/tools/gyp/test/include_dirs/src/inc.h b/tools/gyp/test/include_dirs/src/inc.h new file mode 100644 index 0000000..0398d69 --- /dev/null +++ b/tools/gyp/test/include_dirs/src/inc.h @@ -0,0 +1 @@ +#define INC_STRING "inc.h" diff --git a/tools/gyp/test/include_dirs/src/inc1/include1.h b/tools/gyp/test/include_dirs/src/inc1/include1.h new file mode 100644 index 0000000..43356b5 --- /dev/null +++ b/tools/gyp/test/include_dirs/src/inc1/include1.h @@ -0,0 +1 @@ +#define INCLUDE1_STRING "include1.h" diff --git a/tools/gyp/test/include_dirs/src/includes.c b/tools/gyp/test/include_dirs/src/includes.c new file mode 100644 index 0000000..e2afbd3 --- /dev/null +++ b/tools/gyp/test/include_dirs/src/includes.c @@ -0,0 +1,19 @@ +#include + +#include "inc.h" +#include "include1.h" +#include "include2.h" +#include "shadow.h" + +int main(int argc, char *argv[]) +{ + 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/tools/gyp/test/include_dirs/src/includes.gyp b/tools/gyp/test/include_dirs/src/includes.gyp new file mode 100644 index 0000000..3592690 --- /dev/null +++ b/tools/gyp/test/include_dirs/src/includes.gyp @@ -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/tools/gyp/test/include_dirs/src/shadow1/shadow.h b/tools/gyp/test/include_dirs/src/shadow1/shadow.h new file mode 100644 index 0000000..80f6de2 --- /dev/null +++ b/tools/gyp/test/include_dirs/src/shadow1/shadow.h @@ -0,0 +1 @@ +#define SHADOW_STRING "shadow1/shadow.h" diff --git a/tools/gyp/test/include_dirs/src/shadow2/shadow.h b/tools/gyp/test/include_dirs/src/shadow2/shadow.h new file mode 100644 index 0000000..fad5ccd --- /dev/null +++ b/tools/gyp/test/include_dirs/src/shadow2/shadow.h @@ -0,0 +1 @@ +#define SHADOW_STRING "shadow2/shadow.h" diff --git a/tools/gyp/test/include_dirs/src/subdir/inc.h b/tools/gyp/test/include_dirs/src/subdir/inc.h new file mode 100644 index 0000000..0a68d7b --- /dev/null +++ b/tools/gyp/test/include_dirs/src/subdir/inc.h @@ -0,0 +1 @@ +#define INC_STRING "subdir/inc.h" diff --git a/tools/gyp/test/include_dirs/src/subdir/inc2/include2.h b/tools/gyp/test/include_dirs/src/subdir/inc2/include2.h new file mode 100644 index 0000000..721577e --- /dev/null +++ b/tools/gyp/test/include_dirs/src/subdir/inc2/include2.h @@ -0,0 +1 @@ +#define INCLUDE2_STRING "subdir/inc2/include2.h" diff --git a/tools/gyp/test/include_dirs/src/subdir/subdir_includes.c b/tools/gyp/test/include_dirs/src/subdir/subdir_includes.c new file mode 100644 index 0000000..727f682 --- /dev/null +++ b/tools/gyp/test/include_dirs/src/subdir/subdir_includes.c @@ -0,0 +1,14 @@ +#include + +#include "inc.h" +#include "include1.h" +#include "include2.h" + +int main(int argc, char *argv[]) +{ + 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/tools/gyp/test/include_dirs/src/subdir/subdir_includes.gyp b/tools/gyp/test/include_dirs/src/subdir/subdir_includes.gyp new file mode 100644 index 0000000..257d052 --- /dev/null +++ b/tools/gyp/test/include_dirs/src/subdir/subdir_includes.gyp @@ -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/tools/gyp/test/intermediate_dir/gyptest-intermediate-dir.py b/tools/gyp/test/intermediate_dir/gyptest-intermediate-dir.py new file mode 100755 index 0000000..b4fd16f --- /dev/null +++ b/tools/gyp/test/intermediate_dir/gyptest-intermediate-dir.py @@ -0,0 +1,45 @@ +#!/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 targets have independent INTERMEDIATE_DIRs. +""" + +import TestGyp + +import os +import sys + +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') +test.build('test2.gyp', 'target2', chdir='src') +# Check INTERMEDIATE_DIR file didn't get overwritten but SHARED_INTERMEDIAT_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) + +# These sometimes fail flakily with the xcode generator due to the shared file +# still containing 'target1'. Maybe the xcode build runs actions asynchronously? +# Asserting that the intermediate file names are identical is good enough. +#test.must_contain(shared_intermediate_file1, 'shared_target2') +#test.must_contain(shared_intermediate_file2, 'shared_target2') + +test.pass_test() diff --git a/tools/gyp/test/intermediate_dir/src/script.py b/tools/gyp/test/intermediate_dir/src/script.py new file mode 100755 index 0000000..fa828a0 --- /dev/null +++ b/tools/gyp/test/intermediate_dir/src/script.py @@ -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. + +# 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]) + 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/tools/gyp/test/intermediate_dir/src/test.gyp b/tools/gyp/test/intermediate_dir/src/test.gyp new file mode 100644 index 0000000..9cd07c9 --- /dev/null +++ b/tools/gyp/test/intermediate_dir/src/test.gyp @@ -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. + +{ + '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': [], + '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/tools/gyp/test/intermediate_dir/src/test2.gyp b/tools/gyp/test/intermediate_dir/src/test2.gyp new file mode 100644 index 0000000..07ed9a0 --- /dev/null +++ b/tools/gyp/test/intermediate_dir/src/test2.gyp @@ -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. + +{ + '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': [], + '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/tools/gyp/test/lib/README.txt b/tools/gyp/test/lib/README.txt new file mode 100644 index 0000000..b3d7245 --- /dev/null +++ b/tools/gyp/test/lib/README.txt @@ -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/tools/gyp/test/lib/TestCmd.py b/tools/gyp/test/lib/TestCmd.py new file mode 100644 index 0000000..45d901c --- /dev/null +++ b/tools/gyp/test/lib/TestCmd.py @@ -0,0 +1,1594 @@ +""" +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 " +__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 ("?", ""): + 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" + + at = _caller(traceback.extract_stack(), skip) + sys.stderr.write("NO RESULT for test" + of + desc + sep + at) + + 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/tools/gyp/test/lib/TestCommon.py b/tools/gyp/test/lib/TestCommon.py new file mode 100644 index 0000000..4aa7185 --- /dev/null +++ b/tools/gyp/test/lib/TestCommon.py @@ -0,0 +1,581 @@ +""" +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 " +__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 + +if os.name == 'posix': + def _failed(self, status = 0): + if self.status is None or status is None: + return None + return _status(self) != status + def _status(self): + return self.status +elif os.name == 'nt': + def _failed(self, status = 0): + return not (self.status is None or status is None) and \ + self.status != 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. + """ + try: + options = kw['options'] + del kw['options'] + except KeyError: + pass + else: + 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 + try: + match = kw['match'] + del kw['match'] + except KeyError: + 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/tools/gyp/test/lib/TestGyp.py b/tools/gyp/test/lib/TestGyp.py new file mode 100644 index 0000000..a65c3e2 --- /dev/null +++ b/tools/gyp/test/lib/TestGyp.py @@ -0,0 +1,806 @@ +# 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. + +""" +TestGyp.py: a testing framework for GYP integration tests. +""" + +import os +import re +import shutil +import stat +import sys +import tempfile + +import TestCommon +from TestCommon import __all__ + +__all__.extend([ + 'TestGyp', +]) + + +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. + """ + + 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])) + + 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.initialize_build_tool() + + if not kw.has_key('match'): + kw['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. + try: + os.makedirs(workdir) + except OSError: + pass + kw['workdir'] = tempfile.mktemp(prefix='testgyp.', dir=workdir) + + formats = kw.get('formats', []) + if kw.has_key('formats'): + del kw['formats'] + + super(TestGypBase, self).__init__(*args, **kw) + + excluded_formats = set([f for f in formats if f[0] == '!']) + included_formats = set(formats) - excluded_formats + if ('!'+self.format in excluded_formats or + included_formats and self.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'] + + 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 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, scons) 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. + """ + # TODO: --depth=. works around Chromium-specific tree climbing. + args = ('--depth=.', '--format='+self.format, gyp_file) + args + return self.run(program=self.gyp, arguments=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' + + +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 + 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: + result.append(subdir) + result.append(self.built_file_basename(name, type, **kw)) + return self.workpath(*result) + + +class TestGypNinja(TestGypBase): + """ + Subclass for testing the GYP Ninja generator. + """ + format = 'ninja' + build_tool_list = ['ninja'] + ALL = 'all' + DEFAULT = 'all' + + # The default library prefix is computed from TestCommon.lib_prefix, + # but ninja uses no prefix for static libraries. + lib_ = '' + + def run_gyp(self, gyp_file, *args, **kw): + # We must pass the desired configuration as a parameter. + if self.configuration: + args = list(args) + ['-Gconfig=' + self.configuration] + # Stash the gyp configuration we used to run gyp, so we can + # know whether we need to rerun it later. + self.last_gyp_configuration = self.configuration + TestGypBase.run_gyp(self, gyp_file, *args, **kw) + + def build(self, gyp_file, target=None, **kw): + if self.last_gyp_configuration != self.configuration: + # Rerun gyp if necessary. + self.run_gyp(gyp_file) + + 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)] + 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 in (self.STATIC_LIB,): + result.append('obj') + elif type in (self.SHARED_LIB,): + result.append('lib') + subdir = kw.get('subdir') + if subdir: + 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): + kw['stdout'] = "ninja: no work to do.\n" + return self.build(gyp_file, target, **kw) + + +class TestGypMSVS(TestGypBase): + """ + 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): + """ Initializes the Visual Studio .build_tool and .uses_msbuild parameters. + + 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. + """ + super(TestGypMSVS, self).initialize_build_tool() + possible_roots = ['C:\\Program Files (x86)', 'C:\\Program Files', + 'E:\\Program Files (x86)', 'E:\\Program Files'] + possible_paths = { + '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'} + msvs_version = os.environ.get('GYP_MSVS_VERSION', 'auto') + 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: + bt = os.path.join(r, path) + if os.path.exists(bt): + self.build_tool = bt + self.uses_msbuild = msvs_version >= '2010' + return + else: + print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" ' + 'but corresponding "%s" was not found.' % (msvs_version, path)) + if self.build_tool: + # We found 'devenv' on the path, use that and try to guess the version. + for version, path in possible_paths.iteritems(): + if self.build_tool.find(path) >= 0: + self.uses_msbuild = version >= '2010' + return + else: + # If not, assume not MSBuild. + self.uses_msbuild = False + return + # Neither GYP_MSVS_VERSION nor the path help us out. Iterate through + # the choices looking for a match. + for version, path in possible_paths.iteritems(): + for r in possible_roots: + bt = os.path.join(r, path) + if os.path.exists(bt): + self.build_tool = bt + self.uses_msbuild = msvs_version >= '2010' + return + print 'Error: could not find devenv' + sys.exit(1) + def build(self, gyp_file, target=None, rebuild=False, **kw): + """ + Runs a Visual Studio build using the configuration generated + from the specified gyp_file. + """ + configuration = self.configuration_buildname() + if 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 m.group(1) == '1' + 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 TestGypSCons(TestGypBase): + """ + Subclass for testing the GYP SCons generator. + """ + format = 'scons' + build_tool_list = ['scons', 'scons.py'] + ALL = 'all' + def build(self, gyp_file, target=None, **kw): + """ + Runs a scons build using the SCons configuration generated from the + specified gyp_file. + """ + arguments = kw.get('arguments', [])[:] + dirname = os.path.dirname(gyp_file) + if dirname: + arguments.extend(['-C', dirname]) + if self.configuration: + arguments.append('--mode=' + self.configuration) + if target not in (None, self.DEFAULT): + arguments.append(target) + 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 SCons target is up to date. + """ + if target in (None, self.DEFAULT): + up_to_date_targets = 'all' + else: + up_to_date_targets = target + up_to_date_lines = [] + for arg in up_to_date_targets.split(): + up_to_date_lines.append("scons: `%s' is up to date.\n" % arg) + kw['stdout'] = ''.join(up_to_date_lines) + arguments = kw.get('arguments', [])[:] + arguments.append('-Q') + kw['arguments'] = arguments + return self.build(gyp_file, target, **kw) + def run_built_executable(self, name, *args, **kw): + """ + Runs an executable built by scons. + """ + configuration = self.configuration_dirname() + os.environ['LD_LIBRARY_PATH'] = os.path.join(configuration, 'lib') + # 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 Scons. + + 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 in (self.STATIC_LIB, self.SHARED_LIB): + result.append('lib') + result.append(self.built_file_basename(name, type, **kw)) + return self.workpath(*result) + + +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 + ) + + 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 + 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, + TestGypMake, + TestGypMSVS, + TestGypNinja, + TestGypSCons, + TestGypXcode, +] + +def TestGyp(*args, **kw): + """ + Returns an appropriate TestGyp* instance for a specified GYP format. + """ + format = kw.get('format') + if format: + del kw['format'] + else: + 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/tools/gyp/test/library/gyptest-shared-obj-install-path.py b/tools/gyp/test/library/gyptest-shared-obj-install-path.py new file mode 100755 index 0000000..2cf1a28 --- /dev/null +++ b/tools/gyp/test/library/gyptest-shared-obj-install-path.py @@ -0,0 +1,37 @@ +#!/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 .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') + +with open('relocate/src/Makefile') 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('relocate/src/Makefile', 'w') as makefile: + makefile.write(make_contents) + +test.build('shared_dependency.gyp', test.ALL, chdir='relocate/src') + +test.pass_test() diff --git a/tools/gyp/test/library/gyptest-shared.py b/tools/gyp/test/library/gyptest-shared.py new file mode 100755 index 0000000..a1d2985 --- /dev/null +++ b/tools/gyp/test/library/gyptest-shared.py @@ -0,0 +1,84 @@ +#!/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() + +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/tools/gyp/test/library/gyptest-static.py b/tools/gyp/test/library/gyptest-static.py new file mode 100755 index 0000000..4bc71c4 --- /dev/null +++ b/tools/gyp/test/library/gyptest-static.py @@ -0,0 +1,84 @@ +#!/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() + +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/tools/gyp/test/library/src/lib1.c b/tools/gyp/test/library/src/lib1.c new file mode 100644 index 0000000..3866b1b --- /dev/null +++ b/tools/gyp/test/library/src/lib1.c @@ -0,0 +1,10 @@ +#include + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void lib1_function(void) +{ + fprintf(stdout, "Hello from lib1.c\n"); + fflush(stdout); +} diff --git a/tools/gyp/test/library/src/lib1_moveable.c b/tools/gyp/test/library/src/lib1_moveable.c new file mode 100644 index 0000000..5d3cc1d --- /dev/null +++ b/tools/gyp/test/library/src/lib1_moveable.c @@ -0,0 +1,10 @@ +#include + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void moveable_function(void) +{ + fprintf(stdout, "Hello from lib1_moveable.c\n"); + fflush(stdout); +} diff --git a/tools/gyp/test/library/src/lib2.c b/tools/gyp/test/library/src/lib2.c new file mode 100644 index 0000000..21dda72 --- /dev/null +++ b/tools/gyp/test/library/src/lib2.c @@ -0,0 +1,10 @@ +#include + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void lib2_function(void) +{ + fprintf(stdout, "Hello from lib2.c\n"); + fflush(stdout); +} diff --git a/tools/gyp/test/library/src/lib2_moveable.c b/tools/gyp/test/library/src/lib2_moveable.c new file mode 100644 index 0000000..f645071 --- /dev/null +++ b/tools/gyp/test/library/src/lib2_moveable.c @@ -0,0 +1,10 @@ +#include + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void moveable_function(void) +{ + fprintf(stdout, "Hello from lib2_moveable.c\n"); + fflush(stdout); +} diff --git a/tools/gyp/test/library/src/library.gyp b/tools/gyp/test/library/src/library.gyp new file mode 100644 index 0000000..bc35516 --- /dev/null +++ b/tools/gyp/test/library/src/library.gyp @@ -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/tools/gyp/test/library/src/program.c b/tools/gyp/test/library/src/program.c new file mode 100644 index 0000000..d7712cc --- /dev/null +++ b/tools/gyp/test/library/src/program.c @@ -0,0 +1,15 @@ +#include + +extern void lib1_function(void); +extern void lib2_function(void); +extern void moveable_function(void); + +int main(int argc, char *argv[]) +{ + fprintf(stdout, "Hello from program.c\n"); + fflush(stdout); + lib1_function(); + lib2_function(); + moveable_function(); + return 0; +} diff --git a/tools/gyp/test/library/src/shared_dependency.gyp b/tools/gyp/test/library/src/shared_dependency.gyp new file mode 100644 index 0000000..7d29f5d --- /dev/null +++ b/tools/gyp/test/library/src/shared_dependency.gyp @@ -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/tools/gyp/test/link-objects/base.c b/tools/gyp/test/link-objects/base.c new file mode 100644 index 0000000..2bc29a1 --- /dev/null +++ b/tools/gyp/test/link-objects/base.c @@ -0,0 +1,6 @@ +void extra(); + +int main(int argc, char** argv) { + extra(); + return 0; +} diff --git a/tools/gyp/test/link-objects/extra.c b/tools/gyp/test/link-objects/extra.c new file mode 100644 index 0000000..1d7ee09 --- /dev/null +++ b/tools/gyp/test/link-objects/extra.c @@ -0,0 +1,5 @@ +#include + +void extra() { + printf("PASS\n"); +} diff --git a/tools/gyp/test/link-objects/gyptest-all.py b/tools/gyp/test/link-objects/gyptest-all.py new file mode 100755 index 0000000..45bd6e1 --- /dev/null +++ b/tools/gyp/test/link-objects/gyptest-all.py @@ -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/tools/gyp/test/link-objects/link-objects.gyp b/tools/gyp/test/link-objects/link-objects.gyp new file mode 100644 index 0000000..ab72855 --- /dev/null +++ b/tools/gyp/test/link-objects/link-objects.gyp @@ -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/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist.strings b/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..452e7fa --- /dev/null +++ b/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist.strings @@ -0,0 +1,3 @@ +/* Localized versions of Info.plist keys */ + +NSHumanReadableCopyright = "Copyright ©2011 Google Inc." diff --git a/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/MainMenu.xib b/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/MainMenu.xib new file mode 100644 index 0000000..4524596 --- /dev/null +++ b/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/MainMenu.xib @@ -0,0 +1,4119 @@ + + + + 1060 + 10A324 + 719 + 1015 + 418.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 719 + + + YES + + + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + YES + + YES + + + YES + + + + YES + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + YES + + + TestApp + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + TestApp + + YES + + + About TestApp + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Preferences… + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + Services + + YES + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide TestApp + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit TestApp + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + File + + YES + + + New + n + 1048576 + 2147483647 + + + + + + Open… + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + Open Recent + + YES + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + Save + s + 1048576 + 2147483647 + + + + + + Save As… + S + 1179648 + 2147483647 + + + + + + Revert to Saved + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Page Setup... + P + 1179648 + 2147483647 + + + + + + + Print… + p + 1048576 + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + Edit + + YES + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1179648 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Paste and Match Style + V + 1572864 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + Find + + YES + + + Find… + f + 1048576 + 2147483647 + + + 1 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1179648 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling and Grammar + + 1048576 + 2147483647 + + + submenuAction: + + Spelling and Grammar + + YES + + + Show Spelling and Grammar + : + 1048576 + 2147483647 + + + + + + Check Document Now + ; + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Check Spelling While Typing + + 1048576 + 2147483647 + + + + + + Check Grammar With Spelling + + 1048576 + 2147483647 + + + + + + Correct Spelling Automatically + + 2147483647 + + + + + + + + + Substitutions + + 1048576 + 2147483647 + + + submenuAction: + + Substitutions + + YES + + + Show Substitutions + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Smart Copy/Paste + f + 1048576 + 2147483647 + + + 1 + + + + Smart Quotes + g + 1048576 + 2147483647 + + + 2 + + + + Smart Dashes + + 2147483647 + + + + + + Smart Links + G + 1179648 + 2147483647 + + + 3 + + + + Text Replacement + + 2147483647 + + + + + + + + + Transformations + + 2147483647 + + + submenuAction: + + Transformations + + YES + + + Make Upper Case + + 2147483647 + + + + + + Make Lower Case + + 2147483647 + + + + + + Capitalize + + 2147483647 + + + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + Speech + + YES + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + Format + + 2147483647 + + + submenuAction: + + Format + + YES + + + Font + + 2147483647 + + + submenuAction: + + Font + + YES + + + Show Fonts + t + 1048576 + 2147483647 + + + + + + Bold + b + 1048576 + 2147483647 + + + 2 + + + + Italic + i + 1048576 + 2147483647 + + + 1 + + + + Underline + u + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Bigger + + + 1048576 + 2147483647 + + + 3 + + + + Smaller + - + 1048576 + 2147483647 + + + 4 + + + + YES + YES + + + 2147483647 + + + + + + Kern + + 2147483647 + + + submenuAction: + + Kern + + YES + + + Use Default + + 2147483647 + + + + + + Use None + + 2147483647 + + + + + + Tighten + + 2147483647 + + + + + + Loosen + + 2147483647 + + + + + + + + + Ligature + + 2147483647 + + + submenuAction: + + Ligature + + YES + + + Use Default + + 2147483647 + + + + + + Use None + + 2147483647 + + + + + + Use All + + 2147483647 + + + + + + + + + Baseline + + 2147483647 + + + submenuAction: + + Baseline + + YES + + + Use Default + + 2147483647 + + + + + + Superscript + + 2147483647 + + + + + + Subscript + + 2147483647 + + + + + + Raise + + 2147483647 + + + + + + Lower + + 2147483647 + + + + + + + + + YES + YES + + + 2147483647 + + + + + + Show Colors + C + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Copy Style + c + 1572864 + 2147483647 + + + + + + Paste Style + v + 1572864 + 2147483647 + + + + + _NSFontMenu + + + + + Text + + 2147483647 + + + submenuAction: + + Text + + YES + + + Align Left + { + 1048576 + 2147483647 + + + + + + Center + | + 1048576 + 2147483647 + + + + + + Justify + + 2147483647 + + + + + + Align Right + } + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Writing Direction + + 2147483647 + + + submenuAction: + + Writing Direction + + YES + + + YES + Paragraph + + 2147483647 + + + + + + CURlZmF1bHQ + + 2147483647 + + + + + + CUxlZnQgdG8gUmlnaHQ + + 2147483647 + + + + + + CVJpZ2h0IHRvIExlZnQ + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + YES + Selection + + 2147483647 + + + + + + CURlZmF1bHQ + + 2147483647 + + + + + + CUxlZnQgdG8gUmlnaHQ + + 2147483647 + + + + + + CVJpZ2h0IHRvIExlZnQ + + 2147483647 + + + + + + + + + YES + YES + + + 2147483647 + + + + + + Show Ruler + + 2147483647 + + + + + + Copy Ruler + c + 1310720 + 2147483647 + + + + + + Paste Ruler + v + 1310720 + 2147483647 + + + + + + + + + + + + View + + 1048576 + 2147483647 + + + submenuAction: + + View + + YES + + + Show Toolbar + t + 1572864 + 2147483647 + + + + + + Customize Toolbar… + + 1048576 + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + Window + + YES + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 2147483647 + + + submenuAction: + + Help + + YES + + + TestApp Help + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + 15 + 2 + {{335, 390}, {480, 360}} + 1954021376 + TestApp + NSWindow + + {1.79769e+308, 1.79769e+308} + + + 256 + {480, 360} + + + {{0, 0}, {1920, 1178}} + {1.79769e+308, 1.79769e+308} + + + TestAppAppDelegate + + + NSFontManager + + + + + YES + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + print: + + + + 86 + + + + runPageLayout: + + + + 87 + + + + clearRecentDocuments: + + + + 127 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + toggleGrammarChecking: + + + + 347 + + + + toggleSmartInsertDelete: + + + + 355 + + + + toggleAutomaticQuoteSubstitution: + + + + 356 + + + + toggleAutomaticLinkDetection: + + + + 357 + + + + saveDocument: + + + + 362 + + + + saveDocumentAs: + + + + 363 + + + + revertDocumentToSaved: + + + + 364 + + + + runToolbarCustomizationPalette: + + + + 365 + + + + toggleToolbarShown: + + + + 366 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + unhideAllApplications: + + + + 370 + + + + newDocument: + + + + 373 + + + + openDocument: + + + + 374 + + + + addFontTrait: + + + + 421 + + + + addFontTrait: + + + + 422 + + + + modifyFont: + + + + 423 + + + + orderFrontFontPanel: + + + + 424 + + + + modifyFont: + + + + 425 + + + + raiseBaseline: + + + + 426 + + + + lowerBaseline: + + + + 427 + + + + copyFont: + + + + 428 + + + + subscript: + + + + 429 + + + + superscript: + + + + 430 + + + + tightenKerning: + + + + 431 + + + + underline: + + + + 432 + + + + orderFrontColorPanel: + + + + 433 + + + + useAllLigatures: + + + + 434 + + + + loosenKerning: + + + + 435 + + + + pasteFont: + + + + 436 + + + + unscript: + + + + 437 + + + + useStandardKerning: + + + + 438 + + + + useStandardLigatures: + + + + 439 + + + + turnOffLigatures: + + + + 440 + + + + turnOffKerning: + + + + 441 + + + + terminate: + + + + 449 + + + + toggleAutomaticSpellingCorrection: + + + + 456 + + + + orderFrontSubstitutionsPanel: + + + + 458 + + + + toggleAutomaticDashSubstitution: + + + + 461 + + + + toggleAutomaticTextReplacement: + + + + 463 + + + + uppercaseWord: + + + + 464 + + + + capitalizeWord: + + + + 467 + + + + lowercaseWord: + + + + 468 + + + + pasteAsPlainText: + + + + 486 + + + + performFindPanelAction: + + + + 487 + + + + performFindPanelAction: + + + + 488 + + + + performFindPanelAction: + + + + 489 + + + + showHelp: + + + + 493 + + + + delegate + + + + 495 + + + + alignCenter: + + + + 518 + + + + pasteRuler: + + + + 519 + + + + toggleRuler: + + + + 520 + + + + alignRight: + + + + 521 + + + + copyRuler: + + + + 522 + + + + alignJustified: + + + + 523 + + + + alignLeft: + + + + 524 + + + + makeBaseWritingDirectionNatural: + + + + 525 + + + + makeBaseWritingDirectionLeftToRight: + + + + 526 + + + + makeBaseWritingDirectionRightToLeft: + + + + 527 + + + + makeTextWritingDirectionNatural: + + + + 528 + + + + makeTextWritingDirectionLeftToRight: + + + + 529 + + + + makeTextWritingDirectionRightToLeft: + + + + 530 + + + + window + + + + 532 + + + + + YES + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + YES + + + + + + + + + + + + 19 + + + YES + + + + + + 56 + + + YES + + + + + + 217 + + + YES + + + + + + 83 + + + YES + + + + + + 81 + + + YES + + + + + + + + + + + + + + + + 75 + + + + + 80 + + + + + 78 + + + + + 72 + + + + + 82 + + + + + 124 + + + YES + + + + + + 77 + + + + + 73 + + + + + 79 + + + + + 112 + + + + + 74 + + + + + 125 + + + YES + + + + + + 126 + + + + + 205 + + + YES + + + + + + + + + + + + + + + + + + + + 202 + + + + + 198 + + + + + 207 + + + + + 214 + + + + + 199 + + + + + 203 + + + + + 197 + + + + + 206 + + + + + 215 + + + + + 218 + + + YES + + + + + + 216 + + + YES + + + + + + 200 + + + YES + + + + + + + + + + + 219 + + + + + 201 + + + + + 204 + + + + + 220 + + + YES + + + + + + + + + + 213 + + + + + 210 + + + + + 221 + + + + + 208 + + + + + 209 + + + + + 57 + + + YES + + + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + + + 144 + + + + + 129 + + + + + 143 + + + + + 236 + + + + + 131 + + + YES + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 24 + + + YES + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 295 + + + YES + + + + + + 296 + + + YES + + + + + + + 297 + + + + + 298 + + + + + 211 + + + YES + + + + + + 212 + + + YES + + + + + + + 195 + + + + + 196 + + + + + 346 + + + + + 348 + + + YES + + + + + + 349 + + + YES + + + + + + + + + + + + 350 + + + + + 351 + + + + + 354 + + + + + 371 + + + YES + + + + + + 372 + + + + + 375 + + + YES + + + + + + 376 + + + YES + + + + + + + 377 + + + YES + + + + + + 388 + + + YES + + + + + + + + + + + + + + + + + + + + + 389 + + + + + 390 + + + + + 391 + + + + + 392 + + + + + 393 + + + + + 394 + + + + + 395 + + + + + 396 + + + + + 397 + + + YES + + + + + + 398 + + + YES + + + + + + 399 + + + YES + + + + + + 400 + + + + + 401 + + + + + 402 + + + + + 403 + + + + + 404 + + + + + 405 + + + YES + + + + + + + + + + 406 + + + + + 407 + + + + + 408 + + + + + 409 + + + + + 410 + + + + + 411 + + + YES + + + + + + + + 412 + + + + + 413 + + + + + 414 + + + + + 415 + + + YES + + + + + + + + + 416 + + + + + 417 + + + + + 418 + + + + + 419 + + + + + 420 + + + + + 450 + + + YES + + + + + + 451 + + + YES + + + + + + + + 452 + + + + + 453 + + + + + 454 + + + + + 457 + + + + + 459 + + + + + 460 + + + + + 462 + + + + + 465 + + + + + 466 + + + + + 485 + + + + + 490 + + + YES + + + + + + 491 + + + YES + + + + + + 492 + + + + + 494 + + + + + 496 + + + YES + + + + + + 497 + + + YES + + + + + + + + + + + + + + + 498 + + + + + 499 + + + + + 500 + + + + + 501 + + + + + 502 + + + + + 503 + + + YES + + + + + + 504 + + + + + 505 + + + + + 506 + + + + + 507 + + + + + 508 + + + YES + + + + + + + + + + + + + + 509 + + + + + 510 + + + + + 511 + + + + + 512 + + + + + 513 + + + + + 514 + + + + + 515 + + + + + 516 + + + + + 517 + + + + + + + YES + + YES + -3.IBPluginDependency + 112.IBPluginDependency + 112.ImportedFromIB2 + 124.IBPluginDependency + 124.ImportedFromIB2 + 125.IBPluginDependency + 125.ImportedFromIB2 + 125.editorWindowContentRectSynchronizationRect + 126.IBPluginDependency + 126.ImportedFromIB2 + 129.IBPluginDependency + 129.ImportedFromIB2 + 130.IBPluginDependency + 130.ImportedFromIB2 + 130.editorWindowContentRectSynchronizationRect + 131.IBPluginDependency + 131.ImportedFromIB2 + 134.IBPluginDependency + 134.ImportedFromIB2 + 136.IBPluginDependency + 136.ImportedFromIB2 + 143.IBPluginDependency + 143.ImportedFromIB2 + 144.IBPluginDependency + 144.ImportedFromIB2 + 145.IBPluginDependency + 145.ImportedFromIB2 + 149.IBPluginDependency + 149.ImportedFromIB2 + 150.IBPluginDependency + 150.ImportedFromIB2 + 19.IBPluginDependency + 19.ImportedFromIB2 + 195.IBPluginDependency + 195.ImportedFromIB2 + 196.IBPluginDependency + 196.ImportedFromIB2 + 197.IBPluginDependency + 197.ImportedFromIB2 + 198.IBPluginDependency + 198.ImportedFromIB2 + 199.IBPluginDependency + 199.ImportedFromIB2 + 200.IBEditorWindowLastContentRect + 200.IBPluginDependency + 200.ImportedFromIB2 + 200.editorWindowContentRectSynchronizationRect + 201.IBPluginDependency + 201.ImportedFromIB2 + 202.IBPluginDependency + 202.ImportedFromIB2 + 203.IBPluginDependency + 203.ImportedFromIB2 + 204.IBPluginDependency + 204.ImportedFromIB2 + 205.IBEditorWindowLastContentRect + 205.IBPluginDependency + 205.ImportedFromIB2 + 205.editorWindowContentRectSynchronizationRect + 206.IBPluginDependency + 206.ImportedFromIB2 + 207.IBPluginDependency + 207.ImportedFromIB2 + 208.IBPluginDependency + 208.ImportedFromIB2 + 209.IBPluginDependency + 209.ImportedFromIB2 + 210.IBPluginDependency + 210.ImportedFromIB2 + 211.IBPluginDependency + 211.ImportedFromIB2 + 212.IBPluginDependency + 212.ImportedFromIB2 + 212.editorWindowContentRectSynchronizationRect + 213.IBPluginDependency + 213.ImportedFromIB2 + 214.IBPluginDependency + 214.ImportedFromIB2 + 215.IBPluginDependency + 215.ImportedFromIB2 + 216.IBPluginDependency + 216.ImportedFromIB2 + 217.IBPluginDependency + 217.ImportedFromIB2 + 218.IBPluginDependency + 218.ImportedFromIB2 + 219.IBPluginDependency + 219.ImportedFromIB2 + 220.IBEditorWindowLastContentRect + 220.IBPluginDependency + 220.ImportedFromIB2 + 220.editorWindowContentRectSynchronizationRect + 221.IBPluginDependency + 221.ImportedFromIB2 + 23.IBPluginDependency + 23.ImportedFromIB2 + 236.IBPluginDependency + 236.ImportedFromIB2 + 239.IBPluginDependency + 239.ImportedFromIB2 + 24.IBEditorWindowLastContentRect + 24.IBPluginDependency + 24.ImportedFromIB2 + 24.editorWindowContentRectSynchronizationRect + 29.IBEditorWindowLastContentRect + 29.IBPluginDependency + 29.ImportedFromIB2 + 29.WindowOrigin + 29.editorWindowContentRectSynchronizationRect + 295.IBPluginDependency + 296.IBEditorWindowLastContentRect + 296.IBPluginDependency + 296.editorWindowContentRectSynchronizationRect + 297.IBPluginDependency + 298.IBPluginDependency + 346.IBPluginDependency + 346.ImportedFromIB2 + 348.IBPluginDependency + 348.ImportedFromIB2 + 349.IBEditorWindowLastContentRect + 349.IBPluginDependency + 349.ImportedFromIB2 + 349.editorWindowContentRectSynchronizationRect + 350.IBPluginDependency + 350.ImportedFromIB2 + 351.IBPluginDependency + 351.ImportedFromIB2 + 354.IBPluginDependency + 354.ImportedFromIB2 + 371.IBEditorWindowLastContentRect + 371.IBPluginDependency + 371.IBWindowTemplateEditedContentRect + 371.NSWindowTemplate.visibleAtLaunch + 371.editorWindowContentRectSynchronizationRect + 371.windowTemplate.maxSize + 372.IBPluginDependency + 375.IBPluginDependency + 376.IBEditorWindowLastContentRect + 376.IBPluginDependency + 377.IBPluginDependency + 388.IBEditorWindowLastContentRect + 388.IBPluginDependency + 389.IBPluginDependency + 390.IBPluginDependency + 391.IBPluginDependency + 392.IBPluginDependency + 393.IBPluginDependency + 394.IBPluginDependency + 395.IBPluginDependency + 396.IBPluginDependency + 397.IBPluginDependency + 398.IBPluginDependency + 399.IBPluginDependency + 400.IBPluginDependency + 401.IBPluginDependency + 402.IBPluginDependency + 403.IBPluginDependency + 404.IBPluginDependency + 405.IBPluginDependency + 406.IBPluginDependency + 407.IBPluginDependency + 408.IBPluginDependency + 409.IBPluginDependency + 410.IBPluginDependency + 411.IBPluginDependency + 412.IBPluginDependency + 413.IBPluginDependency + 414.IBPluginDependency + 415.IBPluginDependency + 416.IBPluginDependency + 417.IBPluginDependency + 418.IBPluginDependency + 419.IBPluginDependency + 450.IBPluginDependency + 451.IBEditorWindowLastContentRect + 451.IBPluginDependency + 452.IBPluginDependency + 453.IBPluginDependency + 454.IBPluginDependency + 457.IBPluginDependency + 459.IBPluginDependency + 460.IBPluginDependency + 462.IBPluginDependency + 465.IBPluginDependency + 466.IBPluginDependency + 485.IBPluginDependency + 490.IBPluginDependency + 491.IBEditorWindowLastContentRect + 491.IBPluginDependency + 492.IBPluginDependency + 496.IBPluginDependency + 497.IBEditorWindowLastContentRect + 497.IBPluginDependency + 498.IBPluginDependency + 499.IBPluginDependency + 5.IBPluginDependency + 5.ImportedFromIB2 + 500.IBPluginDependency + 501.IBPluginDependency + 502.IBPluginDependency + 503.IBPluginDependency + 504.IBPluginDependency + 505.IBPluginDependency + 506.IBPluginDependency + 507.IBPluginDependency + 508.IBEditorWindowLastContentRect + 508.IBPluginDependency + 509.IBPluginDependency + 510.IBPluginDependency + 511.IBPluginDependency + 512.IBPluginDependency + 513.IBPluginDependency + 514.IBPluginDependency + 515.IBPluginDependency + 516.IBPluginDependency + 517.IBPluginDependency + 56.IBPluginDependency + 56.ImportedFromIB2 + 57.IBEditorWindowLastContentRect + 57.IBPluginDependency + 57.ImportedFromIB2 + 57.editorWindowContentRectSynchronizationRect + 58.IBPluginDependency + 58.ImportedFromIB2 + 72.IBPluginDependency + 72.ImportedFromIB2 + 73.IBPluginDependency + 73.ImportedFromIB2 + 74.IBPluginDependency + 74.ImportedFromIB2 + 75.IBPluginDependency + 75.ImportedFromIB2 + 77.IBPluginDependency + 77.ImportedFromIB2 + 78.IBPluginDependency + 78.ImportedFromIB2 + 79.IBPluginDependency + 79.ImportedFromIB2 + 80.IBPluginDependency + 80.ImportedFromIB2 + 81.IBEditorWindowLastContentRect + 81.IBPluginDependency + 81.ImportedFromIB2 + 81.editorWindowContentRectSynchronizationRect + 82.IBPluginDependency + 82.ImportedFromIB2 + 83.IBPluginDependency + 83.ImportedFromIB2 + 92.IBPluginDependency + 92.ImportedFromIB2 + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{522, 812}, {146, 23}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{436, 809}, {64, 6}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{753, 187}, {275, 113}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{608, 612}, {275, 83}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{547, 180}, {254, 283}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{187, 434}, {243, 243}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{608, 612}, {167, 43}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{753, 217}, {238, 103}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{608, 612}, {241, 103}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{654, 239}, {194, 73}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{525, 802}, {197, 73}} + {{380, 836}, {512, 20}} + com.apple.InterfaceBuilder.CocoaPlugin + + {74, 862} + {{6, 978}, {478, 20}} + com.apple.InterfaceBuilder.CocoaPlugin + {{604, 269}, {231, 43}} + com.apple.InterfaceBuilder.CocoaPlugin + {{475, 832}, {234, 43}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{746, 287}, {220, 133}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{608, 612}, {215, 63}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{380, 496}, {480, 360}} + com.apple.InterfaceBuilder.CocoaPlugin + {{380, 496}, {480, 360}} + + {{33, 99}, {480, 360}} + {3.40282e+38, 3.40282e+38} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{591, 420}, {83, 43}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{523, 2}, {178, 283}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{753, 197}, {170, 63}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{725, 289}, {246, 23}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{674, 260}, {204, 183}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{878, 180}, {164, 173}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + {{286, 129}, {275, 183}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{23, 794}, {245, 183}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{452, 109}, {196, 203}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{145, 474}, {199, 203}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + YES + + + YES + + + + + YES + + + YES + + + + 532 + + + + YES + + TestAppAppDelegate + NSObject + + window + NSWindow + + + IBProjectSource + TestAppAppDelegate.h + + + + + YES + + NSApplication + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSApplication.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSApplicationScripting.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSColorPanel.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSHelpManager.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSPageLayout.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSUserInterfaceItemSearching.h + + + + NSBrowser + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSBrowser.h + + + + NSControl + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSControl.h + + + + NSDocument + NSObject + + YES + + YES + printDocument: + revertDocumentToSaved: + runPageLayout: + saveDocument: + saveDocumentAs: + saveDocumentTo: + + + YES + id + id + id + id + id + id + + + + IBFrameworkSource + AppKit.framework/Headers/NSDocument.h + + + + NSDocument + + IBFrameworkSource + AppKit.framework/Headers/NSDocumentScripting.h + + + + NSDocumentController + NSObject + + YES + + YES + clearRecentDocuments: + newDocument: + openDocument: + saveAllDocuments: + + + YES + id + id + id + id + + + + IBFrameworkSource + AppKit.framework/Headers/NSDocumentController.h + + + + NSFontManager + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontManager.h + + + + NSFormatter + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFormatter.h + + + + NSMatrix + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSMatrix.h + + + + NSMenu + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenu.h + + + + NSMenuItem + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenuItem.h + + + + NSMovieView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSMovieView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSAccessibility.h + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDictionaryController.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDragging.h + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontPanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSKeyValueBinding.h + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSNibLoading.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSOutlineView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSPasteboard.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSSavePanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSToolbarItem.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSView.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSError.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFileManager.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueObserving.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyedArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObject.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObjectScripting.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSPortCoder.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSRunLoop.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptObjectSpecifiers.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptWhoseTests.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSThread.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURL.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLConnection.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLDownload.h + + + + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSInterfaceStyle.h + + + + NSResponder + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSResponder.h + + + + NSTableView + NSControl + + + + NSText + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSText.h + + + + NSTextView + NSText + + IBFrameworkSource + AppKit.framework/Headers/NSTextView.h + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSClipView.h + + + + NSView + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSRulerView.h + + + + NSView + NSResponder + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSDrawer.h + + + + NSWindow + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSWindow.h + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSWindowScripting.h + + + + + 0 + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + ../TestApp.xcodeproj + 3 + + diff --git a/tools/gyp/test/mac/app-bundle/TestApp/TestApp-Info.plist b/tools/gyp/test/mac/app-bundle/TestApp/TestApp-Info.plist new file mode 100644 index 0000000..98fd515 --- /dev/null +++ b/tools/gyp/test/mac/app-bundle/TestApp/TestApp-Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.google.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/tools/gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.h b/tools/gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.h new file mode 100644 index 0000000..518645e --- /dev/null +++ b/tools/gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.h @@ -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 + +@interface TestAppAppDelegate : NSObject { + NSWindow *window; +} + +@property (assign) IBOutlet NSWindow *window; + +@end diff --git a/tools/gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.m b/tools/gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.m new file mode 100644 index 0000000..9aafa42 --- /dev/null +++ b/tools/gyp/test/mac/app-bundle/TestApp/TestAppAppDelegate.m @@ -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/tools/gyp/test/mac/app-bundle/TestApp/main.m b/tools/gyp/test/mac/app-bundle/TestApp/main.m new file mode 100644 index 0000000..df6a12d --- /dev/null +++ b/tools/gyp/test/mac/app-bundle/TestApp/main.m @@ -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 + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **) argv); +} diff --git a/tools/gyp/test/mac/app-bundle/empty.c b/tools/gyp/test/mac/app-bundle/empty.c new file mode 100644 index 0000000..e69de29 diff --git a/tools/gyp/test/mac/app-bundle/test.gyp b/tools/gyp/test/mac/app-bundle/test.gyp new file mode 100644 index 0000000..f51c7b4 --- /dev/null +++ b/tools/gyp/test/mac/app-bundle/test.gyp @@ -0,0 +1,39 @@ +# 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', + '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/tools/gyp/test/mac/debuginfo/file.c b/tools/gyp/test/mac/debuginfo/file.c new file mode 100644 index 0000000..9cddaf1 --- /dev/null +++ b/tools/gyp/test/mac/debuginfo/file.c @@ -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/tools/gyp/test/mac/debuginfo/test.gyp b/tools/gyp/test/mac/debuginfo/test.gyp new file mode 100644 index 0000000..3faf6b5 --- /dev/null +++ b/tools/gyp/test/mac/debuginfo/test.gyp @@ -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/tools/gyp/test/mac/framework/TestFramework/English.lproj/InfoPlist.strings b/tools/gyp/test/mac/framework/TestFramework/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..88f65cf --- /dev/null +++ b/tools/gyp/test/mac/framework/TestFramework/English.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/tools/gyp/test/mac/framework/TestFramework/Info.plist b/tools/gyp/test/mac/framework/TestFramework/Info.plist new file mode 100644 index 0000000..5e05a51 --- /dev/null +++ b/tools/gyp/test/mac/framework/TestFramework/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.yourcompany.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/tools/gyp/test/mac/framework/TestFramework/ObjCVector.h b/tools/gyp/test/mac/framework/TestFramework/ObjCVector.h new file mode 100644 index 0000000..c245096 --- /dev/null +++ b/tools/gyp/test/mac/framework/TestFramework/ObjCVector.h @@ -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 + +#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/tools/gyp/test/mac/framework/TestFramework/ObjCVector.mm b/tools/gyp/test/mac/framework/TestFramework/ObjCVector.mm new file mode 100644 index 0000000..cbf431f --- /dev/null +++ b/tools/gyp/test/mac/framework/TestFramework/ObjCVector.mm @@ -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 + +@interface ObjCVector (Private) +- (std::vector::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::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::iterator)makeIterator:(NSUInteger)index { + std::vector::iterator it = imp_->v.begin(); + it += index; + return it; +} + +@end diff --git a/tools/gyp/test/mac/framework/TestFramework/ObjCVectorInternal.h b/tools/gyp/test/mac/framework/TestFramework/ObjCVectorInternal.h new file mode 100644 index 0000000..fb6c982 --- /dev/null +++ b/tools/gyp/test/mac/framework/TestFramework/ObjCVectorInternal.h @@ -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 + +struct ObjCVectorImp { + std::vector v; +}; diff --git a/tools/gyp/test/mac/framework/TestFramework/TestFramework_Prefix.pch b/tools/gyp/test/mac/framework/TestFramework/TestFramework_Prefix.pch new file mode 100644 index 0000000..394f41d --- /dev/null +++ b/tools/gyp/test/mac/framework/TestFramework/TestFramework_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'TestFramework' target in the 'TestFramework' project. +// + +#ifdef __OBJC__ + #import +#endif diff --git a/tools/gyp/test/mac/framework/empty.c b/tools/gyp/test/mac/framework/empty.c new file mode 100644 index 0000000..e69de29 diff --git a/tools/gyp/test/mac/framework/framework.gyp b/tools/gyp/test/mac/framework/framework.gyp new file mode 100644 index 0000000..7480e52 --- /dev/null +++ b/tools/gyp/test/mac/framework/framework.gyp @@ -0,0 +1,74 @@ +# 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_framework_headers': [ + 'TestFramework/ObjCVector.h', + ], + '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/tools/gyp/test/mac/gyptest-app.py b/tools/gyp/test/mac/gyptest-app.py new file mode 100755 index 0000000..5e772f8 --- /dev/null +++ b/tools/gyp/test/mac/gyptest-app.py @@ -0,0 +1,44 @@ +#!/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 app bundles are built correctly. +""" + +import TestGyp + +import sys + +if sys.platform == 'darwin': + test = TestGyp.TestGyp(formats=['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 + + # Resources + test.built_file_must_exist( + 'Test App Gyp.app/Contents/Resources/English.lproj/InfoPlist.strings', + chdir='app-bundle') + 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.pass_test() diff --git a/tools/gyp/test/mac/gyptest-copies.py b/tools/gyp/test/mac/gyptest-copies.py new file mode 100755 index 0000000..091b1de --- /dev/null +++ b/tools/gyp/test/mac/gyptest-copies.py @@ -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. + +""" +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=['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/tools/gyp/test/mac/gyptest-debuginfo.py b/tools/gyp/test/mac/gyptest-debuginfo.py new file mode 100755 index 0000000..1ec2d1d --- /dev/null +++ b/tools/gyp/test/mac/gyptest-debuginfo.py @@ -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=['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/tools/gyp/test/mac/gyptest-framework.py b/tools/gyp/test/mac/gyptest-framework.py new file mode 100755 index 0000000..6c19e40 --- /dev/null +++ b/tools/gyp/test/mac/gyptest-framework.py @@ -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 that app bundles are built correctly. +""" + +import TestGyp + +import sys + +if sys.platform == 'darwin': + test = TestGyp.TestGyp(formats=['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 + test.built_file_must_exist( + 'Test Framework.framework/Versions/A/Resources/Info.plist', + chdir='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') + + test.pass_test() diff --git a/tools/gyp/test/mac/gyptest-infoplist-process.py b/tools/gyp/test/mac/gyptest-infoplist-process.py new file mode 100755 index 0000000..9a2b140 --- /dev/null +++ b/tools/gyp/test/mac/gyptest-infoplist-process.py @@ -0,0 +1,51 @@ +#!/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 the Info.plist preprocessor functionality. +""" + +import TestGyp + +import sys + +if sys.platform == 'darwin': + test = TestGyp.TestGyp(formats=['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/tools/gyp/test/mac/gyptest-loadable-module.py b/tools/gyp/test/mac/gyptest-loadable-module.py new file mode 100755 index 0000000..39e87f0 --- /dev/null +++ b/tools/gyp/test/mac/gyptest-loadable-module.py @@ -0,0 +1,45 @@ +#!/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 that a loadable_module target is built correctly. +""" + +import TestGyp + +import os +import sys + +if sys.platform == 'darwin': + test = TestGyp.TestGyp(formats=['make', 'xcode']) + + test.run_gyp('test.gyp', chdir='loadable-module') + test.build('test.gyp', test.ALL, chdir='loadable-module') + + # Binary. + test.built_file_must_exist( + 'test_loadable_module.plugin/Contents/MacOS/test_loadable_module', + chdir='loadable-module') + + # Info.plist. + info_plist = test.built_file_path( + 'test_loadable_module.plugin/Contents/Info.plist', + chdir='loadable-module') + test.must_exist(info_plist) + test.must_contain(info_plist, """ + CFBundleExecutable + test_loadable_module +""") + + # PkgInfo. + test.built_file_must_not_exist( + 'test_loadable_module.plugin/Contents/PkgInfo', + chdir='loadable-module') + test.built_file_must_not_exist( + 'test_loadable_module.plugin/Contents/Resources', + chdir='loadable-module') + + test.pass_test() diff --git a/tools/gyp/test/mac/gyptest-postbuild-fail.py b/tools/gyp/test/mac/gyptest-postbuild-fail.py new file mode 100755 index 0000000..28b1a80 --- /dev/null +++ b/tools/gyp/test/mac/gyptest-postbuild-fail.py @@ -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 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=['make', 'xcode'], match = lambda a, b: True) + + test.run_gyp('test.gyp', chdir='postbuild-fail') + + build_error_code = { + 'xcode': 1, + 'make': 2, + }[test.format] + + + # If a postbuild fails, all postbuilds should be re-run on the next build. + # However, even if the first postbuild fails the other postbuilds are still + # executed. + + + # Non-bundles + test.build('test.gyp', 'nonbundle', chdir='postbuild-fail', + status=build_error_code) + test.built_file_must_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_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/tools/gyp/test/mac/gyptest-postbuild.py b/tools/gyp/test/mac/gyptest-postbuild.py new file mode 100755 index 0000000..b69a0bd --- /dev/null +++ b/tools/gyp/test/mac/gyptest-postbuild.py @@ -0,0 +1,51 @@ +#!/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=['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.pass_test() diff --git a/tools/gyp/test/mac/gyptest-prefixheader.py b/tools/gyp/test/mac/gyptest-prefixheader.py new file mode 100755 index 0000000..04b00f6 --- /dev/null +++ b/tools/gyp/test/mac/gyptest-prefixheader.py @@ -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. + +""" +Verifies that GCC_PREFIX_HEADER works. +""" + +import TestGyp + +import sys + +if sys.platform == 'darwin': + test = TestGyp.TestGyp(formats=['make', 'xcode']) + test.run_gyp('test.gyp', chdir='prefixheader') + test.build('test.gyp', test.ALL, chdir='prefixheader') + test.pass_test() diff --git a/tools/gyp/test/mac/gyptest-rebuild.py b/tools/gyp/test/mac/gyptest-rebuild.py new file mode 100755 index 0000000..f88dcb9 --- /dev/null +++ b/tools/gyp/test/mac/gyptest-rebuild.py @@ -0,0 +1,29 @@ +#!/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 app bundles are rebuilt correctly. +""" + +import TestGyp + +import os +import sys + +if sys.platform == 'darwin': + test = TestGyp.TestGyp(formats=['make', 'xcode']) + + test.run_gyp('test.gyp', chdir='app-bundle') + + test.build('test.gyp', test.ALL, chdir='app-bundle') + + # Touch a source file, rebuild, and check that the app target is up-to-date. + os.utime('app-bundle/TestApp/main.m', None) + test.build('test.gyp', test.ALL, chdir='app-bundle') + + test.up_to_date('test.gyp', test.ALL, chdir='app-bundle') + + test.pass_test() diff --git a/tools/gyp/test/mac/gyptest-strip.py b/tools/gyp/test/mac/gyptest-strip.py new file mode 100755 index 0000000..2e4c3b0 --- /dev/null +++ b/tools/gyp/test/mac/gyptest-strip.py @@ -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 stripping works. +""" + +import TestGyp + +import os +import re +import subprocess +import sys +import time + +if sys.platform == 'darwin': + test = TestGyp.TestGyp(formats=['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+)') + proc = subprocess.Popen(['otool', '-l', p], stdout=subprocess.PIPE) + o = proc.communicate()[0] + assert not proc.returncode + m = r.search(o, re.MULTILINE) + n = int(m.group(1)) + if n != n_expected: + print 'Stripping: Expected %d symbols, got %d' % (n_expected, n) + test.fail_test() + + # 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'), 11) + CheckNsyms(OutPath('no_strip'), 11) + CheckNsyms(OutPath('strip_all'), 0) + CheckNsyms(OutPath('strip_nonglobal'), 2) + CheckNsyms(OutPath('strip_debugging'), 3) + CheckNsyms(OutPath('strip_all_custom_flags'), 0) + CheckNsyms(test.built_file_path( + 'strip_all_bundle.framework/Versions/A/strip_all_bundle', chdir='strip'), + 0) + + test.pass_test() diff --git a/tools/gyp/test/mac/gyptest-type-envvars.py b/tools/gyp/test/mac/gyptest-type-envvars.py new file mode 100755 index 0000000..1ef6773 --- /dev/null +++ b/tools/gyp/test/mac/gyptest-type-envvars.py @@ -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. + +""" +Test that MACH_O_TYPE etc are set correctly. +""" + +import TestGyp + +import sys + +if sys.platform == 'darwin': + test = TestGyp.TestGyp(formats=['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/tools/gyp/test/mac/gyptest-xcode-env-order.py b/tools/gyp/test/mac/gyptest-xcode-env-order.py new file mode 100755 index 0000000..6459373 --- /dev/null +++ b/tools/gyp/test/mac/gyptest-xcode-env-order.py @@ -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 that dependent Xcode settings are processed correctly. +""" + +import TestGyp + +import sys + +if sys.platform == 'darwin': + test = TestGyp.TestGyp(formats=['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) + info_plist = test.built_file_path(INFO_PLIST_PATH, chdir=CHDIR) + test.must_exist(info_plist) + test.must_contain(info_plist, '>/Source/Project/Test') + test.must_contain(info_plist, '>DEP:/Source/Project/Test') + test.must_contain(info_plist, + '>com.apple.product-type.application:DEP:/Source/Project/Test') + + test.pass_test() diff --git a/tools/gyp/test/mac/infoplist-process/Info.plist b/tools/gyp/test/mac/infoplist-process/Info.plist new file mode 100644 index 0000000..cb65721 --- /dev/null +++ b/tools/gyp/test/mac/infoplist-process/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.google.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + ProcessedKey1 + PROCESSED_KEY1 + ProcessedKey2 + PROCESSED_KEY2 + + diff --git a/tools/gyp/test/mac/infoplist-process/main.c b/tools/gyp/test/mac/infoplist-process/main.c new file mode 100644 index 0000000..1bf4b2a --- /dev/null +++ b/tools/gyp/test/mac/infoplist-process/main.c @@ -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/tools/gyp/test/mac/infoplist-process/test1.gyp b/tools/gyp/test/mac/infoplist-process/test1.gyp new file mode 100644 index 0000000..bc625a9 --- /dev/null +++ b/tools/gyp/test/mac/infoplist-process/test1.gyp @@ -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/tools/gyp/test/mac/infoplist-process/test2.gyp b/tools/gyp/test/mac/infoplist-process/test2.gyp new file mode 100644 index 0000000..ecfbc9f --- /dev/null +++ b/tools/gyp/test/mac/infoplist-process/test2.gyp @@ -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/tools/gyp/test/mac/infoplist-process/test3.gyp b/tools/gyp/test/mac/infoplist-process/test3.gyp new file mode 100644 index 0000000..be8fe75 --- /dev/null +++ b/tools/gyp/test/mac/infoplist-process/test3.gyp @@ -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/tools/gyp/test/mac/loadable-module/Info.plist b/tools/gyp/test/mac/loadable-module/Info.plist new file mode 100644 index 0000000..f6607ae --- /dev/null +++ b/tools/gyp/test/mac/loadable-module/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.google.test_loadable_module + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BRPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + CFPlugInDynamicRegisterFunction + + CFPlugInDynamicRegistration + NO + + diff --git a/tools/gyp/test/mac/loadable-module/module.c b/tools/gyp/test/mac/loadable-module/module.c new file mode 100644 index 0000000..9584538 --- /dev/null +++ b/tools/gyp/test/mac/loadable-module/module.c @@ -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/tools/gyp/test/mac/loadable-module/test.gyp b/tools/gyp/test/mac/loadable-module/test.gyp new file mode 100644 index 0000000..3c8a530 --- /dev/null +++ b/tools/gyp/test/mac/loadable-module/test.gyp @@ -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/tools/gyp/test/mac/postbuild-fail/file.c b/tools/gyp/test/mac/postbuild-fail/file.c new file mode 100644 index 0000000..91695b1 --- /dev/null +++ b/tools/gyp/test/mac/postbuild-fail/file.c @@ -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/tools/gyp/test/mac/postbuild-fail/postbuild-fail.sh b/tools/gyp/test/mac/postbuild-fail/postbuild-fail.sh new file mode 100755 index 0000000..d4113d0 --- /dev/null +++ b/tools/gyp/test/mac/postbuild-fail/postbuild-fail.sh @@ -0,0 +1,6 @@ +#!/usr/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/tools/gyp/test/mac/postbuild-fail/test.gyp b/tools/gyp/test/mac/postbuild-fail/test.gyp new file mode 100644 index 0000000..e63283d --- /dev/null +++ b/tools/gyp/test/mac/postbuild-fail/test.gyp @@ -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/tools/gyp/test/mac/postbuild-fail/touch-dynamic.sh b/tools/gyp/test/mac/postbuild-fail/touch-dynamic.sh new file mode 100755 index 0000000..a388a64 --- /dev/null +++ b/tools/gyp/test/mac/postbuild-fail/touch-dynamic.sh @@ -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/tools/gyp/test/mac/postbuild-fail/touch-static.sh b/tools/gyp/test/mac/postbuild-fail/touch-static.sh new file mode 100755 index 0000000..97ecaa6 --- /dev/null +++ b/tools/gyp/test/mac/postbuild-fail/touch-static.sh @@ -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/tools/gyp/test/mac/postbuilds/file.c b/tools/gyp/test/mac/postbuilds/file.c new file mode 100644 index 0000000..653e71f --- /dev/null +++ b/tools/gyp/test/mac/postbuilds/file.c @@ -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/tools/gyp/test/mac/postbuilds/script/shared_library_postbuild.sh b/tools/gyp/test/mac/postbuilds/script/shared_library_postbuild.sh new file mode 100755 index 0000000..c623c8b --- /dev/null +++ b/tools/gyp/test/mac/postbuilds/script/shared_library_postbuild.sh @@ -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/tools/gyp/test/mac/postbuilds/script/static_library_postbuild.sh b/tools/gyp/test/mac/postbuilds/script/static_library_postbuild.sh new file mode 100755 index 0000000..2bf09b3 --- /dev/null +++ b/tools/gyp/test/mac/postbuilds/script/static_library_postbuild.sh @@ -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/tools/gyp/test/mac/postbuilds/subdirectory/nested_target.gyp b/tools/gyp/test/mac/postbuilds/subdirectory/nested_target.gyp new file mode 100644 index 0000000..f7ca9a6 --- /dev/null +++ b/tools/gyp/test/mac/postbuilds/subdirectory/nested_target.gyp @@ -0,0 +1,45 @@ +# 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.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.c', ], + 'postbuilds': [ + { + 'postbuild_name': 'Dynamic library postbuild', + 'variables': { + 'some_regex': 'a|b', + }, + 'action': [ + '../script/shared_library_postbuild.sh', + '<(some_regex)', + 'arg with spaces', + ], + }, + ], + }, + ], +} + diff --git a/tools/gyp/test/mac/postbuilds/test.gyp b/tools/gyp/test/mac/postbuilds/test.gyp new file mode 100644 index 0000000..a9a05cb --- /dev/null +++ b/tools/gyp/test/mac/postbuilds/test.gyp @@ -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. +{ + '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', + ], + }, + ], + }, + { + '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', + ], + }, + ], + }, + ], +} diff --git a/tools/gyp/test/mac/prefixheader/file.c b/tools/gyp/test/mac/prefixheader/file.c new file mode 100644 index 0000000..d0b39d1 --- /dev/null +++ b/tools/gyp/test/mac/prefixheader/file.c @@ -0,0 +1 @@ +MyInt f() { return 0; } diff --git a/tools/gyp/test/mac/prefixheader/header.h b/tools/gyp/test/mac/prefixheader/header.h new file mode 100644 index 0000000..0716e50 --- /dev/null +++ b/tools/gyp/test/mac/prefixheader/header.h @@ -0,0 +1 @@ +typedef int MyInt; diff --git a/tools/gyp/test/mac/prefixheader/test.gyp b/tools/gyp/test/mac/prefixheader/test.gyp new file mode 100644 index 0000000..ce318df --- /dev/null +++ b/tools/gyp/test/mac/prefixheader/test.gyp @@ -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': 'prefix_header', + 'type': 'static_library', + 'sources': [ 'file.c', ], + 'xcode_settings': { + 'GCC_PREFIX_HEADER': 'header.h', + }, + }, + { + 'target_name': 'precompiled_prefix_header', + 'type': 'shared_library', + 'mac_bundle': 1, + 'sources': [ 'file.c', ], + 'xcode_settings': { + 'GCC_PREFIX_HEADER': 'header.h', + 'GCC_PRECOMPILE_PREFIX_HEADER': 'YES', + }, + }, + ], +} diff --git a/tools/gyp/test/mac/strip/file.c b/tools/gyp/test/mac/strip/file.c new file mode 100644 index 0000000..421f040 --- /dev/null +++ b/tools/gyp/test/mac/strip/file.c @@ -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. + +static void the_static_function() {} + +void the_function() { + the_static_function(); +} diff --git a/tools/gyp/test/mac/strip/test.gyp b/tools/gyp/test/mac/strip/test.gyp new file mode 100644 index 0000000..4eb5447 --- /dev/null +++ b/tools/gyp/test/mac/strip/test.gyp @@ -0,0 +1,104 @@ +# 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', + }, + }, + ], +} diff --git a/tools/gyp/test/mac/type_envvars/file.c b/tools/gyp/test/mac/type_envvars/file.c new file mode 100644 index 0000000..9cddaf1 --- /dev/null +++ b/tools/gyp/test/mac/type_envvars/file.c @@ -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/tools/gyp/test/mac/type_envvars/test.gyp b/tools/gyp/test/mac/type_envvars/test.gyp new file mode 100644 index 0000000..4827957 --- /dev/null +++ b/tools/gyp/test/mac/type_envvars/test.gyp @@ -0,0 +1,89 @@ +# 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', ], + }, + ], + }, + + { + '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', ], + }, + ], + }, + ], +} diff --git a/tools/gyp/test/mac/type_envvars/test_bundle_executable.sh b/tools/gyp/test/mac/type_envvars/test_bundle_executable.sh new file mode 100755 index 0000000..4d3a084 --- /dev/null +++ b/tools/gyp/test/mac/type_envvars/test_bundle_executable.sh @@ -0,0 +1,9 @@ +#!/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 + +test $MACH_O_TYPE = mh_execute +test $PRODUCT_TYPE = com.apple.product-type.application diff --git a/tools/gyp/test/mac/type_envvars/test_bundle_loadable_module.sh b/tools/gyp/test/mac/type_envvars/test_bundle_loadable_module.sh new file mode 100755 index 0000000..c74c8e4 --- /dev/null +++ b/tools/gyp/test/mac/type_envvars/test_bundle_loadable_module.sh @@ -0,0 +1,9 @@ +#!/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 + +test $MACH_O_TYPE = mh_bundle +test $PRODUCT_TYPE = com.apple.product-type.bundle diff --git a/tools/gyp/test/mac/type_envvars/test_bundle_shared_library.sh b/tools/gyp/test/mac/type_envvars/test_bundle_shared_library.sh new file mode 100755 index 0000000..08ad4fb --- /dev/null +++ b/tools/gyp/test/mac/type_envvars/test_bundle_shared_library.sh @@ -0,0 +1,9 @@ +#!/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 + +test $MACH_O_TYPE = mh_dylib +test $PRODUCT_TYPE = com.apple.product-type.framework diff --git a/tools/gyp/test/mac/type_envvars/test_nonbundle_executable.sh b/tools/gyp/test/mac/type_envvars/test_nonbundle_executable.sh new file mode 100755 index 0000000..02d373d --- /dev/null +++ b/tools/gyp/test/mac/type_envvars/test_nonbundle_executable.sh @@ -0,0 +1,10 @@ +#!/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 +# 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 diff --git a/tools/gyp/test/mac/type_envvars/test_nonbundle_loadable_module.sh b/tools/gyp/test/mac/type_envvars/test_nonbundle_loadable_module.sh new file mode 100755 index 0000000..aa67df3 --- /dev/null +++ b/tools/gyp/test/mac/type_envvars/test_nonbundle_loadable_module.sh @@ -0,0 +1,9 @@ +#!/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 + +test $MACH_O_TYPE = mh_bundle +test $PRODUCT_TYPE = com.apple.product-type.library.dynamic diff --git a/tools/gyp/test/mac/type_envvars/test_nonbundle_shared_library.sh b/tools/gyp/test/mac/type_envvars/test_nonbundle_shared_library.sh new file mode 100755 index 0000000..937a50c --- /dev/null +++ b/tools/gyp/test/mac/type_envvars/test_nonbundle_shared_library.sh @@ -0,0 +1,9 @@ +#!/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 + +test $MACH_O_TYPE = mh_dylib +test $PRODUCT_TYPE = com.apple.product-type.library.dynamic diff --git a/tools/gyp/test/mac/type_envvars/test_nonbundle_static_library.sh b/tools/gyp/test/mac/type_envvars/test_nonbundle_static_library.sh new file mode 100755 index 0000000..892f0d9 --- /dev/null +++ b/tools/gyp/test/mac/type_envvars/test_nonbundle_static_library.sh @@ -0,0 +1,9 @@ +#!/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 + +test $MACH_O_TYPE = staticlib +test $PRODUCT_TYPE = com.apple.product-type.library.static diff --git a/tools/gyp/test/mac/xcode-env-order/Info.plist b/tools/gyp/test/mac/xcode-env-order/Info.plist new file mode 100644 index 0000000..55db30d --- /dev/null +++ b/tools/gyp/test/mac/xcode-env-order/Info.plist @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.google.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + ProcessedKey1 + ${DEPENDENT_KEY1} + ProcessedKey2 + ${DEPENDENT_KEY2} + ProcessedKey3 + ${DEPENDENT_KEY3} + + diff --git a/tools/gyp/test/mac/xcode-env-order/main.c b/tools/gyp/test/mac/xcode-env-order/main.c new file mode 100644 index 0000000..1bf4b2a --- /dev/null +++ b/tools/gyp/test/mac/xcode-env-order/main.c @@ -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/tools/gyp/test/mac/xcode-env-order/test.gyp b/tools/gyp/test/mac/xcode-env-order/test.gyp new file mode 100644 index 0000000..d9191aa --- /dev/null +++ b/tools/gyp/test/mac/xcode-env-order/test.gyp @@ -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': 'test_app', + 'product_name': 'Test', + 'type': 'executable', + 'mac_bundle': 1, + 'sources': [ + 'main.c', + ], + 'xcode_settings': { + 'INFOPLIST_FILE': 'Info.plist', + 'STRING_KEY': '/Source/Project', + 'DEPENDENT_KEY2': '$(STRING_KEY)/$(PRODUCT_NAME)', + 'DEPENDENT_KEY1': 'DEP:$(DEPENDENT_KEY2)', + 'DEPENDENT_KEY3': '$(PRODUCT_TYPE):$(DEPENDENT_KEY1)', + }, + }, + ], +} diff --git a/tools/gyp/test/make/dependencies.gyp b/tools/gyp/test/make/dependencies.gyp new file mode 100644 index 0000000..e2bee24 --- /dev/null +++ b/tools/gyp/test/make/dependencies.gyp @@ -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/tools/gyp/test/make/gyptest-dependencies.py b/tools/gyp/test/make/gyptest-dependencies.py new file mode 100755 index 0000000..76cfd0e --- /dev/null +++ b/tools/gyp/test/make/gyptest-dependencies.py @@ -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 .d files and all.deps are properly generated. +""" + +import os +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) + +all_deps_file = test.built_file_path(".deps/all.deps") +test.must_contain(all_deps_file, "main.h") +test.must_contain(all_deps_file, "cmd_") + +test.pass_test() diff --git a/tools/gyp/test/make/gyptest-noload.py b/tools/gyp/test/make/gyptest-noload.py new file mode 100755 index 0000000..1f51033 --- /dev/null +++ b/tools/gyp/test/make/gyptest-noload.py @@ -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/tools/gyp/test/make/main.cc b/tools/gyp/test/make/main.cc new file mode 100644 index 0000000..70ac6e4 --- /dev/null +++ b/tools/gyp/test/make/main.cc @@ -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 + +#include "main.h" + +int main(int argc, char *argv[]) { + printf("hello world\n"); + return 0; +} diff --git a/tools/gyp/test/make/main.h b/tools/gyp/test/make/main.h new file mode 100644 index 0000000..e69de29 diff --git a/tools/gyp/test/make/noload/all.gyp b/tools/gyp/test/make/noload/all.gyp new file mode 100644 index 0000000..1617a9e --- /dev/null +++ b/tools/gyp/test/make/noload/all.gyp @@ -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/tools/gyp/test/make/noload/lib/shared.c b/tools/gyp/test/make/noload/lib/shared.c new file mode 100644 index 0000000..51776c5 --- /dev/null +++ b/tools/gyp/test/make/noload/lib/shared.c @@ -0,0 +1,3 @@ +#include "shared.h" + +const char kSharedStr[] = "shared.c"; diff --git a/tools/gyp/test/make/noload/lib/shared.gyp b/tools/gyp/test/make/noload/lib/shared.gyp new file mode 100644 index 0000000..8a8841b --- /dev/null +++ b/tools/gyp/test/make/noload/lib/shared.gyp @@ -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/tools/gyp/test/make/noload/lib/shared.h b/tools/gyp/test/make/noload/lib/shared.h new file mode 100644 index 0000000..a21da75 --- /dev/null +++ b/tools/gyp/test/make/noload/lib/shared.h @@ -0,0 +1 @@ +extern const char kSharedStr[]; diff --git a/tools/gyp/test/make/noload/main.c b/tools/gyp/test/make/noload/main.c new file mode 100644 index 0000000..46d3c52 --- /dev/null +++ b/tools/gyp/test/make/noload/main.c @@ -0,0 +1,9 @@ +#include + +#include "lib/shared.h" + +int main(int argc, char *argv[]) +{ + printf("Hello from %s.\n", kSharedStr); + return 0; +} diff --git a/tools/gyp/test/module/gyptest-default.py b/tools/gyp/test/module/gyptest-default.py new file mode 100755 index 0000000..6b1c9b6 --- /dev/null +++ b/tools/gyp/test/module/gyptest-default.py @@ -0,0 +1,28 @@ +#!/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 loadable modules. The +default for all platforms should be to output the loadable modules to the same +path as the executable. +""" + +import TestGyp + +test = TestGyp.TestGyp() + +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/tools/gyp/test/module/src/lib1.c b/tools/gyp/test/module/src/lib1.c new file mode 100644 index 0000000..8de0e94 --- /dev/null +++ b/tools/gyp/test/module/src/lib1.c @@ -0,0 +1,10 @@ +#include + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void module_main(void) +{ + fprintf(stdout, "Hello from lib1.c\n"); + fflush(stdout); +} diff --git a/tools/gyp/test/module/src/lib2.c b/tools/gyp/test/module/src/lib2.c new file mode 100644 index 0000000..266396d --- /dev/null +++ b/tools/gyp/test/module/src/lib2.c @@ -0,0 +1,10 @@ +#include + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void module_main(void) +{ + fprintf(stdout, "Hello from lib2.c\n"); + fflush(stdout); +} diff --git a/tools/gyp/test/module/src/module.gyp b/tools/gyp/test/module/src/module.gyp new file mode 100644 index 0000000..bb43c30 --- /dev/null +++ b/tools/gyp/test/module/src/module.gyp @@ -0,0 +1,55 @@ +# 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"', { + 'defines': ['PLATFORM_MAC'], + }], + ['OS=="linux"', { + 'defines': ['PLATFORM_LINUX'], + # Support 64-bit shared libs (also works fine for 32-bit). + 'cflags': ['-fPIC'], + 'ldflags': ['-ldl'], + }], + ], + }, + 'targets': [ + { + 'target_name': 'program', + 'type': 'executable', + 'dependencies': [ + 'lib1', + 'lib2', + ], + 'sources': [ + 'program.c', + ], + }, + { + 'target_name': 'lib1', + 'type': 'loadable_module', + 'product_name': 'lib1', + 'product_prefix': '', + 'xcode_settings': {'OTHER_LDFLAGS': ['-dynamiclib'], 'MACH_O_TYPE': ''}, + 'sources': [ + 'lib1.c', + ], + }, + { + 'target_name': 'lib2', + 'product_name': 'lib2', + 'product_prefix': '', + 'type': 'loadable_module', + 'xcode_settings': {'OTHER_LDFLAGS': ['-dynamiclib'], 'MACH_O_TYPE': ''}, + 'sources': [ + 'lib2.c', + ], + }, + ], +} diff --git a/tools/gyp/test/module/src/program.c b/tools/gyp/test/module/src/program.c new file mode 100644 index 0000000..b2f3320 --- /dev/null +++ b/tools/gyp/test/module/src/program.c @@ -0,0 +1,111 @@ +#include +#include + +#if defined(PLATFORM_WIN) +#include +#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) +#include +#include +#include +#include +#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; + } +#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; + } +#endif + + CallModule("lib1"); + CallModule("lib2"); + return 0; +} diff --git a/tools/gyp/test/msvs/express/base/base.gyp b/tools/gyp/test/msvs/express/base/base.gyp new file mode 100644 index 0000000..b7c9fc6 --- /dev/null +++ b/tools/gyp/test/msvs/express/base/base.gyp @@ -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/tools/gyp/test/msvs/express/express.gyp b/tools/gyp/test/msvs/express/express.gyp new file mode 100644 index 0000000..917abe2 --- /dev/null +++ b/tools/gyp/test/msvs/express/express.gyp @@ -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/tools/gyp/test/msvs/express/gyptest-express.py b/tools/gyp/test/msvs/express/gyptest-express.py new file mode 100755 index 0000000..54c06f6 --- /dev/null +++ b/tools/gyp/test/msvs/express/gyptest-express.py @@ -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/tools/gyp/test/msvs/precompiled/gyptest-all.py b/tools/gyp/test/msvs/precompiled/gyptest-all.py new file mode 100755 index 0000000..327ca6d --- /dev/null +++ b/tools/gyp/test/msvs/precompiled/gyptest-all.py @@ -0,0 +1,23 @@ +#!/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 + +test = TestGyp.TestGyp(formats=['msvs'], 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/tools/gyp/test/msvs/precompiled/hello.c b/tools/gyp/test/msvs/precompiled/hello.c new file mode 100644 index 0000000..d1abbb9 --- /dev/null +++ b/tools/gyp/test/msvs/precompiled/hello.c @@ -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(int argc, char *argv[]) { + printf("Hello, world!\n"); + hello2(); + return 0; +} diff --git a/tools/gyp/test/msvs/precompiled/hello.gyp b/tools/gyp/test/msvs/precompiled/hello.gyp new file mode 100644 index 0000000..b9533ef --- /dev/null +++ b/tools/gyp/test/msvs/precompiled/hello.gyp @@ -0,0 +1,19 @@ +# 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': 'hello', + 'type': 'executable', + 'sources': [ + 'hello.c', + 'hello2.c', + 'precomp.c', + ], + 'msvs_precompiled_header': 'stdio.h', + 'msvs_precompiled_source': 'precomp.c', + }, + ], +} diff --git a/tools/gyp/test/msvs/precompiled/hello2.c b/tools/gyp/test/msvs/precompiled/hello2.c new file mode 100644 index 0000000..d6d5311 --- /dev/null +++ b/tools/gyp/test/msvs/precompiled/hello2.c @@ -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 +#include + +int hello2() { + printf("Hello, two!\n"); + return 0; +} diff --git a/tools/gyp/test/msvs/precompiled/precomp.c b/tools/gyp/test/msvs/precompiled/precomp.c new file mode 100644 index 0000000..517c61a --- /dev/null +++ b/tools/gyp/test/msvs/precompiled/precomp.c @@ -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 +#include diff --git a/tools/gyp/test/multiple-targets/gyptest-all.py b/tools/gyp/test/multiple-targets/gyptest-all.py new file mode 100755 index 0000000..9f157c4 --- /dev/null +++ b/tools/gyp/test/multiple-targets/gyptest-all.py @@ -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. + +""" +""" + +import TestGyp + +test = TestGyp.TestGyp() + +test.run_gyp('multiple.gyp', chdir='src') + +test.relocate('src', 'relocate/src') + +# TODO(sgk): remove stderr=None when the --generator-output= support +# gets rid of the scons warning +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/tools/gyp/test/multiple-targets/gyptest-default.py b/tools/gyp/test/multiple-targets/gyptest-default.py new file mode 100755 index 0000000..8d5072d --- /dev/null +++ b/tools/gyp/test/multiple-targets/gyptest-default.py @@ -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. + +""" +""" + +import TestGyp + +test = TestGyp.TestGyp() + +test.run_gyp('multiple.gyp', chdir='src') + +test.relocate('src', 'relocate/src') + +# TODO(sgk): remove stderr=None when the --generator-output= support +# gets rid of the scons warning +test.build('multiple.gyp', 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/tools/gyp/test/multiple-targets/src/common.c b/tools/gyp/test/multiple-targets/src/common.c new file mode 100644 index 0000000..f1df7c1 --- /dev/null +++ b/tools/gyp/test/multiple-targets/src/common.c @@ -0,0 +1,7 @@ +#include + +void common(void) +{ + printf("hello from common.c\n"); + return; +} diff --git a/tools/gyp/test/multiple-targets/src/multiple.gyp b/tools/gyp/test/multiple-targets/src/multiple.gyp new file mode 100644 index 0000000..3db4ea3 --- /dev/null +++ b/tools/gyp/test/multiple-targets/src/multiple.gyp @@ -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/tools/gyp/test/multiple-targets/src/prog1.c b/tools/gyp/test/multiple-targets/src/prog1.c new file mode 100644 index 0000000..d55f8af --- /dev/null +++ b/tools/gyp/test/multiple-targets/src/prog1.c @@ -0,0 +1,10 @@ +#include + +extern void common(void); + +int main(int argc, char *argv[]) +{ + printf("hello from prog1.c\n"); + common(); + return 0; +} diff --git a/tools/gyp/test/multiple-targets/src/prog2.c b/tools/gyp/test/multiple-targets/src/prog2.c new file mode 100644 index 0000000..760590e --- /dev/null +++ b/tools/gyp/test/multiple-targets/src/prog2.c @@ -0,0 +1,10 @@ +#include + +extern void common(void); + +int main(int argc, char *argv[]) +{ + printf("hello from prog2.c\n"); + common(); + return 0; +} diff --git a/tools/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py b/tools/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py new file mode 100755 index 0000000..f84af24 --- /dev/null +++ b/tools/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py @@ -0,0 +1,45 @@ +#!/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 building an object file correctly depends on running actions in +dependent targets, but not the targets themselves. +""" + +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) + +test.build('action_dependencies.gyp', 'obj/b.b.o', 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('obj/b.b.o', chdir=chdir) + +test.build('action_dependencies.gyp', 'obj/c.c.o', 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('obj/c.c.o', chdir=chdir) + + +test.pass_test() diff --git a/tools/gyp/test/ninja/action_dependencies/src/a.c b/tools/gyp/test/ninja/action_dependencies/src/a.c new file mode 100644 index 0000000..4d7af9b --- /dev/null +++ b/tools/gyp/test/ninja/action_dependencies/src/a.c @@ -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/tools/gyp/test/ninja/action_dependencies/src/a.h b/tools/gyp/test/ninja/action_dependencies/src/a.h new file mode 100644 index 0000000..335db56 --- /dev/null +++ b/tools/gyp/test/ninja/action_dependencies/src/a.h @@ -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/tools/gyp/test/ninja/action_dependencies/src/action_dependencies.gyp b/tools/gyp/test/ninja/action_dependencies/src/action_dependencies.gyp new file mode 100644 index 0000000..5baa7a7 --- /dev/null +++ b/tools/gyp/test/ninja/action_dependencies/src/action_dependencies.gyp @@ -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/tools/gyp/test/ninja/action_dependencies/src/b.c b/tools/gyp/test/ninja/action_dependencies/src/b.c new file mode 100644 index 0000000..7d70d01 --- /dev/null +++ b/tools/gyp/test/ninja/action_dependencies/src/b.c @@ -0,0 +1,17 @@ +/* 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 + +#include "b.h" + +int main(int argc, char** argv) { + if (argc < 2) + return 1; + FILE* f = fopen(argv[1], "wt"); + fprintf(f, "#define VALUE %d\n", funcA()); + fclose(f); + return 0; +} diff --git a/tools/gyp/test/ninja/action_dependencies/src/b.h b/tools/gyp/test/ninja/action_dependencies/src/b.h new file mode 100644 index 0000000..91362cd --- /dev/null +++ b/tools/gyp/test/ninja/action_dependencies/src/b.h @@ -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/tools/gyp/test/ninja/action_dependencies/src/c.c b/tools/gyp/test/ninja/action_dependencies/src/c.c new file mode 100644 index 0000000..b412087 --- /dev/null +++ b/tools/gyp/test/ninja/action_dependencies/src/c.c @@ -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/tools/gyp/test/ninja/action_dependencies/src/c.h b/tools/gyp/test/ninja/action_dependencies/src/c.h new file mode 100644 index 0000000..c81a45b --- /dev/null +++ b/tools/gyp/test/ninja/action_dependencies/src/c.h @@ -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/tools/gyp/test/ninja/action_dependencies/src/emit.py b/tools/gyp/test/ninja/action_dependencies/src/emit.py new file mode 100755 index 0000000..2df74b7 --- /dev/null +++ b/tools/gyp/test/ninja/action_dependencies/src/emit.py @@ -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/tools/gyp/test/no-output/gyptest-no-output.py b/tools/gyp/test/no-output/gyptest-no-output.py new file mode 100755 index 0000000..bf9a0b5 --- /dev/null +++ b/tools/gyp/test/no-output/gyptest-no-output.py @@ -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/tools/gyp/test/no-output/src/nooutput.gyp b/tools/gyp/test/no-output/src/nooutput.gyp new file mode 100644 index 0000000..c40124e --- /dev/null +++ b/tools/gyp/test/no-output/src/nooutput.gyp @@ -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/tools/gyp/test/product/gyptest-product.py b/tools/gyp/test/product/gyptest-product.py new file mode 100755 index 0000000..e9790f3 --- /dev/null +++ b/tools/gyp/test/product/gyptest-product.py @@ -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 simplest-possible build of a "Hello, world!" program +using the default build target. +""" + +import TestGyp + +test = TestGyp.TestGyp() + +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/tools/gyp/test/product/hello.c b/tools/gyp/test/product/hello.c new file mode 100644 index 0000000..94798f3 --- /dev/null +++ b/tools/gyp/test/product/hello.c @@ -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 + +int func1(void) { + return 42; +} + +int main(int argc, char *argv[]) { + printf("Hello, world!\n"); + printf("%d\n", func1()); + return 0; +} diff --git a/tools/gyp/test/product/product.gyp b/tools/gyp/test/product/product.gyp new file mode 100644 index 0000000..c25eaaa --- /dev/null +++ b/tools/gyp/test/product/product.gyp @@ -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/tools/gyp/test/rules-dirname/gyptest-dirname.py b/tools/gyp/test/rules-dirname/gyptest-dirname.py new file mode 100755 index 0000000..6e684a4 --- /dev/null +++ b/tools/gyp/test/rules-dirname/gyptest-dirname.py @@ -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 simple rules when using an explicit build target of 'all'. +""" + +import TestGyp + +test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode']) + +test.run_gyp('actions.gyp', chdir='src') + +test.relocate('src', 'relocate/src') + +test.build('actions.gyp', chdir='relocate/src') + +expect = """\ +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.must_exist('relocate/src/subdir/foo/bar/baz.printed') + test.must_exist('relocate/src/subdir/a/b/c.printed') +else: + test.must_match('relocate/src/subdir/foo/bar/baz.printed', 'foo/bar') + test.must_match('relocate/src/subdir/a/b/c.printed', 'a/b') + +test.pass_test() diff --git a/tools/gyp/test/rules-dirname/src/actions.gyp b/tools/gyp/test/rules-dirname/src/actions.gyp new file mode 100644 index 0000000..c5693c6 --- /dev/null +++ b/tools/gyp/test/rules-dirname/src/actions.gyp @@ -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/tools/gyp/test/rules-dirname/src/copy-file.py b/tools/gyp/test/rules-dirname/src/copy-file.py new file mode 100755 index 0000000..9774ccc --- /dev/null +++ b/tools/gyp/test/rules-dirname/src/copy-file.py @@ -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/tools/gyp/test/rules-dirname/src/subdir/a/b/c.gencc b/tools/gyp/test/rules-dirname/src/subdir/a/b/c.gencc new file mode 100644 index 0000000..a4c8eea --- /dev/null +++ b/tools/gyp/test/rules-dirname/src/subdir/a/b/c.gencc @@ -0,0 +1,11 @@ +// -*- mode: c++ -*- +#include + +using std::cout; +using std::endl; + +namespace gen { + void c() { + cout << "hi c" << endl; + } +} diff --git a/tools/gyp/test/rules-dirname/src/subdir/a/b/c.printvars b/tools/gyp/test/rules-dirname/src/subdir/a/b/c.printvars new file mode 100644 index 0000000..cc4561d --- /dev/null +++ b/tools/gyp/test/rules-dirname/src/subdir/a/b/c.printvars @@ -0,0 +1 @@ +# Empty file for testing build rules diff --git a/tools/gyp/test/rules-dirname/src/subdir/foo/bar/baz.gencc b/tools/gyp/test/rules-dirname/src/subdir/foo/bar/baz.gencc new file mode 100644 index 0000000..ff01c2e --- /dev/null +++ b/tools/gyp/test/rules-dirname/src/subdir/foo/bar/baz.gencc @@ -0,0 +1,11 @@ +// -*- mode: c++ -*- +#include + +using std::cout; +using std::endl; + +namespace gen { + void baz() { + cout << "hello baz" << endl; + } +} diff --git a/tools/gyp/test/rules-dirname/src/subdir/foo/bar/baz.printvars b/tools/gyp/test/rules-dirname/src/subdir/foo/bar/baz.printvars new file mode 100644 index 0000000..cc4561d --- /dev/null +++ b/tools/gyp/test/rules-dirname/src/subdir/foo/bar/baz.printvars @@ -0,0 +1 @@ +# Empty file for testing build rules diff --git a/tools/gyp/test/rules-dirname/src/subdir/input-rule-dirname.gyp b/tools/gyp/test/rules-dirname/src/subdir/input-rule-dirname.gyp new file mode 100644 index 0000000..96e32ef --- /dev/null +++ b/tools/gyp/test/rules-dirname/src/subdir/input-rule-dirname.gyp @@ -0,0 +1,92 @@ +# 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_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).printed', + ], + 'action': [ + 'python', '<@(_inputs)', '<(RULE_INPUT_DIRNAME)', '<@(_outputs)', + ], + }, + ], + }, + { + 'target_name': 'gencc_int_output', + 'type': 'executable', + 'msvs_cygwin_shell': 0, + 'msvs_cygwin_dirs': ['../../../../../../<(DEPTH)/third_party/cygwin'], + 'sources': [ + 'foo/bar/baz.gencc', + 'a/b/c.gencc', + 'main.cc', + ], + 'conditions': [ + ['OS=="win"', { + '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, + }, + ], + }, + ], + '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/tools/gyp/test/rules-dirname/src/subdir/main.cc b/tools/gyp/test/rules-dirname/src/subdir/main.cc new file mode 100644 index 0000000..bacc568 --- /dev/null +++ b/tools/gyp/test/rules-dirname/src/subdir/main.cc @@ -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. +namespace gen { + extern void c(); + extern void baz(); +} + +int main() { + gen::c(); + gen::baz(); +} diff --git a/tools/gyp/test/rules-dirname/src/subdir/printvars.py b/tools/gyp/test/rules-dirname/src/subdir/printvars.py new file mode 100755 index 0000000..ef3d92e --- /dev/null +++ b/tools/gyp/test/rules-dirname/src/subdir/printvars.py @@ -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/tools/gyp/test/rules-rebuild/gyptest-all.py b/tools/gyp/test/rules-rebuild/gyptest-all.py new file mode 100755 index 0000000..aaaa2a6 --- /dev/null +++ b/tools/gyp/test/rules-rebuild/gyptest-all.py @@ -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/tools/gyp/test/rules-rebuild/gyptest-default.py b/tools/gyp/test/rules-rebuild/gyptest-default.py new file mode 100755 index 0000000..89694ef --- /dev/null +++ b/tools/gyp/test/rules-rebuild/gyptest-default.py @@ -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_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.pass_test() diff --git a/tools/gyp/test/rules-rebuild/src/main.c b/tools/gyp/test/rules-rebuild/src/main.c new file mode 100644 index 0000000..bdc5ec8 --- /dev/null +++ b/tools/gyp/test/rules-rebuild/src/main.c @@ -0,0 +1,12 @@ +#include + +extern void prog1(void); +extern void prog2(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from main.c\n"); + prog1(); + prog2(); + return 0; +} diff --git a/tools/gyp/test/rules-rebuild/src/make-sources.py b/tools/gyp/test/rules-rebuild/src/make-sources.py new file mode 100755 index 0000000..7ec0227 --- /dev/null +++ b/tools/gyp/test/rules-rebuild/src/make-sources.py @@ -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/tools/gyp/test/rules-rebuild/src/prog1.in b/tools/gyp/test/rules-rebuild/src/prog1.in new file mode 100644 index 0000000..191b00e --- /dev/null +++ b/tools/gyp/test/rules-rebuild/src/prog1.in @@ -0,0 +1,7 @@ +#include +#include "prog1.h" + +void prog1(void) +{ + printf("Hello from %s!\n", NAME); +} diff --git a/tools/gyp/test/rules-rebuild/src/prog2.in b/tools/gyp/test/rules-rebuild/src/prog2.in new file mode 100644 index 0000000..7bfac51 --- /dev/null +++ b/tools/gyp/test/rules-rebuild/src/prog2.in @@ -0,0 +1,7 @@ +#include +#include "prog2.h" + +void prog2(void) +{ + printf("Hello from %s!\n", NAME); +} diff --git a/tools/gyp/test/rules-rebuild/src/same_target.gyp b/tools/gyp/test/rules-rebuild/src/same_target.gyp new file mode 100644 index 0000000..22ba560 --- /dev/null +++ b/tools/gyp/test/rules-rebuild/src/same_target.gyp @@ -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/tools/gyp/test/rules-variables/gyptest-rules-variables.py b/tools/gyp/test/rules-variables/gyptest-rules-variables.py new file mode 100755 index 0000000..06ee5ca --- /dev/null +++ b/tools/gyp/test/rules-variables/gyptest-rules-variables.py @@ -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/tools/gyp/test/rules-variables/src/input_ext.c b/tools/gyp/test/rules-variables/src/input_ext.c new file mode 100644 index 0000000..f41e73e --- /dev/null +++ b/tools/gyp/test/rules-variables/src/input_ext.c @@ -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 + +void input_ext() { + printf("input_ext\n"); +} diff --git a/tools/gyp/test/rules-variables/src/input_name/test.c b/tools/gyp/test/rules-variables/src/input_name/test.c new file mode 100644 index 0000000..e28b74d --- /dev/null +++ b/tools/gyp/test/rules-variables/src/input_name/test.c @@ -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 + +void input_name() { + printf("input_name\n"); +} diff --git a/tools/gyp/test/rules-variables/src/input_path/subdir/test.c b/tools/gyp/test/rules-variables/src/input_path/subdir/test.c new file mode 100644 index 0000000..403dbbd --- /dev/null +++ b/tools/gyp/test/rules-variables/src/input_path/subdir/test.c @@ -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 + +void input_path() { + printf("input_path\n"); +} diff --git a/tools/gyp/test/rules-variables/src/subdir/input_dirname.c b/tools/gyp/test/rules-variables/src/subdir/input_dirname.c new file mode 100644 index 0000000..40cecd8 --- /dev/null +++ b/tools/gyp/test/rules-variables/src/subdir/input_dirname.c @@ -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 + +void input_dirname() { + printf("input_dirname\n"); +} diff --git a/tools/gyp/test/rules-variables/src/subdir/test.c b/tools/gyp/test/rules-variables/src/subdir/test.c new file mode 100644 index 0000000..6c0280b --- /dev/null +++ b/tools/gyp/test/rules-variables/src/subdir/test.c @@ -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/tools/gyp/test/rules-variables/src/test.input_root.c b/tools/gyp/test/rules-variables/src/test.input_root.c new file mode 100644 index 0000000..33a7740 --- /dev/null +++ b/tools/gyp/test/rules-variables/src/test.input_root.c @@ -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 + +void input_root() { + printf("input_root\n"); +} diff --git a/tools/gyp/test/rules-variables/src/variables.gyp b/tools/gyp/test/rules-variables/src/variables.gyp new file mode 100644 index 0000000..e40f3a8 --- /dev/null +++ b/tools/gyp/test/rules-variables/src/variables.gyp @@ -0,0 +1,30 @@ +# 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': '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/tools/gyp/test/rules/gyptest-all.py b/tools/gyp/test/rules/gyptest-all.py new file mode 100755 index 0000000..63c3a10 --- /dev/null +++ b/tools/gyp/test/rules/gyptest-all.py @@ -0,0 +1,66 @@ +#!/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', 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/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/tools/gyp/test/rules/gyptest-default.py b/tools/gyp/test/rules/gyptest-default.py new file mode 100755 index 0000000..117c53d --- /dev/null +++ b/tools/gyp/test/rules/gyptest-default.py @@ -0,0 +1,55 @@ +#!/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/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/tools/gyp/test/rules/gyptest-input-root.py b/tools/gyp/test/rules/gyptest-input-root.py new file mode 100755 index 0000000..92bade6 --- /dev/null +++ b/tools/gyp/test/rules/gyptest-input-root.py @@ -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/tools/gyp/test/rules/src/actions.gyp b/tools/gyp/test/rules/src/actions.gyp new file mode 100644 index 0000000..23e00ce --- /dev/null +++ b/tools/gyp/test/rules/src/actions.gyp @@ -0,0 +1,21 @@ +# 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/never_used.gyp:*', + 'subdir2/no_inputs.gyp:*', + 'subdir2/none.gyp:*', + 'subdir3/executable2.gyp:*', + 'subdir4/build-asm.gyp:*', + 'external/external.gyp:*', + ], + }, + ], +} diff --git a/tools/gyp/test/rules/src/copy-file.py b/tools/gyp/test/rules/src/copy-file.py new file mode 100755 index 0000000..5a5feae --- /dev/null +++ b/tools/gyp/test/rules/src/copy-file.py @@ -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/tools/gyp/test/rules/src/external/external.gyp b/tools/gyp/test/rules/src/external/external.gyp new file mode 100644 index 0000000..004ec63 --- /dev/null +++ b/tools/gyp/test/rules/src/external/external.gyp @@ -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/tools/gyp/test/rules/src/external/file1.in b/tools/gyp/test/rules/src/external/file1.in new file mode 100644 index 0000000..86ac3ad --- /dev/null +++ b/tools/gyp/test/rules/src/external/file1.in @@ -0,0 +1 @@ +Hello from file1.in diff --git a/tools/gyp/test/rules/src/external/file2.in b/tools/gyp/test/rules/src/external/file2.in new file mode 100644 index 0000000..bf83d8e --- /dev/null +++ b/tools/gyp/test/rules/src/external/file2.in @@ -0,0 +1 @@ +Hello from file2.in diff --git a/tools/gyp/test/rules/src/input-root.gyp b/tools/gyp/test/rules/src/input-root.gyp new file mode 100644 index 0000000..b6600e7 --- /dev/null +++ b/tools/gyp/test/rules/src/input-root.gyp @@ -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/tools/gyp/test/rules/src/rule.py b/tools/gyp/test/rules/src/rule.py new file mode 100755 index 0000000..8a1f36d --- /dev/null +++ b/tools/gyp/test/rules/src/rule.py @@ -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 + +int main() { + puts("Hello %s"); + return 0; +} +""" % sys.argv[1]) +f.close() diff --git a/tools/gyp/test/rules/src/somefile.ext b/tools/gyp/test/rules/src/somefile.ext new file mode 100644 index 0000000..e69de29 diff --git a/tools/gyp/test/rules/src/subdir1/executable.gyp b/tools/gyp/test/rules/src/subdir1/executable.gyp new file mode 100644 index 0000000..3028577 --- /dev/null +++ b/tools/gyp/test/rules/src/subdir1/executable.gyp @@ -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 SCons and 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/tools/gyp/test/rules/src/subdir1/function1.in b/tools/gyp/test/rules/src/subdir1/function1.in new file mode 100644 index 0000000..60ff289 --- /dev/null +++ b/tools/gyp/test/rules/src/subdir1/function1.in @@ -0,0 +1,6 @@ +#include + +void function1(void) +{ + printf("Hello from function1.in\n"); +} diff --git a/tools/gyp/test/rules/src/subdir1/function2.in b/tools/gyp/test/rules/src/subdir1/function2.in new file mode 100644 index 0000000..0fcfc03 --- /dev/null +++ b/tools/gyp/test/rules/src/subdir1/function2.in @@ -0,0 +1,6 @@ +#include + +void function2(void) +{ + printf("Hello from function2.in\n"); +} diff --git a/tools/gyp/test/rules/src/subdir1/program.c b/tools/gyp/test/rules/src/subdir1/program.c new file mode 100644 index 0000000..258d7f9 --- /dev/null +++ b/tools/gyp/test/rules/src/subdir1/program.c @@ -0,0 +1,12 @@ +#include + +extern void function1(void); +extern void function2(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from program.c\n"); + function1(); + function2(); + return 0; +} diff --git a/tools/gyp/test/rules/src/subdir2/file1.in b/tools/gyp/test/rules/src/subdir2/file1.in new file mode 100644 index 0000000..86ac3ad --- /dev/null +++ b/tools/gyp/test/rules/src/subdir2/file1.in @@ -0,0 +1 @@ +Hello from file1.in diff --git a/tools/gyp/test/rules/src/subdir2/file2.in b/tools/gyp/test/rules/src/subdir2/file2.in new file mode 100644 index 0000000..bf83d8e --- /dev/null +++ b/tools/gyp/test/rules/src/subdir2/file2.in @@ -0,0 +1 @@ +Hello from file2.in diff --git a/tools/gyp/test/rules/src/subdir2/never_used.gyp b/tools/gyp/test/rules/src/subdir2/never_used.gyp new file mode 100644 index 0000000..17f6f55 --- /dev/null +++ b/tools/gyp/test/rules/src/subdir2/never_used.gyp @@ -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/tools/gyp/test/rules/src/subdir2/no_inputs.gyp b/tools/gyp/test/rules/src/subdir2/no_inputs.gyp new file mode 100644 index 0000000..e61a1a3 --- /dev/null +++ b/tools/gyp/test/rules/src/subdir2/no_inputs.gyp @@ -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/tools/gyp/test/rules/src/subdir2/none.gyp b/tools/gyp/test/rules/src/subdir2/none.gyp new file mode 100644 index 0000000..38bcdab --- /dev/null +++ b/tools/gyp/test/rules/src/subdir2/none.gyp @@ -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/tools/gyp/test/rules/src/subdir3/executable2.gyp b/tools/gyp/test/rules/src/subdir3/executable2.gyp new file mode 100644 index 0000000..a2a528f --- /dev/null +++ b/tools/gyp/test/rules/src/subdir3/executable2.gyp @@ -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/tools/gyp/test/rules/src/subdir3/function3.in b/tools/gyp/test/rules/src/subdir3/function3.in new file mode 100644 index 0000000..99f46ab --- /dev/null +++ b/tools/gyp/test/rules/src/subdir3/function3.in @@ -0,0 +1,6 @@ +#include + +extern "C" void function3(void) +{ + printf("Hello from function3.in\n"); +} diff --git a/tools/gyp/test/rules/src/subdir3/program.c b/tools/gyp/test/rules/src/subdir3/program.c new file mode 100644 index 0000000..94f6c50 --- /dev/null +++ b/tools/gyp/test/rules/src/subdir3/program.c @@ -0,0 +1,10 @@ +#include + +extern void function3(void); + +int main(int argc, char *argv[]) +{ + printf("Hello from program.c\n"); + function3(); + return 0; +} diff --git a/tools/gyp/test/rules/src/subdir4/asm-function.asm b/tools/gyp/test/rules/src/subdir4/asm-function.asm new file mode 100644 index 0000000..ed47cad --- /dev/null +++ b/tools/gyp/test/rules/src/subdir4/asm-function.asm @@ -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/tools/gyp/test/rules/src/subdir4/build-asm.gyp b/tools/gyp/test/rules/src/subdir4/build-asm.gyp new file mode 100644 index 0000000..be4a612 --- /dev/null +++ b/tools/gyp/test/rules/src/subdir4/build-asm.gyp @@ -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.asm', + 'program.c', + ], + 'conditions': [ + ['OS=="linux" or OS=="mac"', { + 'rules': [ + { + 'rule_name': 'convert_asm', + 'extension': 'asm', + '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/tools/gyp/test/rules/src/subdir4/program.c b/tools/gyp/test/rules/src/subdir4/program.c new file mode 100644 index 0000000..4247590 --- /dev/null +++ b/tools/gyp/test/rules/src/subdir4/program.c @@ -0,0 +1,19 @@ +#include + +// 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(int argc, char *argv[]) +{ + fprintf(stdout, "Hello from program.c\n"); + fflush(stdout); + fprintf(stdout, "Got %d.\n", asm_function()); + fflush(stdout); + return 0; +} diff --git a/tools/gyp/test/same-gyp-name/gyptest-all.py b/tools/gyp/test/same-gyp-name/gyptest-all.py new file mode 100755 index 0000000..7645688 --- /dev/null +++ b/tools/gyp/test/same-gyp-name/gyptest-all.py @@ -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 that depends on 2 gyp files with the same name. +""" + +import TestGyp + +# This causes a problem on XCode (duplicate ID). +# See http://code.google.com/p/gyp/issues/detail?id=114 +test = TestGyp.TestGyp(formats=['msvs', 'scons', 'make']) + +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 +""" + +test.run_built_executable('program1', chdir='relocate/src', stdout=expect1) +test.run_built_executable('program2', chdir='relocate/src', stdout=expect2) + +test.pass_test() diff --git a/tools/gyp/test/same-gyp-name/gyptest-default.py b/tools/gyp/test/same-gyp-name/gyptest-default.py new file mode 100755 index 0000000..c1031f8 --- /dev/null +++ b/tools/gyp/test/same-gyp-name/gyptest-default.py @@ -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 that depends on 2 gyp files with the same name. +""" + +import TestGyp + +# This causes a problem on XCode (duplicate ID). +# See http://code.google.com/p/gyp/issues/detail?id=114 +test = TestGyp.TestGyp(formats=['msvs', 'scons', 'make']) + +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 +""" + +test.run_built_executable('program1', chdir='relocate/src', stdout=expect1) +test.run_built_executable('program2', chdir='relocate/src', stdout=expect2) + +test.pass_test() diff --git a/tools/gyp/test/same-gyp-name/src/all.gyp b/tools/gyp/test/same-gyp-name/src/all.gyp new file mode 100644 index 0000000..229f02e --- /dev/null +++ b/tools/gyp/test/same-gyp-name/src/all.gyp @@ -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/tools/gyp/test/same-gyp-name/src/subdir1/executable.gyp b/tools/gyp/test/same-gyp-name/src/subdir1/executable.gyp new file mode 100644 index 0000000..82483b4 --- /dev/null +++ b/tools/gyp/test/same-gyp-name/src/subdir1/executable.gyp @@ -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/tools/gyp/test/same-gyp-name/src/subdir1/main1.cc b/tools/gyp/test/same-gyp-name/src/subdir1/main1.cc new file mode 100644 index 0000000..3645558 --- /dev/null +++ b/tools/gyp/test/same-gyp-name/src/subdir1/main1.cc @@ -0,0 +1,6 @@ +#include + +int main() { + printf("Hello from main1.cc\n"); + return 0; +} diff --git a/tools/gyp/test/same-gyp-name/src/subdir2/executable.gyp b/tools/gyp/test/same-gyp-name/src/subdir2/executable.gyp new file mode 100644 index 0000000..e353701 --- /dev/null +++ b/tools/gyp/test/same-gyp-name/src/subdir2/executable.gyp @@ -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/tools/gyp/test/same-gyp-name/src/subdir2/main2.cc b/tools/gyp/test/same-gyp-name/src/subdir2/main2.cc new file mode 100644 index 0000000..0c724de --- /dev/null +++ b/tools/gyp/test/same-gyp-name/src/subdir2/main2.cc @@ -0,0 +1,6 @@ +#include + +int main() { + printf("Hello from main2.cc\n"); + return 0; +} diff --git a/tools/gyp/test/same-name/gyptest-all.py b/tools/gyp/test/same-name/gyptest-all.py new file mode 100755 index 0000000..4c21502 --- /dev/null +++ b/tools/gyp/test/same-name/gyptest-all.py @@ -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/tools/gyp/test/same-name/gyptest-default.py b/tools/gyp/test/same-name/gyptest-default.py new file mode 100755 index 0000000..98757c2 --- /dev/null +++ b/tools/gyp/test/same-name/gyptest-default.py @@ -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/tools/gyp/test/same-name/src/all.gyp b/tools/gyp/test/same-name/src/all.gyp new file mode 100644 index 0000000..44e1049 --- /dev/null +++ b/tools/gyp/test/same-name/src/all.gyp @@ -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': 'prog1', + 'type': 'executable', + 'defines': [ + 'PROG="prog1"', + ], + 'sources': [ + 'prog1.c', + 'func.c', + # Uncomment to test same-named files in different directories, + # which Visual Studio doesn't support. + #'subdir1/func.c', + #'subdir2/func.c', + ], + }, + { + 'target_name': 'prog2', + 'type': 'executable', + 'defines': [ + 'PROG="prog2"', + ], + 'sources': [ + 'prog2.c', + 'func.c', + # Uncomment to test same-named files in different directories, + # which Visual Studio doesn't support. + #'subdir1/func.c', + #'subdir2/func.c', + ], + }, + ], +} diff --git a/tools/gyp/test/same-name/src/func.c b/tools/gyp/test/same-name/src/func.c new file mode 100644 index 0000000..e069c69 --- /dev/null +++ b/tools/gyp/test/same-name/src/func.c @@ -0,0 +1,6 @@ +#include + +void func(void) +{ + printf("Hello %s from func.c\n", PROG); +} diff --git a/tools/gyp/test/same-name/src/prog1.c b/tools/gyp/test/same-name/src/prog1.c new file mode 100644 index 0000000..c8940fe --- /dev/null +++ b/tools/gyp/test/same-name/src/prog1.c @@ -0,0 +1,16 @@ +#include + +extern void func(void); + +int main(int argc, char *argv[]) +{ + 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/tools/gyp/test/same-name/src/prog2.c b/tools/gyp/test/same-name/src/prog2.c new file mode 100644 index 0000000..e6605c2 --- /dev/null +++ b/tools/gyp/test/same-name/src/prog2.c @@ -0,0 +1,16 @@ +#include + +extern void func(void); + +int main(int argc, char *argv[]) +{ + 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/tools/gyp/test/same-name/src/subdir1/func.c b/tools/gyp/test/same-name/src/subdir1/func.c new file mode 100644 index 0000000..b73450d --- /dev/null +++ b/tools/gyp/test/same-name/src/subdir1/func.c @@ -0,0 +1,6 @@ +#include + +void subdir1_func(void) +{ + printf("Hello %s from subdir1/func.c\n", PROG); +} diff --git a/tools/gyp/test/same-name/src/subdir2/func.c b/tools/gyp/test/same-name/src/subdir2/func.c new file mode 100644 index 0000000..0248b57 --- /dev/null +++ b/tools/gyp/test/same-name/src/subdir2/func.c @@ -0,0 +1,6 @@ +#include + +void subdir2_func(void) +{ + printf("Hello %s from subdir2/func.c\n", PROG); +} diff --git a/tools/gyp/test/same-target-name/gyptest-same-target-name.py b/tools/gyp/test/same-target-name/gyptest-same-target-name.py new file mode 100755 index 0000000..bfe5540 --- /dev/null +++ b/tools/gyp/test/same-target-name/gyptest-same-target-name.py @@ -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/tools/gyp/test/same-target-name/src/all.gyp b/tools/gyp/test/same-target-name/src/all.gyp new file mode 100644 index 0000000..ac16976 --- /dev/null +++ b/tools/gyp/test/same-target-name/src/all.gyp @@ -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/tools/gyp/test/same-target-name/src/executable1.gyp b/tools/gyp/test/same-target-name/src/executable1.gyp new file mode 100644 index 0000000..3c492c1 --- /dev/null +++ b/tools/gyp/test/same-target-name/src/executable1.gyp @@ -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/tools/gyp/test/same-target-name/src/executable2.gyp b/tools/gyp/test/same-target-name/src/executable2.gyp new file mode 100644 index 0000000..41e84a6 --- /dev/null +++ b/tools/gyp/test/same-target-name/src/executable2.gyp @@ -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/tools/gyp/test/scons_tools/gyptest-tools.py b/tools/gyp/test/scons_tools/gyptest-tools.py new file mode 100755 index 0000000..e97f5e6 --- /dev/null +++ b/tools/gyp/test/scons_tools/gyptest-tools.py @@ -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 that a scons build picks up tools modules specified +via 'scons_tools' in the 'scons_settings' dictionary. +""" + +import TestGyp + +test = TestGyp.TestGyp() + +test.run_gyp('tools.gyp') + +test.build('tools.gyp', test.ALL) + +if test.format == 'scons': + expect = "Hello, world!\n" +else: + expect = "" +test.run_built_executable('tools', stdout=expect) + +test.pass_test() diff --git a/tools/gyp/test/scons_tools/site_scons/site_tools/this_tool.py b/tools/gyp/test/scons_tools/site_scons/site_tools/this_tool.py new file mode 100644 index 0000000..10c8947 --- /dev/null +++ b/tools/gyp/test/scons_tools/site_scons/site_tools/this_tool.py @@ -0,0 +1,10 @@ +# 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. + +# SCons "tool" module that simply sets a -D value. +def generate(env): + env['CPPDEFINES'] = ['THIS_TOOL'] + +def exists(env): + pass diff --git a/tools/gyp/test/scons_tools/tools.c b/tools/gyp/test/scons_tools/tools.c new file mode 100644 index 0000000..78dc0e3 --- /dev/null +++ b/tools/gyp/test/scons_tools/tools.c @@ -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 + +int main(int argc, char *argv[]) +{ +#ifdef THIS_TOOL + printf("Hello, world!\n"); +#endif + return 0; +} diff --git a/tools/gyp/test/scons_tools/tools.gyp b/tools/gyp/test/scons_tools/tools.gyp new file mode 100644 index 0000000..736ba3f --- /dev/null +++ b/tools/gyp/test/scons_tools/tools.gyp @@ -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': 'tools', + 'type': 'executable', + 'sources': [ + 'tools.c', + ], + }, + ], + 'scons_settings': { + 'tools': ['default', 'this_tool'], + }, +} diff --git a/tools/gyp/test/settings/gyptest-settings.py b/tools/gyp/test/settings/gyptest-settings.py new file mode 100755 index 0000000..0ed81ed --- /dev/null +++ b/tools/gyp/test/settings/gyptest-settings.py @@ -0,0 +1,18 @@ +#!/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. + +""" +Smoke-tests 'settings' blocks. +""" + +import TestGyp + +# 'settings' is only supported for make and scons (and will be removed there as +# well eventually). +test = TestGyp.TestGyp(formats=['make', 'scons']) +test.run_gyp('settings.gyp') +test.build('test.gyp', test.ALL) +test.pass_test() diff --git a/tools/gyp/test/settings/settings.gyp b/tools/gyp/test/settings/settings.gyp new file mode 100644 index 0000000..5bde13e --- /dev/null +++ b/tools/gyp/test/settings/settings.gyp @@ -0,0 +1,20 @@ +# 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': 'settings_target', + 'type': 'settings', + # In real life, this would set 'cflags' etc and other targets + # would depend on it. + }, + { + # This is needed so scons will actually generate a SConstruct + # (which it doesn't do for settings targets alone). + 'target_name': 'junk1', + 'type': 'none', + }, + ], +} diff --git a/tools/gyp/test/sibling/gyptest-all.py b/tools/gyp/test/sibling/gyptest-all.py new file mode 100755 index 0000000..7e80cf8 --- /dev/null +++ b/tools/gyp/test/sibling/gyptest-all.py @@ -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. + +""" +""" + +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'): + chdir = 'src' + +if test.format == 'xcode': + chdir = 'src/prog1' +test.run_built_executable('prog1', + chdir=chdir, + stdout="Hello from prog1.c\n") + +if test.format == 'xcode': + chdir = 'src/prog2' +test.run_built_executable('prog2', + chdir=chdir, + stdout="Hello from prog2.c\n") + +test.pass_test() diff --git a/tools/gyp/test/sibling/gyptest-relocate.py b/tools/gyp/test/sibling/gyptest-relocate.py new file mode 100755 index 0000000..7c86548 --- /dev/null +++ b/tools/gyp/test/sibling/gyptest-relocate.py @@ -0,0 +1,41 @@ +#!/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('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'): + chdir = 'relocate/src' + +if test.format == 'xcode': + chdir = 'relocate/src/prog1' +test.run_built_executable('prog1', + chdir=chdir, + stdout="Hello from prog1.c\n") + +if test.format == 'xcode': + chdir = 'relocate/src/prog2' +test.run_built_executable('prog2', + chdir=chdir, + stdout="Hello from prog2.c\n") + +test.pass_test() diff --git a/tools/gyp/test/sibling/src/build/all.gyp b/tools/gyp/test/sibling/src/build/all.gyp new file mode 100644 index 0000000..6eafdf9 --- /dev/null +++ b/tools/gyp/test/sibling/src/build/all.gyp @@ -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': [ + { + # TODO(sgk): a target name of 'all' leads to a scons dependency cycle + 'target_name': 'All', + 'type': 'none', + 'dependencies': [ + '../prog1/prog1.gyp:*', + '../prog2/prog2.gyp:*', + ], + }, + ], +} diff --git a/tools/gyp/test/sibling/src/prog1/prog1.c b/tools/gyp/test/sibling/src/prog1/prog1.c new file mode 100644 index 0000000..161ae8a --- /dev/null +++ b/tools/gyp/test/sibling/src/prog1/prog1.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("Hello from prog1.c\n"); + return 0; +} diff --git a/tools/gyp/test/sibling/src/prog1/prog1.gyp b/tools/gyp/test/sibling/src/prog1/prog1.gyp new file mode 100644 index 0000000..fbe38b9 --- /dev/null +++ b/tools/gyp/test/sibling/src/prog1/prog1.gyp @@ -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': 'prog1', + 'type': 'executable', + 'sources': [ + 'prog1.c', + ], + }, + ], +} diff --git a/tools/gyp/test/sibling/src/prog2/prog2.c b/tools/gyp/test/sibling/src/prog2/prog2.c new file mode 100644 index 0000000..7635ae8 --- /dev/null +++ b/tools/gyp/test/sibling/src/prog2/prog2.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("Hello from prog2.c\n"); + return 0; +} diff --git a/tools/gyp/test/sibling/src/prog2/prog2.gyp b/tools/gyp/test/sibling/src/prog2/prog2.gyp new file mode 100644 index 0000000..5934548 --- /dev/null +++ b/tools/gyp/test/sibling/src/prog2/prog2.gyp @@ -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/tools/gyp/test/small/gyptest-small.py b/tools/gyp/test/small/gyptest-small.py new file mode 100755 index 0000000..a484cb3 --- /dev/null +++ b/tools/gyp/test/small/gyptest-small.py @@ -0,0 +1,51 @@ +#!/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. + +""" +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', +] + +# 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/tools/gyp/test/subdirectory/gyptest-SYMROOT-all.py b/tools/gyp/test/subdirectory/gyptest-SYMROOT-all.py new file mode 100755 index 0000000..b750904 --- /dev/null +++ b/tools/gyp/test/subdirectory/gyptest-SYMROOT-all.py @@ -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/tools/gyp/test/subdirectory/gyptest-SYMROOT-default.py b/tools/gyp/test/subdirectory/gyptest-SYMROOT-default.py new file mode 100755 index 0000000..c64ae7d --- /dev/null +++ b/tools/gyp/test/subdirectory/gyptest-SYMROOT-default.py @@ -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/tools/gyp/test/subdirectory/gyptest-subdir-all.py b/tools/gyp/test/subdirectory/gyptest-subdir-all.py new file mode 100755 index 0000000..93344a0 --- /dev/null +++ b/tools/gyp/test/subdirectory/gyptest-subdir-all.py @@ -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. + +""" +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 + +# Ninja doesn't support running from subdirectories. +test = TestGyp.TestGyp(formats=['!ninja']) + +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/tools/gyp/test/subdirectory/gyptest-subdir-default.py b/tools/gyp/test/subdirectory/gyptest-subdir-default.py new file mode 100755 index 0000000..92edcd2 --- /dev/null +++ b/tools/gyp/test/subdirectory/gyptest-subdir-default.py @@ -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. + +""" +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 + +# Ninja doesn't support running from subdirectories. +test = TestGyp.TestGyp(formats=['!ninja']) + +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/tools/gyp/test/subdirectory/gyptest-subdir2-deep.py b/tools/gyp/test/subdirectory/gyptest-subdir2-deep.py new file mode 100755 index 0000000..4854898 --- /dev/null +++ b/tools/gyp/test/subdirectory/gyptest-subdir2-deep.py @@ -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/tools/gyp/test/subdirectory/gyptest-top-all.py b/tools/gyp/test/subdirectory/gyptest-top-all.py new file mode 100755 index 0000000..a29a41b --- /dev/null +++ b/tools/gyp/test/subdirectory/gyptest-top-all.py @@ -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 implementations of SCons and 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/tools/gyp/test/subdirectory/gyptest-top-default.py b/tools/gyp/test/subdirectory/gyptest-top-default.py new file mode 100755 index 0000000..ac5f60d --- /dev/null +++ b/tools/gyp/test/subdirectory/gyptest-top-default.py @@ -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 implementations of SCons and 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/tools/gyp/test/subdirectory/src/prog1.c b/tools/gyp/test/subdirectory/src/prog1.c new file mode 100644 index 0000000..161ae8a --- /dev/null +++ b/tools/gyp/test/subdirectory/src/prog1.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("Hello from prog1.c\n"); + return 0; +} diff --git a/tools/gyp/test/subdirectory/src/prog1.gyp b/tools/gyp/test/subdirectory/src/prog1.gyp new file mode 100644 index 0000000..2aa66ce --- /dev/null +++ b/tools/gyp/test/subdirectory/src/prog1.gyp @@ -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/tools/gyp/test/subdirectory/src/subdir/prog2.c b/tools/gyp/test/subdirectory/src/subdir/prog2.c new file mode 100644 index 0000000..7635ae8 --- /dev/null +++ b/tools/gyp/test/subdirectory/src/subdir/prog2.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("Hello from prog2.c\n"); + return 0; +} diff --git a/tools/gyp/test/subdirectory/src/subdir/prog2.gyp b/tools/gyp/test/subdirectory/src/subdir/prog2.gyp new file mode 100644 index 0000000..c6cd35f --- /dev/null +++ b/tools/gyp/test/subdirectory/src/subdir/prog2.gyp @@ -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/tools/gyp/test/subdirectory/src/subdir/subdir2/prog3.c b/tools/gyp/test/subdirectory/src/subdir/subdir2/prog3.c new file mode 100644 index 0000000..7cfb0fa --- /dev/null +++ b/tools/gyp/test/subdirectory/src/subdir/subdir2/prog3.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("Hello from prog3.c\n"); + return 0; +} diff --git a/tools/gyp/test/subdirectory/src/subdir/subdir2/prog3.gyp b/tools/gyp/test/subdirectory/src/subdir/subdir2/prog3.gyp new file mode 100644 index 0000000..b49fb59 --- /dev/null +++ b/tools/gyp/test/subdirectory/src/subdir/subdir2/prog3.gyp @@ -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/tools/gyp/test/subdirectory/src/symroot.gypi b/tools/gyp/test/subdirectory/src/symroot.gypi new file mode 100644 index 0000000..5199164 --- /dev/null +++ b/tools/gyp/test/subdirectory/src/symroot.gypi @@ -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/tools/gyp/test/toolsets/gyptest-toolsets.py b/tools/gyp/test/toolsets/gyptest-toolsets.py new file mode 100755 index 0000000..19737f8 --- /dev/null +++ b/tools/gyp/test/toolsets/gyptest-toolsets.py @@ -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 that toolsets are correctly applied +""" + +import TestGyp + +# Multiple toolsets are currently only supported by the make generator. +test = TestGyp.TestGyp(formats=['make']) + +test.run_gyp('toolsets.gyp') + +test.build('toolsets.gyp', test.ALL) + +test.run_built_executable('host-main', stdout="Host\n") +test.run_built_executable('target-main', stdout="Target\n") + +test.pass_test() diff --git a/tools/gyp/test/toolsets/main.cc b/tools/gyp/test/toolsets/main.cc new file mode 100644 index 0000000..0f353ae --- /dev/null +++ b/tools/gyp/test/toolsets/main.cc @@ -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 + +const char *GetToolset(); + +int main(int argc, char *argv[]) { + printf("%s\n", GetToolset()); +} diff --git a/tools/gyp/test/toolsets/toolsets.cc b/tools/gyp/test/toolsets/toolsets.cc new file mode 100644 index 0000000..a45fa02 --- /dev/null +++ b/tools/gyp/test/toolsets/toolsets.cc @@ -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/tools/gyp/test/toolsets/toolsets.gyp b/tools/gyp/test/toolsets/toolsets.gyp new file mode 100644 index 0000000..e41b928 --- /dev/null +++ b/tools/gyp/test/toolsets/toolsets.gyp @@ -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': { + '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'], + 'sources': [ + 'main.cc', + ], + }, + { + 'target_name': 'target-main', + 'type': 'executable', + 'dependencies': ['toolsets'], + 'sources': [ + 'main.cc', + ], + }, + ], +} diff --git a/tools/gyp/test/toplevel-dir/gyptest-toplevel-dir.py b/tools/gyp/test/toplevel-dir/gyptest-toplevel-dir.py new file mode 100755 index 0000000..61986cd --- /dev/null +++ b/tools/gyp/test/toplevel-dir/gyptest-toplevel-dir.py @@ -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=['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/tools/gyp/test/toplevel-dir/src/sub1/main.gyp b/tools/gyp/test/toplevel-dir/src/sub1/main.gyp new file mode 100644 index 0000000..3321901 --- /dev/null +++ b/tools/gyp/test/toplevel-dir/src/sub1/main.gyp @@ -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/tools/gyp/test/toplevel-dir/src/sub1/prog1.c b/tools/gyp/test/toplevel-dir/src/sub1/prog1.c new file mode 100644 index 0000000..161ae8a --- /dev/null +++ b/tools/gyp/test/toplevel-dir/src/sub1/prog1.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("Hello from prog1.c\n"); + return 0; +} diff --git a/tools/gyp/test/toplevel-dir/src/sub2/prog2.c b/tools/gyp/test/toplevel-dir/src/sub2/prog2.c new file mode 100644 index 0000000..7635ae8 --- /dev/null +++ b/tools/gyp/test/toplevel-dir/src/sub2/prog2.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + printf("Hello from prog2.c\n"); + return 0; +} diff --git a/tools/gyp/test/toplevel-dir/src/sub2/prog2.gyp b/tools/gyp/test/toplevel-dir/src/sub2/prog2.gyp new file mode 100644 index 0000000..5934548 --- /dev/null +++ b/tools/gyp/test/toplevel-dir/src/sub2/prog2.gyp @@ -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/tools/gyp/test/variables/commands/commands-repeated.gyp b/tools/gyp/test/variables/commands/commands-repeated.gyp new file mode 100644 index 0000000..822ae4f --- /dev/null +++ b/tools/gyp/test/variables/commands/commands-repeated.gyp @@ -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': ' commands.gyp.stdout +python ../../../gyp --ignore-environment --debug variables --debug general --format gypd --depth . commands.gyp > commands.gyp.ignore-env.stdout +cp -f commands.gypd commands.gypd.golden +python ../../../gyp --debug variables --debug general --format gypd --depth . commands-repeated.gyp > commands-repeated.gyp.stdout +cp -f commands-repeated.gypd commands-repeated.gypd.golden diff --git a/tools/gyp/test/variables/filelist/filelist.gyp.stdout b/tools/gyp/test/variables/filelist/filelist.gyp.stdout new file mode 100644 index 0000000..910b767 --- /dev/null +++ b/tools/gyp/test/variables/filelist/filelist.gyp.stdout @@ -0,0 +1,174 @@ +GENERAL:__init__.py:356:main running with these options: +GENERAL:__init__.py:363:main check: None +GENERAL:__init__.py:363:main circular_check: True +GENERAL:__init__.py:363:main debug: ['variables', 'general'] +GENERAL:__init__.py:363:main defines: None +GENERAL:__init__.py:361:main depth: '.' +GENERAL:__init__.py:363:main formats: ['gypd'] +GENERAL:__init__.py:363:main generator_flags: [] +GENERAL:__init__.py:363:main generator_output: None +GENERAL:__init__.py:363:main includes: None +GENERAL:__init__.py:363:main msvs_version: None +GENERAL:__init__.py:361:main suffix: '' +GENERAL:__init__.py:363:main toplevel_dir: None +GENERAL:__init__.py:363:main use_environment: True +GENERAL:__init__.py:417:main cmdline_default_variables: {} +GENERAL:__init__.py:443:main generator_flags: {} +VARIABLES:input.py:785:ExpandVariables Expanding 'exclude' to 'exclude' +VARIABLES:input.py:785:ExpandVariables Expanding 'Sch.*' to 'Sch.*' +VARIABLES:input.py:785:ExpandVariables Expanding 'include' to 'include' +VARIABLES:input.py:785:ExpandVariables Expanding '.*dt' to '.*dt' +VARIABLES:input.py:785:ExpandVariables Expanding 'exclude' to 'exclude' +VARIABLES:input.py:785:ExpandVariables Expanding 'Jer.*' to 'Jer.*' +VARIABLES:input.py:785:ExpandVariables Expanding 'John' to 'John' +VARIABLES:input.py:785:ExpandVariables Expanding 'Jacob' to 'Jacob' +VARIABLES:input.py:785:ExpandVariables Expanding 'Astor' to 'Astor' +VARIABLES:input.py:785:ExpandVariables Expanding 'Jingleheimer' to 'Jingleheimer' +VARIABLES:input.py:785:ExpandVariables Expanding 'Jerome' to 'Jerome' +VARIABLES:input.py:785:ExpandVariables Expanding 'Schmidt' to 'Schmidt' +VARIABLES:input.py:785:ExpandVariables Expanding 'Schultz' to 'Schultz' +VARIABLES:input.py:785:ExpandVariables Expanding 'Astor' to 'Astor' +VARIABLES:input.py:785:ExpandVariables Expanding '.' to '.' +VARIABLES:input.py:546:ExpandVariables Matches: {'content': 'names.txt <@(names', 'is_array': '', 'replace': '<|(names.txt <@(names)', 'type': '<|', 'command_string': None} +VARIABLES:input.py:546:ExpandVariables Matches: {'content': 'names', 'is_array': '', 'replace': '<@(names)', 'type': '<@', 'command_string': None} +VARIABLES:input.py:785:ExpandVariables Expanding 'names' to 'names' +VARIABLES:input.py:785:ExpandVariables Expanding 'John' to 'John' +VARIABLES:input.py:785:ExpandVariables Expanding 'Jacob' to 'Jacob' +VARIABLES:input.py:785:ExpandVariables Expanding 'Jingleheimer' to 'Jingleheimer' +VARIABLES:input.py:785:ExpandVariables Expanding 'Schmidt' to 'Schmidt' +VARIABLES:input.py:767:ExpandVariables Found output 'names.txt John Jacob Jingleheimer Schmidt', recursing. +VARIABLES:input.py:785:ExpandVariables Expanding 'names.txt John Jacob Jingleheimer Schmidt' to 'names.txt John Jacob Jingleheimer Schmidt' +VARIABLES:input.py:785:ExpandVariables Expanding 'names.txt <@(names)' to 'names.txt John Jacob Jingleheimer Schmidt' +VARIABLES:input.py:767:ExpandVariables Found output 'names.txt', recursing. +VARIABLES:input.py:785:ExpandVariables Expanding 'names.txt' to 'names.txt' +VARIABLES:input.py:785:ExpandVariables Expanding '<|(names.txt <@(names))' to 'names.txt' +VARIABLES:input.py:785:ExpandVariables Expanding 'foo' to 'foo' +VARIABLES:input.py:785:ExpandVariables Expanding 'target' to 'target' +VARIABLES:input.py:785:ExpandVariables Expanding 'none' to 'none' +VARIABLES:input.py:785:ExpandVariables Expanding 'test_action' to 'test_action' +VARIABLES:input.py:785:ExpandVariables Expanding 'python' to 'python' +VARIABLES:input.py:785:ExpandVariables Expanding 'dummy.py' to 'dummy.py' +VARIABLES:input.py:546:ExpandVariables Matches: {'content': 'names_listfile', 'is_array': '', 'replace': '<(names_listfile)', 'type': '<', 'command_string': None} +VARIABLES:input.py:785:ExpandVariables Expanding 'names_listfile' to 'names_listfile' +VARIABLES:input.py:767:ExpandVariables Found output 'names.txt', recursing. +VARIABLES:input.py:785:ExpandVariables Expanding 'names.txt' to 'names.txt' +VARIABLES:input.py:785:ExpandVariables Expanding '<(names_listfile)' to 'names.txt' +VARIABLES:input.py:546:ExpandVariables Matches: {'content': 'names_listfile', 'is_array': '', 'replace': '<(names_listfile)', 'type': '<', 'command_string': None} +VARIABLES:input.py:785:ExpandVariables Expanding 'names_listfile' to 'names_listfile' +VARIABLES:input.py:767:ExpandVariables Found output 'names.txt', recursing. +VARIABLES:input.py:785:ExpandVariables Expanding 'names.txt' to 'names.txt' +VARIABLES:input.py:785:ExpandVariables Expanding '<(names_listfile)' to 'names.txt' +VARIABLES:input.py:546:ExpandVariables Matches: {'content': 'cat <(names_listfile', 'is_array': '', 'replace': ' filelist.gyp.stdout +cp -f src/filelist.gypd filelist.gypd.golden diff --git a/tools/gyp/test/variants/gyptest-variants.py b/tools/gyp/test/variants/gyptest-variants.py new file mode 100755 index 0000000..ce2455f --- /dev/null +++ b/tools/gyp/test/variants/gyptest-variants.py @@ -0,0 +1,45 @@ +#!/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 handling of build variants. + +TODO: Right now, only the SCons generator supports this, so the +test case is SCons-specific. In particular, it relise on SCons' +ability to rebuild in response to changes on the command line. It +may be simpler to just drop this feature if the other generators +can't be made to behave the same way. +""" + +import TestGyp + +test = TestGyp.TestGyp(formats=['scons']) + +test.run_gyp('variants.gyp', chdir='src') + +test.relocate('src', 'relocate/src') + +test.build('variants.gyp', chdir='relocate/src') + +test.run_built_executable('variants', + chdir='relocate/src', + stdout="Hello, world!\n") + +test.sleep() +test.build('variants.gyp', 'VARIANT1=1', chdir='relocate/src') + +test.run_built_executable('variants', + chdir='relocate/src', + stdout="Hello from VARIANT1\n") + +test.sleep() +test.build('variants.gyp', 'VARIANT2=1', chdir='relocate/src') + +test.run_built_executable('variants', + chdir='relocate/src', + stdout="Hello from VARIANT2\n") + +test.pass_test() diff --git a/tools/gyp/test/variants/src/variants.c b/tools/gyp/test/variants/src/variants.c new file mode 100644 index 0000000..3018e40 --- /dev/null +++ b/tools/gyp/test/variants/src/variants.c @@ -0,0 +1,13 @@ +#include + +int main(int argc, char *argv[]) +{ +#if defined(VARIANT1) + printf("Hello from VARIANT1\n"); +#elif defined(VARIANT2) + printf("Hello from VARIANT2\n"); +#else + printf("Hello, world!\n"); +#endif + return 0; +} diff --git a/tools/gyp/test/variants/src/variants.gyp b/tools/gyp/test/variants/src/variants.gyp new file mode 100644 index 0000000..0305ca7 --- /dev/null +++ b/tools/gyp/test/variants/src/variants.gyp @@ -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': 'variants', + 'type': 'executable', + 'sources': [ + 'variants.c', + ], + 'variants': { + 'variant1' : { + 'defines': [ + 'VARIANT1', + ], + }, + 'variant2' : { + 'defines': [ + 'VARIANT2', + ], + }, + }, + }, + ], +} diff --git a/tools/gyp/tools/graphviz.py b/tools/gyp/tools/graphviz.py index 7f71668..326ae22 100755 --- a/tools/gyp/tools/graphviz.py +++ b/tools/gyp/tools/graphviz.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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 @@ -83,13 +83,18 @@ def WriteGraph(edges): print '}' -if __name__ == '__main__': +def main(): if len(sys.argv) < 2: print >>sys.stderr, __doc__ print >>sys.stderr print >>sys.stderr, 'usage: %s target1 target2...' % (sys.argv[0]) - sys.exit(1) + return 1 edges = LoadEdges('dump.json', sys.argv[1:]) WriteGraph(edges) + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/gyp/tools/pretty_gyp.py b/tools/gyp/tools/pretty_gyp.py old mode 100644 new mode 100755 index 04c7901..3749792 --- a/tools/gyp/tools/pretty_gyp.py +++ b/tools/gyp/tools/pretty_gyp.py @@ -1,142 +1,154 @@ -#!/usr/bin/env python -# Copyright (c) 2009 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 pretty-prints the contents of a GYP file. - -import sys -import re - -input = [] -if len(sys.argv) > 1: - input_file = open(sys.argv[1]) - input = input_file.read().splitlines() - input_file.close() -else: - input = sys.stdin.read().splitlines() - -# This is used to remove comments when we're counting braces. -comment_re = re.compile(r'\s*#.*') - -# This is used 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[\'"])(.*?)(? 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) - -# This does the main work of indenting the input based on the brace counts. -def prettyprint_input(lines): - 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 - -# Split up the double braces. -lines = split_double_braces(input) - -# Indent and print the output. -prettyprint_input(lines) +#!/usr/bin/env python +# 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. + +"""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[\'"])(.*?)(? 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/tools/gyp/tools/pretty_sln.py b/tools/gyp/tools/pretty_sln.py index 0741fff..7013f2b 100755 --- a/tools/gyp/tools/pretty_sln.py +++ b/tools/gyp/tools/pretty_sln.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2.5 +#!/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 @@ -153,7 +153,7 @@ 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 + return 1 (projects, deps) = ParseSolution(sys.argv[1]) PrintDependencies(projects, deps) @@ -161,7 +161,8 @@ def main(): if '--recursive' in sys.argv: PrintVCProj(projects) + return 0 -if __name__ == '__main__': - main() +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/gyp/tools/pretty_vcproj.py b/tools/gyp/tools/pretty_vcproj.py index 292a39f..ba65bf2 100755 --- a/tools/gyp/tools/pretty_vcproj.py +++ b/tools/gyp/tools/pretty_vcproj.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2.5 +#!/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 @@ -23,14 +23,16 @@ REPLACEMENTS = dict() ARGUMENTS = None -class CmpTuple: + +class CmpTuple(object): """Compare function between 2 tuple.""" def __call__(self, x, y): (key1, value1) = x (key2, value2) = y return cmp(key1, key2) -class CmpNode: + +class CmpNode(object): """Compare function between 2 xml nodes.""" def get_string(self, node): @@ -57,6 +59,7 @@ def get_string(self, node): def __call__(self, x, y): return cmp(self.get_string(x), self.get_string(y)) + def PrettyPrintNode(node, indent=0): if node.nodeType == Node.TEXT_NODE: if node.data.strip(): @@ -90,6 +93,7 @@ def PrettyPrintNode(node, indent=0): PrettyPrintNode(sub_node, indent=indent+2) print '%s' % (' '*indent, node.nodeName) + def FlattenFilter(node): """Returns a list of all the node and sub nodes.""" node_list = [] @@ -107,6 +111,7 @@ def FlattenFilter(node): return node_list + def FixFilenames(filenames, current_directory): new_list = [] for filename in filenames: @@ -121,8 +126,9 @@ def FixFilenames(filenames, current_directory): new_list.append(os.path.abspath(filename)) return new_list + def AbsoluteNode(node): - # Make all the properties we know about in this node absolute. + """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', @@ -136,8 +142,9 @@ def AbsoluteNode(node): if not value: node.removeAttribute(name) + def CleanupVcproj(node): - # For each sub node, we call recursively this function. + """For each sub node, we call recursively this function.""" for sub_node in node.childNodes: AbsoluteNode(sub_node) CleanupVcproj(sub_node) @@ -192,6 +199,7 @@ def CleanupVcproj(node): continue node.appendChild(new_node) + def GetConfiguationNodes(vcproj): #TODO(nsylvain): Find a better way to navigate the xml. nodes = [] @@ -203,6 +211,7 @@ def GetConfiguationNodes(vcproj): return nodes + def GetChildrenVsprops(filename): dom = parse(filename) if dom.documentElement.attributes: @@ -231,6 +240,7 @@ def SeekToNode(node1, child2): # No match. We give up. return None + def MergeAttributes(node1, node2): # No attributes to merge? if not node2.attributes: @@ -255,6 +265,7 @@ def MergeAttributes(node1, node2): if name == 'InheritedPropertySheets': node1.removeAttribute(name) + def MergeProperties(node1, node2): MergeAttributes(node1, node2) for child2 in node2.childNodes: @@ -264,6 +275,7 @@ def MergeProperties(node1, node2): else: node1.appendChild(child2.cloneNode(True)) + def main(argv): global REPLACEMENTS global ARGUMENTS @@ -274,7 +286,7 @@ def main(argv): if len(argv) < 2: print ('Usage: %s "c:\\path\\to\\vcproj.vcproj" [key1=value1] ' '[key2=value2]' % argv[0]) - return + return 1 # Parse the keys for i in range(2, len(argv)): @@ -311,6 +323,8 @@ def main(argv): # user. #print dom.toprettyxml(newl="\n") PrettyPrintNode(dom.documentElement) + return 0 + if __name__ == '__main__': - main(sys.argv) + sys.exit(main(sys.argv))