From 986c94a9dbf47043bb0d346fb5cde86ab10feea6 Mon Sep 17 00:00:00 2001 From: "thakis@chromium.org" Date: Tue, 11 Sep 2012 22:19:08 +0000 Subject: ninja: Survive case-only file renames on case-insensitive filesystems. See https://github.com/martine/ninja/issues/402 for more information. Review URL: https://chromiumcodereview.appspot.com/10907140 git-svn-id: http://gyp.googlecode.com/svn/trunk@1494 78cadc50-ecff-11dd-a971-7dbc132099af --- pylib/gyp/generator/ninja.py | 19 ++++++++++++---- test/rename/extension/file.c | 2 ++ test/rename/extension/file.cc | 2 ++ test/rename/extension/test.gyp | 13 +++++++++++ test/rename/filecase/file.c | 1 + test/rename/filecase/test-casesensitive.gyp | 15 +++++++++++++ test/rename/filecase/test.gyp | 14 ++++++++++++ test/rename/gyptest-extension.py | 28 +++++++++++++++++++++++ test/rename/gyptest-filecase.py | 35 +++++++++++++++++++++++++++++ 9 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 test/rename/extension/file.c create mode 100644 test/rename/extension/file.cc create mode 100644 test/rename/extension/test.gyp create mode 100644 test/rename/filecase/file.c create mode 100644 test/rename/filecase/test-casesensitive.gyp create mode 100644 test/rename/filecase/test.gyp create mode 100644 test/rename/gyptest-extension.py create mode 100644 test/rename/gyptest-filecase.py diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py index 4921e147..4571c25e 100644 --- a/pylib/gyp/generator/ninja.py +++ b/pylib/gyp/generator/ninja.py @@ -354,7 +354,8 @@ class NinjaWriter: self.ninja.newline() return targets[0] - def WriteSpec(self, spec, config_name, generator_flags): + def WriteSpec(self, spec, config_name, generator_flags, + case_sensitive_filesystem): """The main entry point for NinjaWriter: write the build rules for a spec. Returns a Target object, which represents the output paths for this spec. @@ -428,7 +429,8 @@ class NinjaWriter: self.xcode_settings, self.GypPathToNinja, lambda path, lang: self.GypPathToUniqueOutput(path + '-' + lang)) link_deps = self.WriteSources( - config_name, config, sources, compile_depends_stamp, pch) + config_name, config, sources, compile_depends_stamp, pch, + case_sensitive_filesystem) # Some actions/rules output 'sources' that are already object files. link_deps += [self.GypPathToNinja(f) for f in sources if f.endswith(self.obj_ext)] @@ -705,7 +707,7 @@ class NinjaWriter: bundle_depends.append(out) def WriteSources(self, config_name, config, sources, predepends, - precompiled_header): + precompiled_header, case_sensitive_filesystem): """Write build rules to compile all of |sources|.""" if self.toolset == 'host': self.ninja.variable('ar', '$ar_host') @@ -798,6 +800,12 @@ class NinjaWriter: continue input = self.GypPathToNinja(source) output = self.GypPathToUniqueOutput(filename + obj_ext) + # Ninja's depfile handling gets confused when the case of a filename + # changes on a case-insensitive file system. To work around that, always + # convert .o filenames to lowercase on such file systems. See + # https://github.com/martine/ninja/issues/402 for details. + if not case_sensitive_filesystem: + output = output.lower() implicit = precompiled_header.GetObjDependencies([input], [output]) self.ninja.build(output, command, input, implicit=[gch for _, _, gch in implicit], @@ -1296,6 +1304,8 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, master_ninja = ninja_syntax.Writer( OpenOutput(os.path.join(toplevel_build, 'build.ninja')), width=120) + case_sensitive_filesystem = not os.path.exists( + os.path.join(toplevel_build, 'BUILD.NINJA')) # Put build-time support tools in out/{config_name}. gyp.common.CopyTool(flavor, toplevel_build) @@ -1682,7 +1692,8 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, flavor, abs_build_dir=abs_build_dir) master_ninja.subninja(output_file) - target = writer.WriteSpec(spec, config_name, generator_flags) + target = writer.WriteSpec( + spec, config_name, generator_flags, case_sensitive_filesystem) if target: if name != target.FinalOutput() and spec['toolset'] == 'target': target_short_names.setdefault(name, []).append(target) diff --git a/test/rename/extension/file.c b/test/rename/extension/file.c new file mode 100644 index 00000000..5241aebb --- /dev/null +++ b/test/rename/extension/file.c @@ -0,0 +1,2 @@ +#include +int main() { printf("C\n"); return 0; } diff --git a/test/rename/extension/file.cc b/test/rename/extension/file.cc new file mode 100644 index 00000000..e6c50f7d --- /dev/null +++ b/test/rename/extension/file.cc @@ -0,0 +1,2 @@ +#include +int main() { printf("C++\n"); } diff --git a/test/rename/extension/test.gyp b/test/rename/extension/test.gyp new file mode 100644 index 00000000..16acdfb2 --- /dev/null +++ b/test/rename/extension/test.gyp @@ -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. +{ + 'targets': [ + { + 'target_name': 'extrename', + 'type': 'executable', + 'sources': [ 'file.c', ], + }, + ], +} + diff --git a/test/rename/filecase/file.c b/test/rename/filecase/file.c new file mode 100644 index 00000000..237c8ce1 --- /dev/null +++ b/test/rename/filecase/file.c @@ -0,0 +1 @@ +int main() {} diff --git a/test/rename/filecase/test-casesensitive.gyp b/test/rename/filecase/test-casesensitive.gyp new file mode 100644 index 00000000..48eaa6eb --- /dev/null +++ b/test/rename/filecase/test-casesensitive.gyp @@ -0,0 +1,15 @@ +# 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. +{ + 'targets': [ + { + 'target_name': 'filecaserename_sensitive', + 'type': 'executable', + 'sources': [ + 'FiLe.c', + 'fIlE.c', + ], + }, + ], +} diff --git a/test/rename/filecase/test.gyp b/test/rename/filecase/test.gyp new file mode 100644 index 00000000..eaee9337 --- /dev/null +++ b/test/rename/filecase/test.gyp @@ -0,0 +1,14 @@ +# 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. +{ + 'targets': [ + { + 'target_name': 'filecaserename', + 'type': 'executable', + 'sources': [ + 'file.c', + ], + }, + ], +} diff --git a/test/rename/gyptest-extension.py b/test/rename/gyptest-extension.py new file mode 100644 index 00000000..03b7e1c7 --- /dev/null +++ b/test/rename/gyptest-extension.py @@ -0,0 +1,28 @@ +#!/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. + +""" +Checks that files whose extension changes get rebuilt correctly. +""" + +import os +import TestGyp + +# .c -> .cc renames don't work with make. # XXX +test = TestGyp.TestGyp()#formats=['!make']) +CHDIR = 'extension' +test.run_gyp('test.gyp', chdir=CHDIR) +test.build('test.gyp', test.ALL, chdir=CHDIR) +test.run_built_executable('extrename', stdout="C\n", chdir=CHDIR) + +test.write('extension/test.gyp', + test.read('extension/test.gyp').replace('file.c', 'file.cc')) +test.run_gyp('test.gyp', chdir=CHDIR) +test.build('test.gyp', test.ALL, chdir=CHDIR) +test.run_built_executable('extrename', stdout="C++\n", chdir=CHDIR) + +test.pass_test() + diff --git a/test/rename/gyptest-filecase.py b/test/rename/gyptest-filecase.py new file mode 100644 index 00000000..daed5180 --- /dev/null +++ b/test/rename/gyptest-filecase.py @@ -0,0 +1,35 @@ +#!/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. + +""" +Checks that files whose file case changes get rebuilt correctly. +""" + +import os +import TestGyp + +test = TestGyp.TestGyp() +CHDIR = 'filecase' +test.run_gyp('test.gyp', chdir=CHDIR) +test.build('test.gyp', test.ALL, chdir=CHDIR) + +os.rename('filecase/file.c', 'filecase/fIlE.c') +test.write('filecase/test.gyp', + test.read('filecase/test.gyp').replace('file.c', 'fIlE.c')) +test.run_gyp('test.gyp', chdir=CHDIR) +test.build('test.gyp', test.ALL, chdir=CHDIR) + + +# Check that having files that differ just in their case still work on +# case-sensitive file systems. +test.write('filecase/FiLe.c', 'int f(); int main() { return f(); }') +test.write('filecase/fIlE.c', 'int f() { return 42; }') +is_case_sensitive = test.read('filecase/FiLe.c') != test.read('filecase/fIlE.c') +if is_case_sensitive: + test.run_gyp('test-casesensitive.gyp', chdir=CHDIR) + test.build('test-casesensitive.gyp', test.ALL, chdir=CHDIR) + +test.pass_test() -- cgit v1.2.3