Navigation Menu

Skip to content

Commit

Permalink
Add support for building targets directly from gyp.
Browse files Browse the repository at this point in the history
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
sbc@chromium.org committed Sep 18, 2012
1 parent 6cf3fba commit 08fc464
Show file tree
Hide file tree
Showing 12 changed files with 170 additions and 1 deletion.
4 changes: 3 additions & 1 deletion gyptest.py
Expand Up @@ -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:
Expand Down
13 changes: 13 additions & 0 deletions pylib/gyp/MSVSVersion.py
Expand Up @@ -9,6 +9,7 @@
import re
import subprocess
import sys
import gyp


class VisualStudioVersion(object):
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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')
Expand All @@ -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))

Expand Down
9 changes: 9 additions & 0 deletions pylib/gyp/__init__.py
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
12 changes: 12 additions & 0 deletions pylib/gyp/generator/make.py
Expand Up @@ -24,6 +24,7 @@
import os
import re
import sys
import subprocess
import gyp
import gyp.common
import gyp.system_test
Expand Down Expand Up @@ -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)
Expand Down
20 changes: 20 additions & 0 deletions pylib/gyp/generator/msvs.py
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
9 changes: 9 additions & 0 deletions pylib/gyp/generator/ninja.py
Expand Up @@ -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"
Expand Down
25 changes: 25 additions & 0 deletions pylib/gyp/generator/scons.py
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
19 changes: 19 additions & 0 deletions pylib/gyp/generator/xcode.py
Expand Up @@ -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', {})
Expand Down
22 changes: 22 additions & 0 deletions 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()
13 changes: 13 additions & 0 deletions 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;
}
15 changes: 15 additions & 0 deletions 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',
],
},
],
}
10 changes: 10 additions & 0 deletions test/lib/TestGyp.py
Expand Up @@ -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.
Expand All @@ -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]
Expand Down

0 comments on commit 08fc464

Please sign in to comment.