Skip to content

Commit

Permalink
version 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
evmar committed Sep 13, 2012
2 parents 50af448 + 06fa623 commit 7096bf1
Show file tree
Hide file tree
Showing 58 changed files with 2,177 additions and 709 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
*.pyc
*.exe
*.pdb
*.ilk
TAGS
/build
/build.ninja
Expand All @@ -12,3 +14,4 @@ TAGS
/graph.png
/doc/manual.html
/doc/doxygen
/gtest-1.6.0
76 changes: 0 additions & 76 deletions HACKING

This file was deleted.

167 changes: 167 additions & 0 deletions HACKING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
## Basic overview

`./configure.py` generates the `build.ninja` files used to build
ninja. It accepts various flags to adjust build parameters.

The primary build target of interest is `ninja`, but when hacking on
Ninja your changes should be testable so it's more useful to build
and run `ninja_test` when developing.

(`./bootstrap.py` creates a bootstrap `ninja` and runs the above
process; it's only necessary to run if you don't have a copy of
`ninja` to build with.)

### Adjusting build flags

Build in "debug" mode while developing (disables optimizations and builds
way faster on Windows):

./configure.py --debug

To use clang, set `CXX`:

CXX=clang++ ./configure.py

## How to successfully make changes to Ninja

Github pull requests are convenient for me to merge (I can just click
a button and it's all handled server-side), but I'm also comfortable
accepting pre-github git patches (via `send-email` etc.).

Good pull requests have all of these attributes:

* Are scoped to one specific issue
* Include a test to demonstrate their correctness
* Update the docs where relevant
* Match the Ninja coding style (see below)
* Don't include a mess of "oops, fix typo" commits

These are typically merged without hesitation. If a change is lacking
any of the above I usually will ask you to fix it, though there are
obvious exceptions (fixing typos in comments don't need tests).

I am very wary of changes that increase the complexity of Ninja (in
particular, new build file syntax or command-line flags) or increase
the maintenance burden of Ninja. Ninja is already successfully in use
by hundreds of developers for large projects and it already achieves
(most of) the goals I set out for it to do. It's probably best to
discuss new feature ideas on the mailing list before I shoot down your
patch.

## Testing

### Installing gtest

The `ninja_test` binary, containing all the tests, depends on the
googletest (gtest) library.

* On older Ubuntus it'll install as libraries into `/usr/lib`:

apt-get install libgtest

* On newer Ubuntus it's only distributed as source

apt-get install libgtest-dev
./configure --with-gtest=/usr/src/gtest

* Otherwise you need to download it, unpack it, and pass
`--with-gtest` to `configure.py`. Get it from [its downloads
page](http://code.google.com/p/googletest/downloads/list); [this
direct download link might work
too](http://googletest.googlecode.com/files/gtest-1.6.0.zip).

### Test-driven development

Set your build command to

./ninja ninja_test && ./ninja_test --gtest_filter=MyTest.Name

now you can repeatedly run that while developing until the tests pass
(I frequently set it as my compilation command in Emacs). Remember to
build "all" before committing to verify the other source still works!

## Testing performance impact of changes

If you have a Chrome build handy, it's a good test case. Otherwise,
[the github downoads page](https://github.com/martine/ninja/downloads)
has a copy of the Chrome build files (and depfiles). You can untar
that, then run

path/to/my/ninja chrome

and compare that against a baseline Ninja.

There's a script at `misc/measure.py` that repeatedly runs a command like
the above (to address variance) and summarizes its runtime. E.g.

path/to/misc/measure.py path/to/my/ninja chrome

For changing the depfile parser, you can also build `parser_perftest`
and run that directly on some representative input files.

## Coding guidelines

Generally it's the [Google C++ coding style][], but in brief:

* Function name are camelcase.
* Member methods are camelcase, expect for trivial getters which are
underscore separated.
* Local variables are underscore separated.
* Member variables are underscore separated and suffixed by an extra
underscore.
* Two spaces indentation.
* Opening braces is at the end of line.
* Lines are 80 columns maximum.
* All source files should have the Google Inc. license header.

[Google C++ coding style]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml

## Documentation

### Style guidelines

* Use `///` for doxygen.
* Use `\a` to refer to arguments.
* It's not necessary to document each argument, especially when they're
relatively self-evident (e.g. in `CanonicalizePath(string* path, string* err)`,
the arguments are hopefully obvious)

### Building the manual

sudo apt-get install asciidoc --no-install-recommends
./ninja manual

### Building the code documentation

sudo apt-get install doxygen
./ninja doxygen

## Building for Windows

While developing, it's helpful to copy `ninja.exe` to another name like
`n.exe`; otherwise, rebuilds will be unable to write `ninja.exe` because
it's locked while in use.

### Via Visual Studio

* Install Visual Studio (Express is fine), [Python for Windows][],
and (if making changes) googletest (see above instructions)
* In a Visual Studio command prompt: `python bootstrap.py`

[Python for Windows]: http://www.python.org/getit/windows/

### Via mingw on Windows (not well supported)

* Install mingw, msys, and python
* In the mingw shell, put Python in your path, and `python bootstrap.py`
* To reconfigure, run `python configure.py`
* Remember to strip the resulting executable if size matters to you

### Via mingw on Linux (not well supported)

* `sudo apt-get install gcc-mingw32 wine`
* `export CC=i586-mingw32msvc-cc CXX=i586-mingw32msvc-c++ AR=i586-mingw32msvc-ar`
* `./configure.py --platform=mingw --host=linux`
* Build `ninja.exe` using a Linux ninja binary: `/path/to/linux/ninja`
* Run: `./ninja.exe` (implicitly runs through wine(!))

1 change: 1 addition & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ help.
There is no installation step. The only file of interest to a user
is the resulting ninja binary.

If you're interested in making changes to Ninja, read HACKING.md first.
54 changes: 43 additions & 11 deletions bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@
import glob
import errno
import shlex
import shutil
import subprocess

os.chdir(os.path.dirname(os.path.abspath(__file__)))

parser = OptionParser()
parser.add_option('--verbose', action='store_true',
help='enable verbose build',)
parser.add_option('--x64', action='store_true',
help='force 64-bit build (Windows)',)
(options, conf_args) = parser.parse_args()

def run(*args, **kwargs):
Expand Down Expand Up @@ -61,7 +64,7 @@ def run(*args, **kwargs):
continue

if sys.platform.startswith('win32'):
if filename == 'subprocess.cc':
if src.endswith('-posix.cc'):
continue
else:
if src.endswith('-win32.cc'):
Expand All @@ -74,12 +77,20 @@ def run(*args, **kwargs):

vcdir = os.environ.get('VCINSTALLDIR')
if vcdir:
args = [os.path.join(vcdir, 'bin', 'cl.exe'), '/nologo', '/EHsc', '/DNOMINMAX']
if options.x64:
cl = [os.path.join(vcdir, 'bin', 'amd64', 'cl.exe')]
else:
cl = [os.path.join(vcdir, 'bin', 'cl.exe')]
args = cl + ['/nologo', '/EHsc', '/DNOMINMAX']
else:
args = shlex.split(os.environ.get('CXX', 'g++'))
args.extend(['-Wno-deprecated',
'-DNINJA_PYTHON="' + sys.executable + '"',
'-DNINJA_BOOTSTRAP'])
cflags.extend(['-Wno-deprecated',
'-DNINJA_PYTHON="' + sys.executable + '"',
'-DNINJA_BOOTSTRAP'])
if sys.platform.startswith('win32'):
cflags.append('-D_WIN32_WINNT=0x0501')
if options.x64:
cflags.append('-m64')
args.extend(cflags)
args.extend(ldflags)
binary = 'ninja.bootstrap'
Expand All @@ -100,9 +111,30 @@ def run(*args, **kwargs):
if options.verbose:
verbose = ['-v']

print 'Building ninja using itself...'
run([sys.executable, 'configure.py'] + conf_args)
run(['./' + binary] + verbose)
os.unlink(binary)

print 'Done!'
if sys.platform.startswith('win32'):
print 'Building ninja using itself...'
run([sys.executable, 'configure.py', '--with-ninja=%s' % binary] +
conf_args)
run(['./' + binary] + verbose)

# Copy the new executable over the bootstrap one.
shutil.copyfile('ninja.exe', binary)

# Clean up.
for obj in glob.glob('*.obj'):
os.unlink(obj)

print """
Done!
Note: to work around Windows file locking, where you can't rebuild an
in-use binary, to run ninja after making any changes to build ninja itself
you should run ninja.bootstrap instead. Your build is also configured to
use ninja.bootstrap.exe as the MSVC helper; see the --with-ninja flag of
the --help output of configure.py."""
else:
print 'Building ninja using itself...'
run([sys.executable, 'configure.py'] + conf_args)
run(['./' + binary] + verbose)
os.unlink(binary)
print 'Done!'
Loading

0 comments on commit 7096bf1

Please sign in to comment.