Skip to content

Commit

Permalink
Merge branch 'master' of github.com:martine/ninja
Browse files Browse the repository at this point in the history
  • Loading branch information
evmar committed Aug 13, 2012
2 parents 77b078b + 356f31a commit 6c04f14
Show file tree
Hide file tree
Showing 11 changed files with 560 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,6 +1,7 @@
*.pyc *.pyc
*.exe *.exe
*.pdb *.pdb
*.ilk
TAGS TAGS
/build /build
/build.ninja /build.ninja
Expand Down
26 changes: 17 additions & 9 deletions configure.py
Expand Up @@ -97,7 +97,9 @@ def cxx(name, **kwargs):
return n.build(built(name + objext), 'cxx', src(name + '.cc'), **kwargs) return n.build(built(name + objext), 'cxx', src(name + '.cc'), **kwargs)
def binary(name): def binary(name):
if platform in ('mingw', 'windows'): if platform in ('mingw', 'windows'):
return name + '.exe' exe = name + '.exe'
n.build(name, 'phony', exe)
return exe
return name return name


n.variable('builddir', 'build') n.variable('builddir', 'build')
Expand All @@ -108,8 +110,13 @@ def binary(name):
n.variable('ar', configure_env.get('AR', 'ar')) n.variable('ar', configure_env.get('AR', 'ar'))


if platform == 'windows': if platform == 'windows':
cflags = ['/nologo', '/Zi', '/W4', '/WX', '/wd4530', '/wd4100', '/wd4706', cflags = ['/nologo', # Don't print startup banner.
'/wd4512', '/wd4800', '/wd4702', '/wd4819', '/GR-', '/Zi', # Create pdb with debug info.
'/W4', # Highest warning level.
'/WX', # Warnings as errors.
'/wd4530', '/wd4100', '/wd4706',
'/wd4512', '/wd4800', '/wd4702', '/wd4819',
'/GR-', # Disable RTTI.
# Disable size_t -> int truncation warning. # Disable size_t -> int truncation warning.
# We never have strings or arrays larger than 2**31. # We never have strings or arrays larger than 2**31.
'/wd4267', '/wd4267',
Expand Down Expand Up @@ -249,6 +256,8 @@ def shell_escape(str):
if platform in ('mingw', 'windows'): if platform in ('mingw', 'windows'):
objs += cxx('subprocess-win32') objs += cxx('subprocess-win32')
if platform == 'windows': if platform == 'windows':
objs += cxx('includes_normalize-win32')
objs += cxx('msvc_helper-win32')
objs += cxx('minidump-win32') objs += cxx('minidump-win32')
objs += cc('getopt') objs += cc('getopt')
else: else:
Expand All @@ -270,8 +279,6 @@ def shell_escape(str):
objs = cxx('ninja') objs = cxx('ninja')
ninja = n.build(binary('ninja'), 'link', objs, implicit=ninja_lib, ninja = n.build(binary('ninja'), 'link', objs, implicit=ninja_lib,
variables=[('libs', libs)]) variables=[('libs', libs)])
if 'ninja' not in ninja:
n.build('ninja', 'phony', ninja)
n.newline() n.newline()
all_targets += ninja all_targets += ninja


Expand All @@ -291,10 +298,10 @@ def shell_escape(str):
else: else:
gtest_cflags = '-fvisibility=hidden ' + gtest_all_incs gtest_cflags = '-fvisibility=hidden ' + gtest_all_incs
objs += n.build(built('gtest-all' + objext), 'cxx', objs += n.build(built('gtest-all' + objext), 'cxx',
os.path.join(path, 'src/gtest-all.cc'), os.path.join(path, 'src', 'gtest-all.cc'),
variables=[('cflags', gtest_cflags)]) variables=[('cflags', gtest_cflags)])
objs += n.build(built('gtest_main' + objext), 'cxx', objs += n.build(built('gtest_main' + objext), 'cxx',
os.path.join(path, 'src/gtest_main.cc'), os.path.join(path, 'src', 'gtest_main.cc'),
variables=[('cflags', gtest_cflags)]) variables=[('cflags', gtest_cflags)])


test_cflags = cflags + ['-DGTEST_HAS_RTTI=0', test_cflags = cflags + ['-DGTEST_HAS_RTTI=0',
Expand All @@ -318,14 +325,15 @@ def shell_escape(str):
'test', 'test',
'util_test']: 'util_test']:
objs += cxx(name, variables=[('cflags', test_cflags)]) objs += cxx(name, variables=[('cflags', test_cflags)])
if platform == 'windows':
for name in ['includes_normalize_test', 'msvc_helper_test']:
objs += cxx(name, variables=[('cflags', test_cflags)])


if platform != 'mingw' and platform != 'windows': if platform != 'mingw' and platform != 'windows':
test_libs.append('-lpthread') test_libs.append('-lpthread')
ninja_test = n.build(binary('ninja_test'), 'link', objs, implicit=ninja_lib, ninja_test = n.build(binary('ninja_test'), 'link', objs, implicit=ninja_lib,
variables=[('ldflags', test_ldflags), variables=[('ldflags', test_ldflags),
('libs', test_libs)]) ('libs', test_libs)])
if 'ninja_test' not in ninja_test:
n.build('ninja_test', 'phony', ninja_test)
n.newline() n.newline()
all_targets += ninja_test all_targets += ninja_test


Expand Down
115 changes: 115 additions & 0 deletions src/includes_normalize-win32.cc
@@ -0,0 +1,115 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "includes_normalize.h"

#include "string_piece.h"
#include "util.h"

#include <algorithm>
#include <iterator>
#include <sstream>

#include <windows.h>

namespace {

/// Return true if paths a and b are on the same Windows drive.
bool SameDrive(StringPiece a, StringPiece b) {
char a_absolute[_MAX_PATH];
char b_absolute[_MAX_PATH];
GetFullPathName(a.AsString().c_str(), sizeof(a_absolute), a_absolute, NULL);
GetFullPathName(b.AsString().c_str(), sizeof(b_absolute), b_absolute, NULL);
char a_drive[_MAX_DIR];
char b_drive[_MAX_DIR];
_splitpath(a_absolute, a_drive, NULL, NULL, NULL);
_splitpath(b_absolute, b_drive, NULL, NULL, NULL);
return _stricmp(a_drive, b_drive) == 0;
}

} // anonymous namespace

string IncludesNormalize::Join(const vector<string>& list, char sep) {
string ret;
for (size_t i = 0; i < list.size(); ++i) {
ret += list[i];
if (i != list.size() - 1)
ret += sep;
}
return ret;
}

vector<string> IncludesNormalize::Split(const string& input, char sep) {
vector<string> elems;
stringstream ss(input);
string item;
while (getline(ss, item, sep))
elems.push_back(item);
return elems;
}

string IncludesNormalize::ToLower(const string& s) {
string ret;
transform(s.begin(), s.end(), back_inserter(ret), tolower);
return ret;
}

string IncludesNormalize::AbsPath(StringPiece s) {
char result[_MAX_PATH];
GetFullPathName(s.AsString().c_str(), sizeof(result), result, NULL);
return result;
}

string IncludesNormalize::Relativize(StringPiece path, const string& start) {
vector<string> start_list = Split(AbsPath(start), '\\');
vector<string> path_list = Split(AbsPath(path), '\\');
int i;
for (i = 0; i < static_cast<int>(min(start_list.size(), path_list.size()));
++i) {
if (ToLower(start_list[i]) != ToLower(path_list[i]))
break;
}

vector<string> rel_list;
for (int j = 0; j < static_cast<int>(start_list.size() - i); ++j)
rel_list.push_back("..");
for (int j = i; j < static_cast<int>(path_list.size()); ++j)
rel_list.push_back(path_list[j]);
if (rel_list.size() == 0)
return ".";
return Join(rel_list, '\\');
}

string IncludesNormalize::Normalize(const string& input,
const char* relative_to) {
char copy[_MAX_PATH];
size_t len = input.size();
strncpy(copy, input.c_str(), input.size() + 1);
for (size_t j = 0; j < len; ++j)
if (copy[j] == '/')
copy[j] = '\\';
string err;
if (!CanonicalizePath(copy, &len, &err)) {
Warning("couldn't canonicalize '%s: %s\n", input.c_str(), err.c_str());
}
string curdir;
if (!relative_to) {
curdir = AbsPath(".");
relative_to = curdir.c_str();
}
StringPiece partially_fixed(copy, len);
if (!SameDrive(partially_fixed, relative_to))
return ToLower(partially_fixed.AsString());
return ToLower(Relativize(partially_fixed, relative_to));
}
35 changes: 35 additions & 0 deletions src/includes_normalize.h
@@ -0,0 +1,35 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>
#include <vector>
using namespace std;

struct StringPiece;

/// Utility functions for normalizing include paths on Windows.
/// TODO: this likely duplicates functionality of CanonicalizePath; refactor.
struct IncludesNormalize {
// Internal utilities made available for testing, maybe useful otherwise.
static string Join(const vector<string>& list, char sep);
static vector<string> Split(const string& input, char sep);
static string ToLower(const string& s);
static string AbsPath(StringPiece s);
static string Relativize(StringPiece path, const string& start);

/// Normalize by fixing slashes style, fixing redundant .. and . and makes the
/// path relative to |relative_to|. Case is normalized to lowercase on
/// Windows too.
static string Normalize(const string& input, const char* relative_to);
};
98 changes: 98 additions & 0 deletions src/includes_normalize_test.cc
@@ -0,0 +1,98 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "includes_normalize.h"

#include <gtest/gtest.h>

#include "test.h"
#include "util.h"

TEST(IncludesNormalize, Simple) {
EXPECT_EQ("b", IncludesNormalize::Normalize("a\\..\\b", NULL));
EXPECT_EQ("b", IncludesNormalize::Normalize("a\\../b", NULL));
EXPECT_EQ("a\\b", IncludesNormalize::Normalize("a\\.\\b", NULL));
EXPECT_EQ("a\\b", IncludesNormalize::Normalize("a\\./b", NULL));
}

namespace {

string GetCurDir() {
char buf[_MAX_PATH];
_getcwd(buf, sizeof(buf));
vector<string> parts = IncludesNormalize::Split(string(buf), '\\');
return parts[parts.size() - 1];
}

} // namespace

TEST(IncludesNormalize, WithRelative) {
string currentdir = IncludesNormalize::ToLower(GetCurDir());
EXPECT_EQ("c", IncludesNormalize::Normalize("a/b/c", "a/b"));
EXPECT_EQ("a", IncludesNormalize::Normalize(IncludesNormalize::AbsPath("a"), NULL));
EXPECT_EQ(string("..\\") + currentdir + string("\\a"),
IncludesNormalize::Normalize("a", "../b"));
EXPECT_EQ(string("..\\") + currentdir + string("\\a\\b"),
IncludesNormalize::Normalize("a/b", "../c"));
EXPECT_EQ("..\\..\\a", IncludesNormalize::Normalize("a", "b/c"));
EXPECT_EQ(".", IncludesNormalize::Normalize("a", "a"));
}

TEST(IncludesNormalize, Case) {
EXPECT_EQ("b", IncludesNormalize::Normalize("Abc\\..\\b", NULL));
EXPECT_EQ("bdef", IncludesNormalize::Normalize("Abc\\..\\BdEf", NULL));
EXPECT_EQ("a\\b", IncludesNormalize::Normalize("A\\.\\b", NULL));
EXPECT_EQ("a\\b", IncludesNormalize::Normalize("A\\./b", NULL));
EXPECT_EQ("a\\b", IncludesNormalize::Normalize("A\\.\\B", NULL));
EXPECT_EQ("a\\b", IncludesNormalize::Normalize("A\\./B", NULL));
}

TEST(IncludesNormalize, Join) {
vector<string> x;
EXPECT_EQ("", IncludesNormalize::Join(x, ':'));
x.push_back("alpha");
EXPECT_EQ("alpha", IncludesNormalize::Join(x, ':'));
x.push_back("beta");
x.push_back("gamma");
EXPECT_EQ("alpha:beta:gamma", IncludesNormalize::Join(x, ':'));
}

TEST(IncludesNormalize, Split) {
EXPECT_EQ("", IncludesNormalize::Join(IncludesNormalize::Split("", '/'), ':'));
EXPECT_EQ("a", IncludesNormalize::Join(IncludesNormalize::Split("a", '/'), ':'));
EXPECT_EQ("a:b:c", IncludesNormalize::Join(IncludesNormalize::Split("a/b/c", '/'), ':'));
}

TEST(IncludesNormalize, ToLower) {
EXPECT_EQ("", IncludesNormalize::ToLower(""));
EXPECT_EQ("stuff", IncludesNormalize::ToLower("Stuff"));
EXPECT_EQ("stuff and things", IncludesNormalize::ToLower("Stuff AND thINGS"));
EXPECT_EQ("stuff 3and thin43gs", IncludesNormalize::ToLower("Stuff 3AND thIN43GS"));
}

TEST(IncludesNormalize, DifferentDrive) {
EXPECT_EQ("stuff.h",
IncludesNormalize::Normalize("p:\\vs08\\stuff.h", "p:\\vs08"));
EXPECT_EQ("stuff.h",
IncludesNormalize::Normalize("P:\\vs08\\stuff.h", "p:\\vs08"));
EXPECT_EQ("p:\\vs08\\stuff.h",
IncludesNormalize::Normalize("P:\\vs08\\stuff.h", "c:\\vs08"));
EXPECT_EQ("p:\\vs08\\stuff.h",
IncludesNormalize::Normalize("P:\\vs08\\stuff.h", "D:\\stuff/things"));
EXPECT_EQ("p:\\vs08\\stuff.h",
IncludesNormalize::Normalize("P:/vs08\\stuff.h", "D:\\stuff/things"));
// TODO: this fails; fix it.
//EXPECT_EQ("P:\\wee\\stuff.h",
// IncludesNormalize::Normalize("P:/vs08\\../wee\\stuff.h", "D:\\stuff/things"));
}

0 comments on commit 6c04f14

Please sign in to comment.