From 1ac32258fcc33039f78f28b9b6218ae278bf1f05 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Thu, 15 Dec 2011 15:10:35 +0000 Subject: [PATCH] Bug 629668 - Don't rebuild IPDL files when not necessary; r=cjones --- ipc/ipdl/Makefile.in | 6 ++++- ipc/ipdl/ipdl.py | 10 ++++++-- ipc/ipdl/ipdl/__init__.py | 40 ++++++++++++++++++----------- ipc/ipdl/ipdl/mgen.py | 54 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 18 deletions(-) create mode 100644 ipc/ipdl/ipdl/mgen.py diff --git a/ipc/ipdl/Makefile.in b/ipc/ipdl/Makefile.in index c42899f70af8..7bc05ec8a86a 100644 --- a/ipc/ipdl/Makefile.in +++ b/ipc/ipdl/Makefile.in @@ -112,15 +112,19 @@ include $(topsrcdir)/config/config.mk include $(topsrcdir)/ipc/chromium/chromium-config.mk include $(topsrcdir)/config/rules.mk +-include $(ALL_IPDLSRCS:.ipdl=.ipdl.depends) # NB: the IPDL compiler manages .ipdl-->.h/.cpp dependencies itself, # which is why we don't have explicit .h/.cpp targets here -export:: $(ALL_IPDLSRCS) +export:: $(CPPSRCS) + +$(CPPSRCS) : $(ALL_IPDLSRCS) $(PYTHON) $(topsrcdir)/config/pythonpath.py \ -I$(topsrcdir)/other-licenses/ply \ $(srcdir)/ipdl.py \ --outheaders-dir=_ipdlheaders \ --outcpp-dir=. \ + --dependencies \ $(IPDLDIRS:%=-I$(topsrcdir)/%) \ $^ diff --git a/ipc/ipdl/ipdl.py b/ipc/ipdl/ipdl.py index e47cd108a3d1..27dd461791c9 100755 --- a/ipc/ipdl/ipdl.py +++ b/ipc/ipdl/ipdl.py @@ -59,12 +59,15 @@ op.add_option('-o', '--outcpp-dir', dest='cppdir', default='.', A protocol Foo in the namespace bar will cause the sources cppdir/FooParent.cpp, cppdir/FooChild.cpp to be generated""") +op.add_option('-m', '--dependencies', dest='emitdependencies', default=False, action='store_true', + help="Emit Makefile dependencies for incremental rebuilds") options, files = op.parse_args() _verbosity = options.verbosity headersdir = options.headersdir cppdir = options.cppdir +emitdependencies = options.emitdependencies includedirs = [ os.path.abspath(incdir) for incdir in options.includedirs ] if not len(files): @@ -106,13 +109,16 @@ for f in files: log(3, ' pretty printed code:') ipdl.genipdl(ast, codedir) + if emitdependencies == 1: + ipdl.genm(ast, cppdir, normalizedFilename(f)) + # Second pass: generate code for f in files: # Read from parser cache filename = normalizedFilename(f) ast = ipdl.parse(None, filename, includedirs=includedirs) ipdl.gencxx(filename, ast, headersdir, cppdir) - + allprotocols.append('%sMsgStart' % ast.protocol.name) allprotocols.sort() @@ -140,5 +146,5 @@ COMPILE_ASSERT(LastMsgIndex <= 65536, need_to_update_IPC_MESSAGE_MACRO); #endif // ifndef IPCMessageStart_h """ -ipdl.writeifmodified(ipcmsgstart.getvalue(), +ipdl.writetofile(ipcmsgstart.getvalue(), os.path.join(headersdir, 'IPCMessageStart.h')) diff --git a/ipc/ipdl/ipdl/__init__.py b/ipc/ipdl/ipdl/__init__.py index fa0cc7bf4ff0..db3f253de9ac 100644 --- a/ipc/ipdl/ipdl/__init__.py +++ b/ipc/ipdl/ipdl/__init__.py @@ -30,12 +30,13 @@ # # ***** END LICENSE BLOCK ***** -__all__ = [ 'gencxx', 'genipdl', 'parse', 'typecheck', 'writeifmodified' ] +__all__ = [ 'gencxx', 'genipdl', 'parse', 'typecheck', 'writetofile' ] -import os, sys +import os, sys, errno from cStringIO import StringIO from ipdl.cgen import IPDLCodeGen +from ipdl.mgen import DependGen from ipdl.lower import LowerToCxx from ipdl.parser import Parser from ipdl.type import TypeCheck @@ -72,23 +73,32 @@ def gencxx(ipdlfilename, ast, outheadersdir, outcppdir): + [ resolveCpp(cpp) for cpp in cpps ]): tempfile = StringIO() CxxCodeGen(tempfile).cgen(ast) - writeifmodified(tempfile.getvalue(), filename) + writetofile(tempfile.getvalue(), filename) def genipdl(ast, outdir): return IPDLCodeGen().cgen(ast) -def writeifmodified(contents, file): - dir = os.path.dirname(file) - os.path.exists(dir) or os.makedirs(dir) +def genm(ast, dir, filename): + tempfile = StringIO() + DependGen(tempfile).mgen(ast) + filename = dir + "/" + os.path.basename(filename) + ".depends" + writetofile(tempfile.getvalue(), filename) - oldcontents = None - if os.path.exists(file): - fd = open(file, 'rb') - oldcontents = fd.read() - fd.close() - if oldcontents != contents: - fd = open(file, 'wb') - fd.write(contents) - fd.close() + +def writetofile(contents, file): + dir = os.path.dirname(file) + + # Guard against race condition by using Try instead + # of |os.path.exists(dir) or os.makedirs(dir)| + try: + os.makedirs(dir) + except OSError, ex: + if ex.errno != errno.EEXIST: + raise ex + # else directory already exists. silently ignore and continue + + fd = open(file, 'wb') + fd.write(contents) + fd.close() diff --git a/ipc/ipdl/ipdl/mgen.py b/ipc/ipdl/ipdl/mgen.py new file mode 100644 index 000000000000..e68c5f07a55e --- /dev/null +++ b/ipc/ipdl/ipdl/mgen.py @@ -0,0 +1,54 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# Contributor(s): +# Benoit Girard +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +import sys + +from ipdl.cgen import CodePrinter +from ipdl.cxx.ast import TypeArray, Visitor + +class DependGen(CodePrinter, Visitor): + def __init__(self, outf=sys.stdout, indentCols=4): + CodePrinter.__init__(self, outf, indentCols) + + def mgen(self, cxxfile): + cxxfile.accept(self) + + def visitTranslationUnit(self, tu): + self.write(tu.filename) + self.write(": ") + + for pinc in tu.protocolIncludes: + self.write(pinc.file) + self.write(" ") + + self.println(); +