181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#!/usr/bin/env python
281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch# Copyright (c) 2011 Google Inc. All rights reserved.
3e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#
4e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# Redistribution and use in source and binary forms, with or without
5e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# modification, are permitted provided that the following conditions are
6e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# met:
7e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#
881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#     * Redistributions of source code must retain the above copyright
9e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# notice, this list of conditions and the following disclaimer.
1081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#     * Redistributions in binary form must reproduce the above
11e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# copyright notice, this list of conditions and the following disclaimer
12e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# in the documentation and/or other materials provided with the
13e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# distribution.
1481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#     * Neither the name of Google Inc. nor the names of its
15e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# contributors may be used to endorse or promote products derived from
16e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# this software without specific prior written permission.
17e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#
18e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
30e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
3181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochimport os
3281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochimport subprocess
33e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
342bde8e466a4451c7319e3a072d118917957d6554Steve Blockfrom optparse import OptionParser
35e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
362bde8e466a4451c7319e3a072d118917957d6554Steve Blockdef chdir_to_source():
372bde8e466a4451c7319e3a072d118917957d6554Steve Block    source_directory = os.path.abspath(os.path.join(__file__, '..', '..'))
382bde8e466a4451c7319e3a072d118917957d6554Steve Block    os.chdir(source_directory)
392bde8e466a4451c7319e3a072d118917957d6554Steve Block
402bde8e466a4451c7319e3a072d118917957d6554Steve Blockdef gyp():
412bde8e466a4451c7319e3a072d118917957d6554Steve Block    return os.path.join('ThirdParty', 'gyp', 'gyp')
42e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
442bde8e466a4451c7319e3a072d118917957d6554Steve Blockclass Project:
452bde8e466a4451c7319e3a072d118917957d6554Steve Block    def __init__(self, name):
462bde8e466a4451c7319e3a072d118917957d6554Steve Block        self._name = name
47e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
482bde8e466a4451c7319e3a072d118917957d6554Steve Block    def name(self):
492bde8e466a4451c7319e3a072d118917957d6554Steve Block        return self._name
50e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
512daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def _gyp_directory(self):
522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return os.path.join(self._name, 'gyp')
532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
542daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def _gyp_file_for_port(self, port):
552daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        # Gyp uses the gyp file name as the XCode proj file name, so for now "apple-mac" must be ProjectName.gyp
562daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if port == "mac":
572daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            return '%s.gyp' % self._name
582daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return "%s.gyp" % port
592daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
602daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def inputs(self, port):
612bde8e466a4451c7319e3a072d118917957d6554Steve Block        return [
622daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            os.path.join(self._gyp_directory(), self._gyp_file_for_port(port)),
632bde8e466a4451c7319e3a072d118917957d6554Steve Block            os.path.join(self._name, self._name + '.gypi'),
642bde8e466a4451c7319e3a072d118917957d6554Steve Block            os.path.join('gyp', 'common.gypi'),
652bde8e466a4451c7319e3a072d118917957d6554Steve Block        ]
66e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def _output_for_port(self, port):
682daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        format = format_for_port(port)
692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return {
702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            'filelist': '%s.am' % port,
712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            'xcode': os.path.join(self._name + '.xcodeproj', 'project.pbxproj'),
722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        }[format]
7381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def output(self, port):
752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return os.path.join(self._gyp_directory(), self._output_for_port(port))
762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def should_generate(self, port):
782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if not os.path.exists(self.output(port)):
792bde8e466a4451c7319e3a072d118917957d6554Steve Block            return True
802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return os.path.getmtime(self.output(port)) < self._newest(self.inputs(port))
812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def _extra_args_for_format(self, format):
832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if format == "xcode":
842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            return ['-G', 'xcode_list_excluded_files=0']
852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return []
862bde8e466a4451c7319e3a072d118917957d6554Steve Block
872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def generate(self, port):
882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        args = [
892bde8e466a4451c7319e3a072d118917957d6554Steve Block            gyp(),
902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            self.inputs(port)[0],
912bde8e466a4451c7319e3a072d118917957d6554Steve Block            '--depth=.',
922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        ]
932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        format = format_for_port(port)
942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        args.append('--format=%s' % format)
952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        args += self._extra_args_for_format(format)
962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        subprocess.call(args)
982bde8e466a4451c7319e3a072d118917957d6554Steve Block        # GYP doesn't always touch the output file, but we want to touch the
992bde8e466a4451c7319e3a072d118917957d6554Steve Block        # file so that we don't keep trying to regenerate it.
1002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        os.utime(self.output(port), None)
1012bde8e466a4451c7319e3a072d118917957d6554Steve Block
1022bde8e466a4451c7319e3a072d118917957d6554Steve Block    @staticmethod
1032bde8e466a4451c7319e3a072d118917957d6554Steve Block    def _newest(paths):
1042bde8e466a4451c7319e3a072d118917957d6554Steve Block        return max([os.path.getmtime(path) for path in paths])
1052bde8e466a4451c7319e3a072d118917957d6554Steve Block
1062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochdef format_for_port(port):
1082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return {
1092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        'mac': 'xcode',
1102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        'gtk': 'filelist',
1112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        'win': 'msvs',
1122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }[port] # Valid port is required.
1132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1152bde8e466a4451c7319e3a072d118917957d6554Steve BlockPROJECTS = [
1162bde8e466a4451c7319e3a072d118917957d6554Steve Block    Project("JavaScriptCore"),
1172bde8e466a4451c7319e3a072d118917957d6554Steve Block    Project("WebCore"),
1182bde8e466a4451c7319e3a072d118917957d6554Steve Block]
1192bde8e466a4451c7319e3a072d118917957d6554Steve Block
1202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochdef projects_to_generate(port):
1212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    should_generate = [project for project in PROJECTS if project.should_generate(port)]
1222bde8e466a4451c7319e3a072d118917957d6554Steve Block    already_generated = [project.name() for project in set(PROJECTS) - set(should_generate)]
1232bde8e466a4451c7319e3a072d118917957d6554Steve Block
1242bde8e466a4451c7319e3a072d118917957d6554Steve Block    if already_generated:
1252bde8e466a4451c7319e3a072d118917957d6554Steve Block        print "Not generating %s because the generated files exist and are newer than the GYP files." % ', '.join(already_generated)
1262bde8e466a4451c7319e3a072d118917957d6554Steve Block        print "Pass --regenerate-projects to override."
1272bde8e466a4451c7319e3a072d118917957d6554Steve Block
1282bde8e466a4451c7319e3a072d118917957d6554Steve Block    return should_generate
12981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
13181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochdef main():
1322bde8e466a4451c7319e3a072d118917957d6554Steve Block    chdir_to_source()
1332bde8e466a4451c7319e3a072d118917957d6554Steve Block
1342bde8e466a4451c7319e3a072d118917957d6554Steve Block    parser = OptionParser()
1352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    parser.add_option("--port", dest="port", action="store", default="mac", # Default to Mac for now
1362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                      help="Which port to generate for.")
1372bde8e466a4451c7319e3a072d118917957d6554Steve Block    parser.add_option("--regenerate-projects", dest="regenerate_projects",
1382bde8e466a4451c7319e3a072d118917957d6554Steve Block                      default=False, action="store_true",
1392bde8e466a4451c7319e3a072d118917957d6554Steve Block                      help="Generate all project files even if they appear to be up to date.")
1402bde8e466a4451c7319e3a072d118917957d6554Steve Block    (options, args) = parser.parse_args()
1412bde8e466a4451c7319e3a072d118917957d6554Steve Block
1422bde8e466a4451c7319e3a072d118917957d6554Steve Block    projects = PROJECTS
1432bde8e466a4451c7319e3a072d118917957d6554Steve Block    if not options.regenerate_projects:
1442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        projects = projects_to_generate(options.port)
14581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1462bde8e466a4451c7319e3a072d118917957d6554Steve Block    for project in projects:
1472bde8e466a4451c7319e3a072d118917957d6554Steve Block        print "Generating %s." % project.name()
1482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        project.generate(options.port)
1492daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
15081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
15181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochif __name__ == "__main__":
15281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    main()
153