Permalink
Browse files

Add support for building targets directly from gyp.

A new --build option has been added which can be used to
build configurations directly from gyp.  Each generator
has a new method (PerformBuild) which knows how to invoke
the underlying build environment to build a certain
configuration.  e.g.

  $ gyp hello.gyp --format=ninja --build=Default

This allows gyp call sites to do actual builds without
having to know the exact method for running the underlying
build environment.

The motivation here is to remove the complexity and
duplication involved with building from gyp.  Currently
there are several places where gyp is run and then the
underlying build is run right away in all cases.  (e.g
the Gyp tests, the buildbots).  NaCl and the NaCL SDK
are also about to add two more places where this is
desirable.

Rational for putting this logic in the generators
themselves is that the generator maintainer is best
placed to know how to invoke the build.  Also the
details of how to run Foo seem best placed in the
Foo generator (especially if you think of generators
as plugins for gyp).

BUG=

Review URL: https://chromiumcodereview.appspot.com/10909158

git-svn-id: http://gyp.googlecode.com/svn/trunk@1499 78cadc50-ecff-11dd-a971-7dbc132099af
  • Loading branch information...
1 parent 6cf3fba commit 08fc464f96f4d8664ae6549d9b7767e8d7fbfa6b sbc@chromium.org committed Sep 18, 2012
View
4 gyptest.py
@@ -171,7 +171,9 @@ def main(argv=None):
os.chdir(opts.chdir)
if opts.path:
- os.environ['PATH'] += ':' + ':'.join(opts.path)
+ extra_path = [os.path.abspath(p) for p in opts.path]
+ extra_path = os.pathsep.join(extra_path)
+ os.environ['PATH'] += os.pathsep + extra_path
if not args:
if not opts.all:
View
13 pylib/gyp/MSVSVersion.py
@@ -9,6 +9,7 @@
import re
import subprocess
import sys
+import gyp
class VisualStudioVersion(object):
@@ -193,6 +194,8 @@ def _CreateVersion(name, path, sdk_based=False):
autodetected if GYP_MSVS_VERSION is not explicitly specified. If a version is
passed in that doesn't match a value in versions python will throw a error.
"""
+ if path:
+ path = os.path.normpath(path)
versions = {
'2012': VisualStudioVersion('2012',
'Visual Studio 2012',
@@ -264,6 +267,14 @@ def _CreateVersion(name, path, sdk_based=False):
return versions[str(name)]
+def _ConvertToCygpath(path):
+ """Convert to cygwin path if we are using cygwin."""
+ if sys.platform == 'cygwin':
+ p = subprocess.Popen(['cygpath', path], stdout=subprocess.PIPE)
+ path = p.communicate()[0].strip()
+ return path
+
+
def _DetectVisualStudioVersions(versions_to_check, force_express):
"""Collect the list of installed visual studio versions.
@@ -294,6 +305,7 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
path = _RegistryGetValue(keys[index], 'InstallDir')
if not path:
continue
+ path = _ConvertToCygpath(path)
# Check for full.
full_path = os.path.join(path, 'devenv.exe')
express_path = os.path.join(path, 'vcexpress.exe')
@@ -314,6 +326,7 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
path = _RegistryGetValue(keys[index], version)
if not path:
continue
+ path = _ConvertToCygpath(path)
versions.append(_CreateVersion(version_to_year[version] + 'e',
os.path.join(path, '..'), sdk_based=True))
View
9 pylib/gyp/__init__.py
@@ -314,6 +314,8 @@ def gyp_main(args):
parser.add_option('--toplevel-dir', dest='toplevel_dir', action='store',
default=None, metavar='DIR', type='path',
help='directory to use as the root of the source tree')
+ parser.add_option('--build', dest='configs', action='append',
+ help='configuration for build after project generation')
# --no-circular-check disables the check for circular relationships between
# .gyp files. These relationships should not exist, but they've only been
# observed to be harmful with the Xcode generator. Chromium's .gyp files
@@ -496,6 +498,13 @@ def gyp_main(args):
# generate targets in the order specified in flat_list.
generator.GenerateOutput(flat_list, targets, data, params)
+ if options.configs:
+ valid_configs = targets[flat_list[0]]['configurations'].keys()
+ for conf in options.configs:
+ if conf not in valid_configs:
+ raise GypError('Invalid config specified via --build: %s' % conf)
+ generator.PerformBuild(data, options.configs, params)
+
# Done
return 0
View
12 pylib/gyp/generator/make.py
@@ -24,6 +24,7 @@
import os
import re
import sys
+import subprocess
import gyp
import gyp.common
import gyp.system_test
@@ -1936,6 +1937,17 @@ def RunSystemTests(flavor):
'ARFLAGS.host': arflags_host }
+def PerformBuild(data, configurations, params):
+ options = params['options']
+ for config in configurations:
+ arguments = ['make']
+ if options.toplevel_dir and options.toplevel_dir != '.':
+ arguments += '-C', options.toplevel_dir
+ arguments.append('BUILDTYPE=' + config)
+ print 'Building [%s]: %s' % (config, arguments)
+ subprocess.check_call(arguments)
+
+
def GenerateOutput(target_list, target_dicts, data, params):
options = params['options']
flavor = gyp.common.GetFlavor(params)
View
20 pylib/gyp/generator/msvs.py
@@ -18,6 +18,7 @@
import gyp.MSVSToolFile as MSVSToolFile
import gyp.MSVSUserFile as MSVSUserFile
import gyp.MSVSVersion as MSVSVersion
+from gyp.common import GypError
# Regular expression for validating Visual Studio GUIDs. If the GUID
@@ -1781,6 +1782,25 @@ def _ShardTargets(target_list, target_dicts):
return (new_target_list, new_target_dicts)
+def PerformBuild(data, configurations, params):
+ options = params['options']
+ msvs_version = params['msvs_version']
+ devenv = os.path.join(msvs_version.path, 'Common7', 'IDE', 'devenv.com')
+
+ for build_file, build_file_dict in data.iteritems():
+ (build_file_root, build_file_ext) = os.path.splitext(build_file)
+ if build_file_ext != '.gyp':
+ continue
+ sln_path = build_file_root + options.suffix + '.sln'
+ if options.generator_output:
+ sln_path = os.path.join(options.generator_output, sln_path)
+
+ for config in configurations:
+ arguments = [devenv, sln_path, '/Build', config]
+ print 'Building [%s]: %s' % (config, arguments)
+ rtn = subprocess.check_call(arguments)
+
+
def GenerateOutput(target_list, target_dicts, data, params):
"""Generate .sln and .vcproj files.
View
9 pylib/gyp/generator/ninja.py
@@ -1722,6 +1722,15 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
master_ninja.default(generator_flags.get('default_target', 'all'))
+def PerformBuild(data, configurations, params):
+ options = params['options']
+ for config in configurations:
+ builddir = os.path.join(options.toplevel_dir, 'out', config)
+ arguments = ['ninja', '-C', builddir]
+ print 'Building [%s]: %s' % (config, arguments)
+ subprocess.check_call(arguments)
+
+
def GenerateOutput(target_list, target_dicts, data, params):
if params['options'].generator_output:
raise NotImplementedError, "--generator_output not implemented for ninja"
View
25 pylib/gyp/generator/scons.py
@@ -8,6 +8,7 @@
import os.path
import pprint
import re
+import subprocess
# TODO: remove when we delete the last WriteList() call in this module
@@ -960,6 +961,30 @@ def TargetFilename(target, build_file=None, output_suffix=''):
return output_file
+def PerformBuild(data, configurations, params):
+ options = params['options']
+
+ # Due to the way we test gyp on the chromium typbots
+ # we need to look for 'scons.py' as well as the more common 'scons'
+ # TODO(sbc): update the trybots to have a more normal install
+ # of scons.
+ scons = 'scons'
+ paths = os.environ['PATH'].split(os.pathsep)
+ for scons_name in ['scons', 'scons.py']:
+ for path in paths:
+ test_scons = os.path.join(path, scons_name)
+ print 'looking for: %s' % test_scons
+ if os.path.exists(test_scons):
+ print "found scons: %s" % scons
+ scons = test_scons
+ break
+
+ for config in configurations:
+ arguments = [scons, '-C', options.toplevel_dir, '--mode=%s' % config]
+ print "Building [%s]: %s" % (config, arguments)
+ subprocess.check_call(arguments)
+
+
def GenerateOutput(target_list, target_dicts, data, params):
"""
Generates all the output files for the specified targets.
View
19 pylib/gyp/generator/xcode.py
@@ -587,6 +587,25 @@ def EscapeXCodeArgument(s):
return '"' + s + '"'
+
+def PerformBuild(data, configurations, params):
+ options = params['options']
+
+ for build_file, build_file_dict in data.iteritems():
+ (build_file_root, build_file_ext) = os.path.splitext(build_file)
+ if build_file_ext != '.gyp':
+ continue
+ xcodeproj_path = build_file_root + options.suffix + '.xcodeproj'
+ if options.generator_output:
+ xcodeproj_path = os.path.join(options.generator_output, xcodeproj_path)
+
+ for config in configurations:
+ arguments = ['xcodebuild', '-project', xcodeproj_path]
+ arguments += ['-configuration', config]
+ print "Building [%s]: %s" % (config, arguments)
+ subprocess.check_call(arguments)
+
+
def GenerateOutput(target_list, target_dicts, data, params):
options = params['options']
generator_flags = params.get('generator_flags', {})
View
22 test/build-option/gyptest-build.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies 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', '--build=Default')
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.up_to_date('hello.gyp', test.DEFAULT)
+
+test.pass_test()
View
13 test/build-option/hello.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello, world!\n");
+ return 0;
+}
View
15 test/build-option/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',
+ ],
+ },
+ ],
+}
View
10 test/lib/TestGyp.py
@@ -604,6 +604,14 @@ def built_file_path(self, name, type=None, **kw):
return self.workpath(*result)
+def ConvertToCygpath(path):
+ """Convert to cygwin path if we are using cygwin."""
+ if sys.platform == 'cygwin':
+ p = subprocess.Popen(['cygpath', path], stdout=subprocess.PIPE)
+ path = p.communicate()[0].strip()
+ return path
+
+
def FindVisualStudioInstallation():
"""Returns appropriate values for .build_tool and .uses_msbuild fields
of TestGypBase for Visual Studio.
@@ -619,6 +627,8 @@ def FindVisualStudioInstallation():
'2008': r'Microsoft Visual Studio 9.0\Common7\IDE\devenv.com',
'2005': r'Microsoft Visual Studio 8\Common7\IDE\devenv.com'}
+ possible_roots = [ConvertToCygpath(r) for r in possible_roots]
+
msvs_version = 'auto'
for flag in (f for f in sys.argv if f.startswith('msvs_version=')):
msvs_version = flag.split('=')[-1]

0 comments on commit 08fc464

Please sign in to comment.