0

[Docs]: Updates to match style guide.

TBR=nodir
BUG=524256

Review URL: https://codereview.chromium.org/1314513007

Cr-Commit-Position: refs/heads/master@{#346334}
This commit is contained in:
andybons
2015-08-30 19:24:51 -07:00
committed by Commit bot
parent 9c4a5643f7
commit 22afb31800
9 changed files with 839 additions and 501 deletions

@ -9,17 +9,18 @@ instructions below for setting up either a physical device or an emulator.
In order to allow the ADB to connect to the device, you must enable USB
debugging:
* Before Android 4.1 (Jelly Bean):
* Go to "System Settings"
* Go to "Developer options"
* Check "USB debugging".
* Un-check "Verify apps over USB".
* On Jelly Bean, developer options are hidden by default. To unhide them:
* Go to "About phone"
* Tap 10 times on "Build number"
* The "Developer options" menu will now be available.
* Check "USB debugging".
* Un-check "Verify apps over USB".
* Before Android 4.1 (Jelly Bean):
* Go to "System Settings"
* Go to "Developer options"
* Check "USB debugging".
* Un-check "Verify apps over USB".
* On Jelly Bean, developer options are hidden by default. To unhide them:
* Go to "About phone"
* Tap 10 times on "Build number"
* The "Developer options" menu will now be available.
* Check "USB debugging".
* Un-check "Verify apps over USB".
### Screen
@ -33,7 +34,7 @@ tests will break in exciting ways if stay awake is off).
### Enable Asserts!
`adb shell setprop debug.assert 1`
adb shell setprop debug.assert 1
### Disable Verify Apps
@ -94,14 +95,15 @@ It may not be immediately obvious where your test code gets compiled to, so here
are some general rules:
* If your test code lives under /content, it will probably be built as part of
the content\_shell\_test\_apk * If your test code lives under /chrome (or
higher), it will probably be built as part of the chrome\_public\_test\_apk *
(Please fill in more details here if you know them).
the content_shell_test_apk
* If your test code lives under /chrome (or higher), it will probably be built
as part of the chrome_public_test_apk
* (Please fill in more details here if you know them).
NB: We used to call the chrome\_public\_test\_apk the
chromium\_shell\_test\_apk. There may still be references to this kicking
around, but wherever you see chromium\_shell\_test you should replace with
chrome\_public\_test.
NB: We used to call the chrome_public_test_apk the
chromium_shell_test_apk. There may still be references to this kicking
around, but wherever you see chromium_shell_test you should replace with
chrome_public_test.
Once you know what to build, just do it like you normally would build anything
else, e.g.: `ninja -C out/Release chrome_public_test_apk`

@ -1,18 +1,26 @@
The Chromium build system is a complicated beast of a system, and it is not very well documented beyond the basics of getting the source and building the Chromium product. This page has more advanced information about the build system.
# Common Build Tasks
If you're new to Chromium development, read the [getting started guides](http://dev.chromium.org/developers/how-tos/get-the-code).
The Chromium build system is a complicated beast of a system, and it is not very
well documented beyond the basics of getting the source and building the
Chromium product. This page has more advanced information about the build
system.
If you're new to Chromium development, read the
[getting started guides](http://dev.chromium.org/developers/how-tos/get-the-code).
[TOC]
# Faster Builds
## Faster Builds
## Components Build
### Components Build
A non-standard build configuration is to use dynamic linking instead of static linking for the various modules in the Chromium codebase. This results in significantly faster link times, but is a divergence from what is shipped and primarily tested. To enable the [component build](http://www.chromium.org/developers/how-tos/component-build):
A non-standard build configuration is to use dynamic linking instead of static
linking for the various modules in the Chromium codebase. This results in
significantly faster link times, but is a divergence from what is shipped and
primarily tested. To enable the
[component build](http://www.chromium.org/developers/how-tos/component-build):
```
$ GYP_DEFINES="component=shared_library" gclient runhooks
```
$ GYP_DEFINES="component=shared_library" gclient runhooks
or
@ -21,36 +29,40 @@ C:\...\src>set GYP_DEFINES=component=shared_library
C:\...\src>gclient runhooks
```
### Windows: Debug Builds Link Faster
## Windows: Debug Builds Link Faster
On Windows if using the components build, building in debug mode will generally
link faster. This is because in debug mode, the linker works incrementally. In
release mode, a full link is performed each time.
On Windows if using the components build, building in debug mode will generally link faster. This is because in debug mode, the linker works incrementally. In release mode, a full link is performed each time.
### Mac: Disable Release Mode Stripping
## Mac: Disable Release Mode Stripping
On Mac, if building in release mode, one of the final build steps will be to
strip the build products and create dSYM files. This process can slow down your
incremental builds, but it can be disabled with the following define:
On Mac, if building in release mode, one of the final build steps will be to strip the build products and create dSYM files. This process can slow down your incremental builds, but it can be disabled with the following define:
$ GYP_DEFINES="mac_strip_release=0" gclient runhooks
```
$ GYP_DEFINES="mac_strip_release=0" gclient runhooks
```
### Mac: DCHECKs in Release Mode
## Mac: DCHECKs in Release Mode
DCHECKs are only designed to be run in debug builds. But building in release
mode on Mac is significantly faster. You can have your cake and eat it too by
building release mode with DCHECKs enabled using the following define:
DCHECKs are only designed to be run in debug builds. But building in release mode on Mac is significantly faster. You can have your cake and eat it too by building release mode with DCHECKs enabled using the following define:
$ GYP_DEFINES="dcheck_always_on=1" gclient runhooks
```
$ GYP_DEFINES="dcheck_always_on=1" gclient runhooks
```
### Linux
## Linux
Linux has its own page on [making the build faster](linux_faster_builds.md).
Linux has its own page on [making the build faster](https://code.google.com/p/chromium/wiki/LinuxFasterBuilds).
## Configuring the Build
# Configuring the Build
### Environment Variables
## Environment Variables
There are various environment variables that can be passed to the metabuild
system GYP when generating project files. This is a summary of them:
There are various environment variables that can be passed to the metabuild system GYP when generating project files. This is a summary of them:
TODO(andybons): Convert to list.
| GYP\_DEFINES | A set of key=value pairs separated by space that will set default values of variables used in .gyp and .gypi files |
|:-------------|:-------------------------------------------------------------------------------------------------------------------|
@ -58,73 +70,84 @@ There are various environment variables that can be passed to the metabuild syst
| GYP\_GENERATOR\_FLAGS | Flags that are passed down to the tool that generates the build-system specific files |
| GYP\_GENERATOR\_OUTPUT | The directory that the top-level build output directory is relative to |
Note also that GYP uses CPPFLAGS, CFLAGS, and CXXFLAGS when generating ninja files (the values at build time = ninja run time are _not_ used); see [gyp/generator/ninja.py](https://code.google.com/p/chromium/codesearch#chromium/src/tools/gyp/pylib/gyp/generator/ninja.py&q=cxxflags).
Note also that GYP uses CPPFLAGS, CFLAGS, and CXXFLAGS when generating ninja
files (the values at build time = ninja run time are _not_ used); see
[gyp/generator/ninja.py](https://code.google.com/p/chromium/codesearch#chromium/src/tools/gyp/pylib/gyp/generator/ninja.py&q=cxxflags).
## Variable Files
### Variable Files
If you want to keep a set of variables established, there are a couple of magic files that GYP reads:
If you want to keep a set of variables established, there are a couple of magic
files that GYP reads:
### chromium.gyp\_env
#### chromium.gyp\_env
Next to your top-level `/src/` directory, create a file called `chromium.gyp_env`. This holds a JSON dictionary, with the keys being any of the above environment variables. For the full list of supported keys, see [/src/build/gyp\_helper.py](https://code.google.com/p/chromium/codesearch#chromium/src/build/gyp_helper.py&sq=package:chromium&type=cs&q=file:gyp_helper.py%5Cb).
Next to your top-level `/src/` directory, create a file called
`chromium.gyp_env`. This holds a JSON dictionary, with the keys being any of the
above environment variables. For the full list of supported keys, see
[/src/build/gyp_helper.py](/build/gyp_helper.py).
```
{
``` {
'variables': {
'mac_strip_release': 0,
},
'GYP_DEFINES':
'clang=1 '
'component=shared_library '
'dcheck_always_on=1 '
}
```
}, 'GYP_DEFINES':
'clang=1 ' 'component=shared_library ' 'dcheck_always_on=1 '
} ```
### include.gyp
#### include.gyp
Or globally in your home directory, create a file `~/.gyp/include.gypi`.
### supplement.gypi
#### supplement.gypi
The build system will also include any files named `/src/*/supplement.gypi`, which should be in the same format as include.gyp above.
The build system will also include any files named `/src/*/supplement.gypi`,
which should be in the same format as include.gyp above.
## Change the Build System
### Change the Build System
Most platforms support multiple build systems (Windows: different Visual Studios versions and ninja, Mac: Xcode and ninja, etc.). A sensible default is selected, but it can be overridden:
Most platforms support multiple build systems (Windows: different Visual Studios
versions and ninja, Mac: Xcode and ninja, etc.). A sensible default is selected,
but it can be overridden:
```
$ GYP_GENERATORS=ninja gclient runhooks
```
$ GYP_GENERATORS=ninja gclient runhooks
[Ninja](https://code.google.com/p/chromium/wiki/NinjaBuild) is generally the fastest way to build anything on any platform.
[Ninja](ninja_build.md) is generally the fastest way to build anything on any
platform.
## Change Build Output Directory
### Change Build Output Directory
If you need to change a compile-time flag and do not want to touch your current build output, you can re-run GYP and place output into a new directory, like so, assuming you are using ninja:
If you need to change a compile-time flag and do not want to touch your current
build output, you can re-run GYP and place output into a new directory, like so,
assuming you are using ninja:
```
```shell
$ GYP_GENERATOR_FLAGS="output_dir=out_other_ninja" gclient runhooks
$ ninja -C out_other_ninja/Release chrome
```
Alternatively, you can do the following, which should work with all GYP generators, but the out directory is nested as `out_other/out/`.
Alternatively, you can do the following, which should work with all GYP
generators, but the out directory is nested as `out_other/out/`.
```
```shell
$ GYP_GENERATOR_OUTPUT="out_other" gclient runhooks
$ ninja -C out_other/out/Release chrome
```
**Note:** If you wish to run the WebKit layout tests, make sure you specify the new directory using `--build-directory=out_other_ninja` (don't include the `Release` part).
**Note:** If you wish to run the WebKit layout tests, make sure you specify the
new directory using `--build-directory=out_other_ninja` (don't include the
`Release` part).
## Building Google Chrome
### Building Google Chrome
To build Chrome, you need to be a Google employee and have access to the [src-internal](http://go.ext.google.com/src-internal) repository. Once your checkout is set up, you can run gclient like so:
To build Chrome, you need to be a Google employee and have access to the
[src-internal](https://goto.google.com/src-internal) repository. Once your
checkout is set up, you can run gclient like so:
```
$ GYP_DEFINES="branding=Chrome buildtype=Official" gclient runhooks
```
$ GYP_DEFINES="branding=Chrome buildtype=Official" gclient runhooks
Then building the `chrome` target will produce the official build. This tip can be used in conjunction with changing the output directory, since changing these defines will rebuild the world.
Then building the `chrome` target will produce the official build. This tip can
be used in conjunction with changing the output directory, since changing these
defines will rebuild the world.
Also note that some GYP\_DEFINES flags are incompatible with the official build. If you get an error when you try to build, try removing all your flags and start with just the above ones.
Also note that some GYP\_DEFINES flags are incompatible with the official build.
If you get an error when you try to build, try removing all your flags and start
with just the above ones.

@ -1,148 +1,217 @@
# What is it?
# Cr
Cr is the new unified interface to the myriad tools we use while working within a chromium checkout.
Its main additional feature is that it allows you to build many configurations and run targets within a single checkout (by not relying on a directory called 'out').
This is especially important when you want to cross-compile (for instance, building android from linux or building arm from intel), but it extends to any build variation.
Cr is the new unified interface to the myriad tools we use while working within
a chromium checkout. Its main additional feature is that it allows you to build
many configurations and run targets within a single checkout (by not relying on
a directory called 'out'). This is especially important when you want to
cross-compile (for instance, building android from linux or building arm from
intel), but it extends to any build variation.
[TOC]
## A quick example
The following is all you need to prepare an output directory, and then build and run the release build of chrome for the host platform:
```
cr init
cr run
The following is all you need to prepare an output directory, and then build and
run the release build of chrome for the host platform:
```shell
cr init
cr run
```
# How do I get it?
## How do I get it?
You already have it, it lives in `src/tools/cr`
You can run the cr.py file by hand, but if you are using bash it is much easier to source the bash helpers.
This will add a cr function to your bash shell that runs with pyc generation turned off, and also installs the bash tab completion handler (which is very primitive at the moment, it only completes the command not the options)
It also adds a function you can use in your prompt to tell you your selected build (`_cr_ps1`), and an helper to return you to the root of your active tree (`crcd`).
I recommend you add the following lines to the end of your ~/.bashrc (with a more correct path)
```
CR_CLIENT_PATH="/path/to/chromium"
source ${CR_CLIENT_PATH}/src/tools/cr/cr-bash-helpers.sh
You can run the cr.py file by hand, but if you are using bash it is much easier
to source the bash helpers. This will add a cr function to your bash shell that
runs with pyc generation turned off, and also installs the bash tab completion
handler (which is very primitive at the moment, it only completes the command
not the options) It also adds a function you can use in your prompt to tell you
your selected build (`_cr_ps1`), and an helper to return you to the root of your
active tree (`crcd`). I recommend you add the following lines to the end of your
`~/.bashrc` (with a more correct path):
```shell
CR_CLIENT_PATH="/path/to/chromium"
source ${CR_CLIENT_PATH}/src/tools/cr/cr-bash-helpers.sh
```
At that point the cr command is available to you.
# How do I use it?
## How do I use it?
It should be mostly self documenting
```
cr --help
```
cr --help
will list all the commands installed
```
cr --help command
```
cr --help command
will give you more detailed help for a specific command.
> _**A note to existing android developers:**_
> Do not source envsetup! ever!
> If you use cr in a shell that has had envsetup sourced, miscellaneous things will be broken. The cr tool does all the work that envsetup used to do in a way that does not pollute your current shell.
> If you really need a shell that has had the environment modified like envsetup used to do, see the cr shell command, also probably file a bug for a missing cr feature!
_**A note to existing android developers:**_
# The commands
* Do not source envsetup! ever!
* If you use cr in a shell that has had envsetup sourced, miscellaneous things
will be broken. The cr tool does all the work that envsetup used to do in a
way that does not pollute your current shell.
* If you really need a shell that has had the environment modified like
envsetup used to do, see the cr shell command, also probably file a bug for
a missing cr feature!
Below are some common workflows, but first there is a quick overview of the commands currently in the system.
## The commands
## Output directory commands
Below are some common workflows, but first there is a quick overview of the
commands currently in the system.
init
> Create and configure an output directory. Also runs select to make it the default.
select
> Select an output directory. This makes it the default output for all commands, so you can omit the --out option if you want to.
prepare
> Prepares an output directory. This runs any preparation steps needed for an output directory to be viable, which at the moment means run gyp.
### Output directory commands
## Build commands
init
build
> Build a target.
install
> Install a binary. Does build first unless `--builder==skip`
> This does nothing on linux, and installs the apk onto the device for android builds.
run
> Invoke a target. Does an install first, unless `--installer=skip`.
debug
> Debug a target. Does a run first, unless `--runner=skip`. Uses the debugger specified by `--debugger`.
Create and configure an output directory. Also runs select to make it the
default.
## Other commands
select
sync
> Sync the source tree. Uses gclient sync to do the real work.
shell
> Run an exernal command in a cr environment.
> This is an escape hatch, if passed a command it runs it in the correct environment for the current output directory, otherwise it starts a sub shell with that environment. This allows you to run any commands that don't have shims, or are too specialized to get one. This is especially important on android where the environment is heavily modified.
Select an output directory. This makes it the default output for all commands,
so you can omit the --out option if you want to.
# Preparing to build
prepare
Prepares an output directory. This runs any preparation steps needed for an
output directory to be viable, which at the moment means run gyp.
### Build commands
build
Build a target.
install
Install a binary. Does build first unless `--builder==skip`. This does nothing
on linux, and installs the apk onto the device for android builds.
run
Invoke a target. Does an install first, unless `--installer=skip`.
debug
Debug a target. Does a run first, unless `--runner=skip`. Uses the debugger
specified by `--debugger`.
### Other commands
sync
Sync the source tree. Uses gclient sync to do the real work.
shell
Run an exernal command in a cr environment. This is an escape hatch, if passed
a command it runs it in the correct environment for the current output
directory, otherwise it starts a sub shell with that environment. This allows
you to run any commands that don't have shims, or are too specialized to get
one. This is especially important on android where the environment is heavily
modified.
## Preparing to build
The first thing you need to do is prepare an output directory to build into.
You do this with:
```
cr init
```
By default on linux this will prepare a linux x86 release build output directory, called out\_linux/Release, if you want an android debug one, you can use:
```
cr init --out=out_android/Debug
```
The output directory can be called anything you like, but if you pick a non standard name cr might not be able to infer the platform, in which case you need to specify it.
The second part **must** be either Release or Debug.
All options can be shortened to the shortest non ambiguous prefix, so the short command line to prepare an android debug output directory in out is:
```
cr init --o=out/Debug --p=android
```
It is totally safe to do this in an existing output directory, and is an easy way to migrate an existing output directory to use in cr if you don't want to start from scratch.
Most commands in cr take a --out parameter to tell them which output directory you want to operate on, but it will default to the last value passed to init or select.
This enables you to omit it from most commands.
cr init
Both init and select do additional work to prepare the output directory, which include things like running gyp. You can do that work on it's own with the prepare command if you want, something you need to do when changing between branches where you have modified the build files.
By default on linux this will prepare a linux x86 release build output
directory, called `out_linux/Release`, if you want an android debug one, you can
use:
If you want to set custom GYP defines for your build you can do this by adding adding the -s GYP\_DEFINES argument, for example:
```
cr init --o=out/Debug -s GYP_DEFINES=component=shared_library
```
cr init --out=out_android/Debug
# Running chrome
The output directory can be called anything you like, but if you pick a non
standard name cr might not be able to infer the platform, in which case you need
to specify it. The second part **must** be either Release or Debug. All options
can be shortened to the shortest non ambiguous prefix, so the short command line
to prepare an android debug output directory in out is:
cr init --o=out/Debug --p=android
It is totally safe to do this in an existing output directory, and is an easy
way to migrate an existing output directory to use in cr if you don't want to
start from scratch.
Most commands in cr take a --out parameter to tell them which output directory
you want to operate on, but it will default to the last value passed to init or
select. This enables you to omit it from most commands.
Both init and select do additional work to prepare the output directory, which
include things like running gyp. You can do that work on it's own with the
prepare command if you want, something you need to do when changing between
branches where you have modified the build files.
If you want to set custom GYP defines for your build you can do this by adding
adding the `-s GYP_DEFINES` argument, for example:
cr init --o=out/Debug -s GYP_DEFINES=component=shared_library
## Running chrome
If you just want to do a basic build and run, then you do
```
cr run
```
which will build, install if necessary, and run chrome, with some default args to open on https://www.google.com/.
The same command line will work for any supported platform and mode.
If you want to just run it again, you can turn off the build and install steps,
```
cr run --installer=skip
```
note that turning off install automatically turns off build (which you could do with `--builder=skip`) as there is no point building if you are not going to install.
cr run
# Debugging chrome
which will build, install if necessary, and run chrome, with some default args
to open on https://www.google.com/. The same command line will work for any
supported platform and mode. If you want to just run it again, you can turn off
the build and install steps,
cr run --installer=skip
note that turning off install automatically turns off build (which you could do
with `--builder=skip`) as there is no point building if you are not going to
install.
## Debugging chrome
To start chrome under a debugger you use
```
cr debug
```
which will build, install, and run chrome, and attach a debugger to it. This works on any supported platform, and if multiple debuggers are available, you can select which one you want with `--debugger=my_debugger`
# Help, it went wrong!
cr debug
which will build, install, and run chrome, and attach a debugger to it. This
works on any supported platform, and if multiple debuggers are available, you
can select which one you want with `--debugger=my_debugger`
## Help, it went wrong!
There are a few things to do, and you should probably do all of them.
Run your commands with dry-run and/or verbose turned on to see what the tool is really doing, for instance
```
cr --d -vvvv init
```
The number of v's matter, it's the verbosity level, you can also just specify the value with -v=4 if you would rather.
Run your commands with dry-run and/or verbose turned on to see what the tool is
really doing, for instance
[Report a bug](https://code.google.com/p/chromium/issues/entry?comment=%3CDont%20forget%20to%20attach%20the%20command%20lines%20used%20with%20-v=4%20if%20possible%3E&pri=2&labels=OS-Android,tool-cr,Build-Tools,Type-Bug&owner=iancottrell@chromium.org&status=Assigned), even if it is just something that confused or annoyed rather than broke, we want this tool to be very low friction for developers.
cr --d -vvvv init
# Known issues
The number of v's matter, it's the verbosity level, you can also just specify
the value with -v=4 if you would rather.
You can see the full list of issues with [this](https://code.google.com/p/chromium/issues/list?can=2&q=label%3Atool-cr) query, but here are the high level issues:
[Report a bug], even if it is just something that confused or annoyed rather
than broke, we want this tool to be very low friction for developers.
* **Only supports gtest** : You run tests using the run command, which tries to infer from the target whether it is a runnable binary or a test. The inference could be improved, and it needs to handle the other test types as well.
* **No support for windows or mac** : allowed for in the design, but need people with expertise on those platforms to help out
* **Bash completion** : The hooks for it are there, but at the moment it only ever completes the command, not any of the arguments
## Known issues
You can see the full list of issues with
[this](https://code.google.com/p/chromium/issues/list?can=2&q=label%3Atool-cr)
query, but here are the high level issues:
* **Only supports gtest** : You run tests using the run command, which tries
to infer from the target whether it is a runnable binary or a test. The
inference could be improved, and it needs to handle the other test types as
well.
* **No support for windows or mac** : allowed for in the design, but need
people with expertise on those platforms to help out
* **Bash completion** : The hooks for it are there, but at the moment it only
ever completes the command, not any of the arguments
[Report a bug]:
https://code.google.com/p/chromium/issues/entry?comment=%3CDont%20forget%20to%20attach%20the%20command%20lines%20used%20with%20-v=4%20if%20possible%3E&pri=2&labels=OS-Android,tool-cr,Build-Tools,Type-Bug&owner=iancottrell@chromium.org&status=Assigned

@ -1,26 +1,39 @@
# Emacs
[TOC]
## Debugging
LinuxDebugging has some emacs-specific debugging tips.
[Linux Debugging](linux_debugging.md) has some emacs-specific debugging tips.
## Blink Style (WebKit)
Chrome and Blink/WebKit style differ. You can use [directory-local variables](http://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html) to make the tab key do the right thing. E.g., in `third_party/WebKit`, add a `.dir-locals.el` that contains
Chrome and Blink/WebKit style differ. You can use
[directory-local variables](http://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html)
to make the tab key do the right thing. E.g., in `third_party/WebKit`, add a
`.dir-locals.el` that contains
```
```el
((nil . ((indent-tabs-mode . nil)
(c-basic-offset . 4)
(fill-column . 120))))
```
This turns off tabs, sets your indent to four spaces, and makes `M-q` wrap at 120 columns (WebKit doesn't define a wrap column, but there's a soft limit somewhere in that area for comments. Some reviewers do enforce the no wrap limit, which Emacs can deal with gracefully; see below.)
This turns off tabs, sets your indent to four spaces, and makes `M-q` wrap at
120 columns (WebKit doesn't define a wrap column, but there's a soft limit
somewhere in that area for comments. Some reviewers do enforce the no wrap
limit, which Emacs can deal with gracefully; see below.)
Be sure to `echo .dir-locals.el >> .git/info/exclude` so `git clean` doesn't delete your file.
Be sure to `echo .dir-locals.el >> .git/info/exclude` so `git clean` doesn't
delete your file.
It can be useful to set up a WebKit specific indent style. It's not too much different so it's easy to base off of the core Google style. Somewhere after you've loaded google.el (most likely in your .emacs file), add:
It can be useful to set up a WebKit specific indent style. It's not too much
different so it's easy to base off of the core Google style. Somewhere after
you've loaded google.el (most likely in your .emacs file), add:
```
(c-add-style "WebKit" '("Google"
```el
(c-add-style "WebKit" '("Google"
(c-basic-offset . 4)
(c-offsets-alist . ((innamespace . 0)
(access-label . -)
@ -32,38 +45,42 @@ It can be useful to set up a WebKit specific indent style. It's not too much dif
then you can add
```
(c-mode . ((c-file-style . "WebKit")))
(c++-mode . ((c-file-style . "WebKit"))))
```el
(c-mode . ((c-file-style . "WebKit")))
(c++-mode . ((c-file-style . "WebKit"))))
```
to the end of the .dir-locals.el file you created above. Note that this style may not yet be complete, but it covers the most common differences.
to the end of the .dir-locals.el file you created above. Note that this style
may not yet be complete, but it covers the most common differences.
Now that you have a WebKit specific style being applied, and assuming you have font locking and it's default jit locking turned on, you can also get Emacs 23 to wrap long lines more intelligently by adding the following to your .emacs file:
Now that you have a WebKit specific style being applied, and assuming you have
font locking and it's default jit locking turned on, you can also get Emacs 23
to wrap long lines more intelligently by adding the following to your .emacs
file:
```
```el
;; For dealing with WebKit long lines and word wrapping.
(defun c-mode-adaptive-indent (beg end)
"Set the wrap-prefix for the the region between BEG and END with adaptive filling."
(goto-char beg)
(while
(let ((lbp (line-beginning-position))
(lep (line-end-position)))
(defun c-mode-adaptive-indent (beg end)
"Set the wrap-prefix for the the region between BEG and END with adaptive filling."
(goto-char beg)
(while
(let ((lbp (line-beginning-position))
(lep (line-end-position)))
(put-text-property lbp lep 'wrap-prefix (concat (fill-context-prefix lbp lep) (make-string c-basic-offset ? )))
(search-forward "\n" end t))))
(define-minor-mode c-adaptive-wrap-mode
"Wrap the buffer text with adaptive filling for c-mode."
:lighter ""
(save-excursion
(save-restriction
(widen)
(let ((buffer-undo-list t)
(inhibit-read-only t)
(mod (buffer-modified-p)))
(if c-adaptive-wrap-mode
(define-minor-mode c-adaptive-wrap-mode
"Wrap the buffer text with adaptive filling for c-mode."
:lighter ""
(save-excursion
(save-restriction
(widen)
(let ((buffer-undo-list t)
(inhibit-read-only t)
(mod (buffer-modified-p)))
(if c-adaptive-wrap-mode
(jit-lock-register 'c-mode-adaptive-indent)
(jit-lock-unregister 'c-mode-adaptive-indent)
(jit-lock-unregister 'c-mode-adaptive-indent)
(remove-text-properties (point-min) (point-max) '(wrap-prefix pref)))
(restore-buffer-modified-p mod)))))
@ -79,43 +96,64 @@ Now that you have a WebKit specific style being applied, and assuming you have f
(add-hook 'hack-local-variables-hook 'c-adaptive-wrap-mode-for-webkit)
```
This turns on visual wrap mode for files using the WebKit c style, and sets up a hook to dynamically set the indent on the wrapped lines. It's not quite as intelligent as it could be (e.g., what would the wrap be if there really were a newline there?), but it's very fast. It makes dealing with long code lines anywhere much more tolerable (not just in WebKit).
This turns on visual wrap mode for files using the WebKit c style, and sets up a
hook to dynamically set the indent on the wrapped lines. It's not quite as
intelligent as it could be (e.g., what would the wrap be if there really were a
newline there?), but it's very fast. It makes dealing with long code lines
anywhere much more tolerable (not just in WebKit).
## Syntax-error Highlighting
NinjaBuild users get in-line highlighting of syntax errors using `flymake.el` on each buffer-save:
```
(load-file "src/tools/emacs/flymake-chromium.el")
```
[Ninja](ninja_build.md) users get in-line highlighting of syntax errors using
`flymake.el` on each buffer-save:
(load-file "src/tools/emacs/flymake-chromium.el")
## [ycmd](https://github.com/Valloric/ycmd) (YouCompleteMe) + flycheck
[emacs-ycmd](https://github.com/abingham/emacs-ycmd) in combination with flycheck provides:
* advanced code completion
* syntax checking
* navigation to declarations and definitions (using `ycmd-goto`)
based on on-the fly processing using clang. A quick demo video showing code completion and flycheck highlighting a missing semicolon syntax error:
[emacs-ycmd](https://github.com/abingham/emacs-ycmd) in combination with
flycheck provides:
<a href='http://www.youtube.com/watch?feature=player_embedded&v=a0zMbm4jACk' target='_blank'><img src='http://img.youtube.com/vi/a0zMbm4jACk/0.jpg' width='696' height=250 /></a>
* advanced code completion
* syntax checking
* navigation to declarations and definitions (using `ycmd-goto`) based on
on-the-fly processing using clang. A quick demo video showing code
completion and flycheck highlighting a missing semicolon syntax error:
[![video preview][img]][video]
[img]: http://img.youtube.com/vi/a0zMbm4jACk/0.jpg
[video]: http://www.youtube.com/watch?feature=player_embedded&v=a0zMbm4jACk
### Requirements
#### Requirements:
* Your build system is set up for building with clang or wrapper+clang
#### Setup
### Setup
1. Clone, update external git repositories and build.sh ycmd from https://github.com/Valloric/ycmd into a directory, e.g. `~/dev/ycmd`
1. Test `ycmd` by running
> `~/dev/ycmd$ python ycmd/__main__.py`
1. Clone, update external git repositories and build.sh ycmd from
https://github.com/Valloric/ycmd into a directory, e.g. `~/dev/ycmd`
1. Test `ycmd` by running `~/dev/ycmd$ python ycmd/__main__.py` You should see
`KeyError: 'hmac_secret'`
1. Install the following packages to emacs, for example from melpa:
* `ycmd`
* `company-ycmd`
* `flycheck-ycmd`
1. [More info on configuring emacs-ycmd](https://github.com/abingham/emacs-ycmd#quickstart)
1. Assuming your checkout of Chromium is in `~/dev/blink`, i.e. this is the
directory in which you find the `src`folder, create a symbolic link as
follows:
> You should see `KeyError: 'hmac_secret'`
1. Install the following packages to emacs, for example from melpa:
* `ycmd`
* `company-ycmd`
* `flycheck-ycmd`
> [More info on configuring emacs-ycmd](https://github.com/abingham/emacs-ycmd#quickstart)
1. Assuming your checkout of Chromium is in `~/dev/blink`, i.e. this is the directory in which you find the `src`folder, create a symbolic link as follows
> `cd ~/dev/blink; ln -s src/tools/vim/chromium.ycm_extra_conf.py .ycm_extra_conf.py`
1. Add something like the following to your `init.el`
```
```shell
cd ~/dev/blink
ln -s src/tools/vim/chromium.ycm_extra_conf.py .ycm_extra_conf.py
```
1. Add something like the following to your `init.el`
```el
;; ycmd
;;; Googlers can replace a lot of this with (require 'google-ycmd).
@ -148,32 +186,49 @@ based on on-the fly processing using clang. A quick demo video showing code comp
(setq url-show-status nil)
```
#### Troubleshooting
### Troubleshooting
* If no completions show up or emacs reports errors, you can check the `*ycmd-server*` buffer for errors. See the next bullet point for how to handle "OS Error: No such file or directory"
* Launching emacs from an OS menu might result in a different environment so that `ycmd` does not find ninja. In that case, you can use a package like [exec-path from shell](https://github.com/purcell/exec-path-from-shell) and add the following to your `init.el`:
```
* If no completions show up or emacs reports errors, you can check the
`*ycmd-server*` buffer for errors. See the next bullet point for how to
handle "OS Error: No such file or directory"
* Launching emacs from an OS menu might result in a different environment so
that `ycmd` does not find ninja. In that case, you can use a package like
[exec-path from shell](https://github.com/purcell/exec-path-from-shell) and
add the following to your `init.el`:
```el
(require 'exec-path-from-shell)
(when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize))
```
## ff-get-other-file
There's a builtin function called `ff-get-other-file` which will get the "other file" based on file extension. I have this bound to C-o in c-mode (`(local-set-key "\C-o" 'ff-get-other-file)`). While "other file" is per-mode defined, in c-like languages it means jumping between the header and the source file. So I switch back and forth between the header and the source with C-o. If we had separate include/ and src/ directories, this would be a pain to setup, but this might just work out of the box for you. See the documentation for the variable `cc-other-file-alist` for more information.
There's a builtin function called `ff-get-other-file` which will get the "other
file" based on file extension. I have this bound to C-o in c-mode
(`(local-set-key "\C-o" 'ff-get-other-file)`). While "other file" is per-mode
defined, in c-like languages it means jumping between the header and the source
file. So I switch back and forth between the header and the source with C-o. If
we had separate include/ and src/ directories, this would be a pain to setup,
but this might just work out of the box for you. See the documentation for the
variable `cc-other-file-alist` for more information.
One drawback of ff-get-other-file is that it will always switch to a matching buffer, even if the other file is in a different directory, so if you have A.cc,A.h,A.cc(2) then ff-get-other-file will switch to A.h from A.cc(2) rather than load A.h(2) from the appropriate directory. If you prefer something (C specific) that always finds, try this:
```
One drawback of ff-get-other-file is that it will always switch to a matching
buffer, even if the other file is in a different directory, so if you have
A.cc,A.h,A.cc(2) then ff-get-other-file will switch to A.h from A.cc(2) rather
than load A.h(2) from the appropriate directory. If you prefer something (C
specific) that always finds, try this:
```el
(defun cc-other-file()
"Toggles source/header file"
(interactive)
(let ((buf (current-buffer))
(name (file-name-sans-extension (buffer-file-name)))
(other-extens
(cadr (assoc (concat "\\."
(other-extens
(cadr (assoc (concat "\\."
(file-name-extension (buffer-file-name))
"\\'")
"\\'")
cc-other-file-alist))))
(dolist (e other-extens)
(if (let ((f (concat name e)))
@ -182,26 +237,33 @@ One drawback of ff-get-other-file is that it will always switch to a matching bu
)
)
```
_Note: if you know an easy way to change the ff-get-other-file behavior, please replace this hack with that solution! - stevenjb@chromium.org_
_Note: if you know an easy way to change the ff-get-other-file behavior, please
replace this hack with that solution! - stevenjb@chromium.org_
## Use Google's C++ style!
We have an emacs module, [google-c-style.el](http://google-styleguide.googlecode.com/svn/trunk/google-c-style.el), which adds c-mode formatting.
Then add to your .emacs:
We have an emacs module,
[google-c-style.el](http://google-styleguide.googlecode.com/svn/trunk/google-c-style.el),
which adds c-mode formatting. Then add to your .emacs:
```el
(load "/<path/to/chromium>/src/buildtools/clang_format/script/clang-format.el")
(add-hook 'c-mode-common-hook
(function (lambda () (local-set-key (kbd "TAB") 'clang-format-region))))
```
(load "/<path/to/chromium>/src/buildtools/clang_format/script/clang-format.el")
(add-hook 'c-mode-common-hook (function (lambda () (local-set-key (kbd "TAB") 'clang-format-region))))
```
Now, you can use the
Now, you can use the
&lt;Tab&gt;
key to format the current line (even a long line) or region.
key to format the current line (even a long line) or region.
### Highlight long lines
## Highlight long lines
One nice way to highlight long lines and other style issues:
```
```el
(require 'whitespace)
(setq whitespace-style '(face indentation trailing empty lines-tail))
(setq whitespace-line-column nil)
@ -212,76 +274,87 @@ One nice way to highlight long lines and other style issues:
(global-whitespace-mode 1)
```
Note: You might need to grab the latest version of [whitespace.el](http://www.emacswiki.org/emacs-en/download/whitespace.el).
Note: You might need to grab the latest version of
[whitespace.el](http://www.emacswiki.org/emacs-en/download/whitespace.el).
## gyp
### `gyp` style
There is a gyp mode that provides basic indentation and font-lock (syntax highlighting) support. The mode derives from python.el (bundled with newer emacsen).
There is a gyp mode that provides basic indentation and font-lock (syntax
highlighting) support. The mode derives from python.el (bundled with newer
emacsen).
You can find it in tools/gyp/tools/emacs or at http://code.google.com/p/gyp/source/browse/trunk/tools/emacs/
You can find it in /src/tools/gyp/tools/emacs
See the README file there for installation instructions.
**Important**: the mode is only tested with `python.el` (bundled with newer emacsen), not with `python-mode.el` (outdated and less maintained these days).
**Important**: the mode is only tested with `python.el` (bundled with newer
emacsen), not with `python-mode.el` (outdated and less maintained these days).
### deep nesting
A couple of helpers that show a summary of where you are; the first by tracing the indentation hierarchy upwards, the second by only showing `#if`s and `#else`s that are relevant to the current line:
A couple of helpers that show a summary of where you are; the first by tracing
the indentation hierarchy upwards, the second by only showing `#if`s and
`#else`s that are relevant to the current line:
```el
(defun ami-summarize-indentation-at-point ()
"Echo a summary of how one gets from the left-most column to
POINT in terms of indentation changes."
(interactive)
(save-excursion
(let ((cur-indent most-positive-fixnum)
(trace '()))
(while (not (bobp))
(let ((current-line (buffer-substring (line-beginning-position)
(line-end-position))))
(when (and (not (string-match "^\\s-*$" current-line))
(< (current-indentation) cur-indent))
(setq cur-indent (current-indentation))
(setq trace (cons current-line trace))
(if (or (string-match "^\\s-*}" current-line)
(string-match "^\\s-*else " current-line)
(string-match "^\\s-*elif " current-line))
(setq cur-indent (1+ cur-indent)))))
(forward-line -1))
(message "%s" (mapconcat 'identity trace "\n")))))
"Echo a summary of how one gets from the left-most column to
POINT in terms of indentation changes."
(interactive)
(save-excursion
(let ((cur-indent most-positive-fixnum)
(trace '()))
(while (not (bobp))
(let ((current-line (buffer-substring (line-beginning-position)
(line-end-position))))
(when (and (not (string-match "^\\s-*$" current-line))
(< (current-indentation) cur-indent))
(setq cur-indent (current-indentation))
(setq trace (cons current-line trace))
(if (or (string-match "^\\s-*}" current-line)
(string-match "^\\s-*else " current-line)
(string-match "^\\s-*elif " current-line))
(setq cur-indent (1+ cur-indent)))))
(forward-line -1))
(message "%s" (mapconcat 'identity trace "\n")))))
(require 'cl)
(defun ami-summarize-preprocessor-branches-at-point ()
"Summarize the C preprocessor branches needed to get to point."
(interactive)
(flet ((current-line-text ()
(buffer-substring (line-beginning-position) (line-end-position))))
(save-excursion
(let ((eol (or (end-of-line) (point)))
deactivate-mark directives-stack)
(goto-char (point-min))
(while (re-search-forward "^#\\(if\\|else\\|endif\\)" eol t)
(if (or (string-prefix-p "#if" (match-string 0))
(string-prefix-p "#else" (match-string 0)))
(push (current-line-text) directives-stack)
(if (string-prefix-p "#endif" (match-string 0))
(while (string-prefix-p "#else" (pop directives-stack)) t))))
(message "%s" (mapconcat 'identity (reverse directives-stack) "\n"))))))
(defun ami-summarize-preprocessor-branches-at-point ()
"Summarize the C preprocessor branches needed to get to point."
(interactive)
(flet ((current-line-text ()
(buffer-substring (line-beginning-position) (line-end-position))))
(save-excursion
(let ((eol (or (end-of-line) (point)))
deactivate-mark directives-stack)
(goto-char (point-min))
(while (re-search-forward "^#\\(if\\|else\\|endif\\)" eol t)
(if (or (string-prefix-p "#if" (match-string 0))
(string-prefix-p "#else" (match-string 0)))
(push (current-line-text) directives-stack)
(if (string-prefix-p "#endif" (match-string 0))
(while (string-prefix-p "#else" (pop directives-stack)) t))))
(message "%s" (mapconcat 'identity (reverse directives-stack) "\n"))))))
```
## find-things-fast
erg wrote a suite of tools that do common operations from the root of your repository, called [Find Things Fast](https://github.com/eglaysher/find-things-fast). It contains ido completion over `git ls-files` (or the svn find equivalent) and `grepsource` that only git greps files with extensions we care about (or the equivalent the `find | xargs grep` statement in non-git repos.)
erg wrote a suite of tools that do common operations from the root of your
repository, called
[Find Things Fast](https://github.com/eglaysher/find-things-fast). It contains
ido completion over `git ls-files` (or the svn find equivalent) and `grepsource`
that only git greps files with extensions we care about (or the equivalent the
`find | xargs grep` statement in non-git repos.)
## vc-mode and find-file performance
When you first open a file under git control, vc mode kicks in and does a high level stat of your git repo. For huge repos, especially WebKit and Chromium, this makes opening a file take literally seconds. This snippet disables VC git for chrome directories:
```
When you first open a file under git control, vc mode kicks in and does a high
level stat of your git repo. For huge repos, especially WebKit and Chromium,
this makes opening a file take literally seconds. This snippet disables VC git
for chrome directories:
```el
; Turn off VC git for chrome
(when (locate-library "vc")
(defadvice vc-registered (around nochrome-vc-registered (file))
@ -298,14 +371,17 @@ ad-do-it)
```
## git tools
We're collecting Chrome-specific tools under `tools/emacs`. See the files there for details.
* `trybot.el`: import Windows trybot output into a `compilation-mode` buffer.
We're collecting Chrome-specific tools under `tools/emacs`. See the files there
for details.
* `trybot.el`: import Windows trybot output into a `compilation-mode` buffer.
## ERC for IRC
See ErcIrc.
See [ErcIrc][erc_irc.md].
## TODO
* Figure out how to make `M-x compile` default to `cd /path/to/chrome/root; make -r chrome`.
* Figure out how to make `M-x compile` default to
`cd /path/to/chrome/root; make -r chrome`.

@ -1,16 +1,24 @@
# ERC IRC
It's very simple to get started with ERC; just do the following:
1. Optional: Sign up at freenode.net to claim your nickname.
1. M-x
1. erc (and accept default for the first couple of items)
1. /join #chromium
1. Optional: Sign up at freenode.net to claim your nickname.
1. M-x
1. erc (and accept default for the first couple of items)
1. /join #chromium
You may notice the following problems:
* It's hard to notice when you're mentioned.
* ERC does not have built-in accidental paste prevention, so you might accidentally paste multiple lines of text into the IRC channel.
You can modify the following and add it to your .emacs file to fix both of the above. Note that you'll need to install and configure sendxmpp for the mention hack, which also requires you to create an account for your "robot" on e.g. jabber.org:
* It's hard to notice when you're mentioned.
* ERC does not have built-in accidental paste prevention, so you might
accidentally paste multiple lines of text into the IRC channel.
```
You can modify the following and add it to your .emacs file to fix both of the
above. Note that you'll need to install and configure sendxmpp for the mention
hack, which also requires you to create an account for your "robot" on e.g.
jabber.org:
```el
(require 'erc)
;; Notify me when someone mentions my nick or aliases on IRC.
@ -89,4 +97,6 @@ You can modify the following and add it to your .emacs file to fix both of the a
))
```
Note: The paste protection code is modified from a paste by user 'yashh' at http://paste.lisp.org/display/78068 (Google cache [here](http://webcache.googleusercontent.com/search?q=cache:p_S9ZKlWZPoJ:paste.lisp.org/display/78068+paste+78068&cd=1&hl=en&ct=clnk&gl=ca&source=www.google.ca)).
Note: The paste protection code is modified from a paste by user 'yashh' at
http://paste.lisp.org/display/78068 (Google cache
[here](http://webcache.googleusercontent.com/search?q=cache:p_S9ZKlWZPoJ:paste.lisp.org/display/78068+paste+78068&cd=1&hl=en&ct=clnk&gl=ca&source=www.google.ca)).

@ -1,67 +1,95 @@
# Git Cookbook
A collection of git recipes to do common git tasks.
See also UsingGit and GitTips.
See also [Git Tips](git_tips.md).
[TOC]
## Introduction
This is designed to be a cookbook for common command sequences/tasks relating to git, git-cl, and how they work with chromium development. It might be a little light on explanations.
This is designed to be a cookbook for common command sequences/tasks relating to
git, git-cl, and how they work with chromium development. It might be a little
light on explanations.
If you are new to git, or do not have much experience with a distributed version control system, you should also check out [The Git Community Book](http://book.git-scm.com/) for an overview of basic git concepts and general git usage. Knowing what git means by branches, commits, reverts, and resets (as opposed to what SVN means by them) will help make the following much more understandable.
If you are new to git, or do not have much experience with a distributed version
control system, you should also check out
[The Git Community Book](http://book.git-scm.com/) for an overview of basic git
concepts and general git usage. Knowing what git means by branches, commits,
reverts, and resets (as opposed to what SVN means by them) will help make the
following much more understandable.
## Excluding file(s) from git-cl, while preserving them for later use
Since git-cl assumes that the diff between your current branch and its tracking branch (defaults to the svn-trunk if there is no tracking branch) is what should be used for the CL, the goal is to remove the unwanted files from the current branch, and preserve them in another branch, or a similar.
Since git-cl assumes that the diff between your current branch and its tracking
branch (defaults to the svn-trunk if there is no tracking branch) is what should
be used for the CL, the goal is to remove the unwanted files from the current
branch, and preserve them in another branch, or a similar.
### Method #1: Reset your current branch, and selectively commit files.
1. `git log` # see the list of your commits. Find the hash of the last commit before your changes.
1. `git reset --soft abcdef` # where abcdef is the hash found in the step above.
1. `git commit <files_for_this_cl> -m "files to upload"` # commit the files you want included in the CL here.
1. `git checkout -b new_branch_name origin/trunk` # Create a new branch for the files that you want to exclude.
1. `git commit -a -m "preserved files"` # Commit the rest of the files.
1. `git log` See the list of your commits. Find the hash of the last commit
before your changes.
1. `git reset --soft abcdef` where abcdef is the hash found in the step above.
1. `git commit <files_for_this_cl> -m "files to upload"` commit the files you
want included in the CL here.
1. `git checkout -b new_branch_name origin/trunk` Create a new branch for the
files that you want to exclude.
1. `git commit -a -m "preserved files"` Commit the rest of the files.
### Method #2: Create a new branch, reset, then commit files to preserve
This method creates a new branch from your current one to preserve your changes. The commits on the new branch are undone, and then only the files you want to preserve are recommitted.
1. `git checkout -b new_branch_name` # This preserves your old files.
1. `git log` # see the list of your commits. Find the hash of the last commit before your changes.
1. `git reset --soft abcdef` # where abcdef is the hash found in the step above.
1. `git commit <files_to_preserve> -m "preserved files"` # commit the found files into the new\_branch\_name.
This method creates a new branch from your current one to preserve your changes.
The commits on the new branch are undone, and then only the files you want to
preserve are recommitted.
Then revert your files however you'd like in your old branch. The files listed in step 4 will be saved in new\_branch\_name
1. `git checkout -b new_branch_name` This preserves your old files.
1. `git log` See the list of your commits. Find the hash of the last commit
before your changes.
1. `git reset --soft abcdef` Where abcdef is the hash found in the step above.
1. `git commit <files_to_preserve> -m "preserved files"` Commit the found files
into the `new_branch_name`.
Then revert your files however you'd like in your old branch. The files listed
in step 4 will be saved in `new_branch_name`
### Method #3: Cherry pick changes into review branches
If you are systematic in creating separate local commits for independent changes, you can make a number of different changes in the same client and then cherry-pick each one into a separate review branch.
1. Make and commit a set of independent changes.
1. `git log` # see the hashes for each of your commits.
1. repeat checkout, cherry-pick, upload steps for each change1..n
1. `git checkout -b review-changeN origin` # create a new review branch tracking origin
1. `git cherry-pick <hash of change N>`
1. `git cl upload`
If you are systematic in creating separate local commits for independent
changes, you can make a number of different changes in the same client and then
cherry-pick each one into a separate review branch.
If a change needs updating due to review comments, you can go back to your main working branch, update the commit, and re-cherry-pick it into the review branch.
1. Make and commit a set of independent changes.
1. `git log` # see the hashes for each of your commits.
1. repeat checkout, cherry-pick, upload steps for each change1..n
1. `git checkout -b review-changeN origin` Create a new review branch
tracking origin
1. `git cherry-pick <hash of change N>`
1. `git cl upload`
1. `git checkout <working branch>`
1. Make changes.
1. If the commit you want to update is the most recent one:
1. `git commit --amend <files>`
1. If not:
1. `git commit <files>`
1. `git rebase -i origin` # use interactive rebase to squash the new commit into the old one.
1. `git log` # observe new hash for the change
1. `git checkout review-changeN`
1. `git reset --hard` # remove the previous version of the change
1. `cherry-pick <new hash of change N>`
1. `git cl upload`
If a change needs updating due to review comments, you can go back to your main
working branch, update the commit, and re-cherry-pick it into the review branch.
1. `git checkout <working branch>`
1. Make changes.
1. If the commit you want to update is the most recent one:
1. `git commit --amend <files>`
1. If not:
1. `git commit <files>`
1. `git rebase -i origin` # use interactive rebase to squash the new
commit into the old one.
1. `git log` # observe new hash for the change
1. `git checkout review-changeN`
1. `git reset --hard` # remove the previous version of the change
1. `cherry-pick <new hash of change N>`
1. `git cl upload`
## Sharing code between multiple machines
Assume Windows computer named vista, Linux one named penguin.
Prerequisite: both machine have git clones of the main git tree.
```
```shell
vista$ git remote add linux ssh://penguin/path/to/git/repo
vista$ git fetch linux
vista$ git branch -a # should show "linux/branchname"
@ -71,70 +99,99 @@ vista$ git push linux # push branch back to linux
penguin$ git reset --hard # update with new stuff in branch
```
Note that, by default, `gclient sync` will update all remotes. If your other machine (i.e., `penguin` in the above example) is not always available, `gclient sync` will timeout and fail trying to reach it. To fix this, you may exclude your machine from being fetched by default:
Note that, by default, `gclient sync` will update all remotes. If your other
machine (i.e., `penguin` in the above example) is not always available,
`gclient sync` will timeout and fail trying to reach it. To fix this, you may
exclude your machine from being fetched by default:
```
vista$ git config --bool remote.linux.skipDefaultUpdate true
```
vista$ git config --bool remote.linux.skipDefaultUpdate true
## Reverting and undoing reverts
Two commands to be familiar with:
* `git cherry-pick X` -- patch in the change made in revision X (where X is a hash, or HEAD~2, or whatever)
* `git revert X` -- patch in the **inverse** of the change made
With that in hand, say you learned that the commit `abcdef` you just made was bad.
Two commands to be familiar with:
* `git cherry-pick X` -- patch in the change made in revision X (where X is a
hash, or HEAD~2, or whatever).
* `git revert X` -- patch in the **inverse** of the change made.
With that in hand, say you learned that the commit `abcdef` you just made was
bad.
Revert it locally:
```
$ git checkout origin # start with trunk
$ git show abcdef # grab the svn revision that abcdef was
$ git revert abcdef
```shell
git checkout origin # start with trunk
git show abcdef # grab the svn revision that abcdef was
git revert abcdef
# an editor will pop up; be sure to replace the unhelpful git hash
# in the commit message with the svn revision number
```
Commit the revert:
```
```shell
# note that since "git svn dcommit" commits each local change separately, be
# extra sure that your commit log looks exactly like what you want the tree's commit
# log to look like before you do this.
$ git log # double check that the commit log is *exactly* what you want
$ git svn dcommit # commit to svn, bypassing all precommit checks and prompts
# extra sure that your commit log looks exactly like what you want the tree's
# commit log to look like before you do this.
git log # double check that the commit log is *exactly* what you want
git svn dcommit # commit to svn, bypassing all precommit checks and prompts
```
Roll it forward again locally:
```
$ git checkout mybranch # go back to your old branch again, and
$ git reset --hard origin # reset the branch to origin, which now has your revert.
$ git cherry-pick abcdef # re-apply your bad change
$ git show # grab the rietveld issue number out of the old commit
$ git cl issue 12345 # restore the rietveld issue that was cleared on commit
```shell
# go back to your old branch again, and reset the branch to origin, which now
# has your revert.
git checkout mybranch
git reset --hard origin
git cherry-pick abcdef # re-apply your bad change
git show # grab the rietveld issue number out of the old commit
git cl issue 12345 # restore the rietveld issue that was cleared on commit
```
And now you can continue hacking where you left off, and since you're reusing the Reitveld issue you don't have to rewrite the commit message. (You may want to go manually reopen the issue on the Rietveld site -- `git cl status` will give you the URL.)
And now you can continue hacking where you left off, and since you're reusing
the Reitveld issue you don't have to rewrite the commit message. (You may want
to go manually reopen the issue on the Rietveld site -- `git cl status` will
give you the URL.)
## Retrieving, or diffing against an old file revision
Git works in terms of commits, not files. Thus, working with the history of a single file requires modified version of the show and diff commands.
```
$ git log path/to/file # Find the commit you want in the file's commit log.
$ git show 123abc:path/to/file # This prints out the file contents at commit 123abc.
$ git diff 123abc -- path/to/file # Diff the current version against path/to/file
# against the version at path/to/file
Git works in terms of commits, not files. Thus, working with the history of a
single file requires modified version of the show and diff commands.
```shell
# Find the commit you want in the file's commit log.
git log path/to/file
# This prints out the file contents at commit 123abc.
git show 123abc:path/to/file
# Diff the current version against path/to/file against the version at
# path/to/file
git diff 123abc -- path/to/file
```
When invoking `git show` or `git diff`, the `path/to/file` is **not relative the the current directory**. It must be the full path from the directory where the .git directory lives. This is different from invoking `git log` which understands relative paths.
When invoking `git show` or `git diff`, the `path/to/file` is **not relative the
the current directory**. It must be the full path from the directory where the
.git directory lives. This is different from invoking `git log` which
understands relative paths.
## Checking out pristine branch from git-svn
In the backend, git-svn keeps a remote tracking branch that points to the the commit tree representing the svn repository. The name of this branch is configured during `git svn init`. The git-svn remote branch is often named `origin/trunk` for Chromium, and `origin/master` for WebKit.
If you want to checkout a "fresh" branch, you can base it directly off the remote branch for svn.
In the backend, git-svn keeps a remote tracking branch that points to the the
commit tree representing the svn repository. The name of this branch is
configured during `git svn init`. The git-svn remote branch is often named
`origin/trunk` for Chromium, and `origin/master` for WebKit.
```
$ git checkout -b fresh origin/trunk # Replace with origin/master for webkit.
```
If you want to checkout a "fresh" branch, you can base it directly off the
remote branch for svn.
To find out what your git-svn remote branch name is, you can examine your `.git/config` file and look for the `svn-remote` entry. It will look something like this:
git checkout -b fresh origin/trunk # Replace with origin/master for webkit.
To find out what your git-svn remote branch name is, you can examine your
`.git/config` file and look for the `svn-remote` entry. It will look something
like this:
```
[svn-remote "svn"]
@ -142,10 +199,17 @@ To find out what your git-svn remote branch name is, you can examine your `.git/
fetch = trunk/src:refs/remotes/origin/trunk
```
The last line (`fetch = trunk/src:refs/remotes/origin/trunk`), says to make `trunk/src` on svn into `refs/remote/origin/trunk` in the local git checkout. Which means, the name of the svn remote branch name is `origin/trunk`. You can use this branch name for all sorts of actions (diff, log, show, etc.)
The last line (`fetch = trunk/src:refs/remotes/origin/trunk`), says to make
`trunk/src` on svn into `refs/remote/origin/trunk` in the local git checkout.
Which means, the name of the svn remote branch name is `origin/trunk`. You can
use this branch name for all sorts of actions (diff, log, show, etc.)
## Making your `git svn {fetch,rebase}` go fast
If you are pulling changes from the git repository in Chromium (or webkit), but your your `git svn` commands still seem to pull each change individually from svn, your repository is probably setup incorrectly. Make sure the entries in your `.git/config` look something like this:
If you are pulling changes from the git repository in Chromium (or WebKit), but
your your `git svn` commands still seem to pull each change individually from
svn, your repository is probably setup incorrectly. Make sure the entries in
your `.git/config` look something like this:
```
[remote "origin"]
@ -156,9 +220,16 @@ If you are pulling changes from the git repository in Chromium (or webkit), but
fetch = trunk/src:refs/remotes/origin/trunk
```
Here, `git svn fetch` will update the hash in refs/remotes/origin/trunk as per the `fetch =` line under `svn-remote`. Similarly, `git fetch` will update the **same** tag under `refs/remotes/origin`.
Here, `git svn fetch` will update the hash in refs/remotes/origin/trunk as per
the `fetch =` line under `svn-remote`. Similarly, `git fetch` will update the
**same** tag under `refs/remotes/origin`.
With this setup, `git fetch` will use the faster git protocol to pull changes down into `origin/trunk`. This effectively updates the high-water mark for `git-svn`. Later invocations of `git svn {find-rev, fetch, rebase}` will be be able to skip pulling those revisions down from the svn server. Instead, it will just run a regex over the commit log in `origin/trunk` and parse all the `git-svn-id` lines. To rebuild the mapping. Example:
With this setup, `git fetch` will use the faster git protocol to pull changes
down into `origin/trunk`. This effectively updates the high-water mark for
`git-svn`. Later invocations of `git svn {find-rev, fetch, rebase}` will be be
able to skip pulling those revisions down from the svn server. Instead, it
will just run a regex over the commit log in `origin/trunk` and parse all the
`git-svn-id` lines. To rebuild the mapping. Example:
```
commit 016d28b8c4959a3d28d2fbfb4b86c0361aad74ef
@ -167,28 +238,37 @@ Date: Mon Jul 19 19:09:41 2010 +0000
Revert r42636. That hack is no longer needed now that we removed the compact
location bar view.
BUG=38992
Review URL: http://codereview.chromium.org/3036004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52935 0039d316-1c4b-4281-b951-d872f2087c98
```
Will be parsed to map svn revision r52935 (on Google Code) to commit 016d28b8c4959a3d28d2fbfb4b86c0361aad74ef. The parsing will generate a lot of lines that look like `rXXXX = 01234ABCD`. It should generally take a minute or so when doing an incremental update.
Will be parsed to map svn revision r52935 (on Google Code) to commit
016d28b8c4959a3d28d2fbfb4b86c0361aad74ef. The parsing will generate a lot of
lines that look like `rXXXX = 01234ABCD`. It should generally take a minute or
so when doing an incremental update.
For this to work, two things must be true:
* The svn url in the `svn-remote` clause must exactly match the url in the git-svn-id pulled form the server.
* The fetch from origin must write into the exact same branch that specified in the fetch line of `svn-remote`.
* The svn url in the `svn-remote` clause must exactly match the url in the
git-svn-id pulled form the server.
* The fetch from origin must write into the exact same branch that specified
in the fetch line of `svn-remote`.
If either of these are not true, then `git svn fetch` and friends will talk to svn directly, and be very slow.
If either of these are not true, then `git svn fetch` and friends will talk to
svn directly, and be very slow.
## Reusing a Git mirror
If you have a nearby copy of a Git repo, you can quickly bootstrap your copy from that one then adjust it to point it at the real upstream one.
If you have a nearby copy of a Git repo, you can quickly bootstrap your copy
from that one then adjust it to point it at the real upstream one.
1. Clone a nearby copy of the code you want: `git clone coworker-machine:/path/to/repo`
1. Change the URL your copy fetches from to point at the real git repo: `git set-url origin http://src.chromium.org/git/chromium.git`
1. Update your copy: `git fetch`
1. Delete any extra branches that you picked up in the initial clone: `git prune origin`
1. Clone a nearby copy of the code you want: `git clone coworker-machine:/path/to/repo`
1. Change the URL your copy fetches from to point at the real git repo:
`git set-url origin http://src.chromium.org/git/chromium.git`
1. Update your copy: `git fetch`
1. Delete any extra branches that you picked up in the initial clone:
`git prune origin`

@ -1,26 +1,47 @@
When UsingGit, there are a few tips that are particularly useful when working on the Chromium codebase, especially due to its size.
# Git Tips
See also GitCookbook.
When using Git, there are a few tips that are particularly useful when working
on the Chromium codebase, especially due to its size.
Remember the basic git convention:
> `git` _`COMMAND`_ `[`_`FLAGS`_`]` `[`_`ARGUMENTS`_`]`
Various git commands have underlying executable with a hyphenated name, such as `git-grep`, but these can also be called via the `git` wrapper script as `git grep` (and `man` should work either way too).
[TOC]
## Remember the basic git convention:
git COMMAND [FLAGS] [ARGUMENTS]
Various git commands have underlying executable with a hyphenated name, such as
`git-grep`, but these can also be called via the `git` wrapper script as
`git grep` (and `man` should work either way too).
## Git references
The following resources can provide background on how Git works:
* [Git-SVN Crash Course](http://git-scm.com/course/svn.html) -- this crash course is useful for Subversion users switching to Git.
* [Think Like (a) Git](http://think-like-a-git.net/) -- does a great job of explaining the main purpose of Git's operations.
* [Git User's Manual](http://schacon.github.com/git/user-manual.html) -- a great resource to learn more about how to use Git properly.
* [A Visual Git Reference](http://marklodato.github.com/visual-git-guide/index-en.html) -- a resource that explains various Git operations for visual reasons.
* [Git Cheat Sheet](http://cheat.errtheblog.com/s/git) -- now that you understand Git, here's a cheat sheet to quickly remind you of all the commands you need.
* [Git-SVN Crash Course](http://git-scm.com/course/svn.html) -- this crash
course is useful for Subversion users witching to Git.
* [Think Like (a) Git](http://think-like-a-git.net/) -- does a great job of
explaining the main purpose of Git operations.
* [Git User's Manual](http://schacon.github.com/git/user-manual.html) -- a
great resource to learn more about ho to use Git properly.
* [A Visual Git Reference](http://marklodato.github.com/visual-git-guide/index-en.html)
-- a resource that explains various Git operations for visual reasons.
* [Git Cheat Sheet](http://cheat.errtheblog.com/s/git) -- now that you
understand Git, here's a cheat sheet to quickly remind you of all the
commands you need.
## Committing changes
For a simple workflow (always commit all changed files, don't keep local revisions), the following script handles check; you may wish to call it `gci` (git commit) or similar.
Amending a single revision is generally easier for various reasons, notably for rebasing and for checking that CLs have been committed. However, if you don't use local revisions (a local branch with multiple revisions), you should make sure to upload revisions periodically to code review if you ever need to go to an old version of a CL.
```
For a simple workflow (always commit all changed files, don't keep local
revisions), the following script handles check; you may wish to call it `gci`
(git commit) or similar.
Amending a single revision is generally easier for various reasons, notably for
rebasing and for checking that CLs have been committed. However, if you don't
use local revisions (a local branch with multiple revisions), you should make
sure to upload revisions periodically to code review if you ever need to go to
an old version of a CL.
```bash
#!/bin/bash
# Commit all, amending if not initial commit.
if git status | grep -q "# Your branch is ahead of 'master' by 1 commit."
@ -32,24 +53,33 @@ fi
```
## Listing and changing branches
```
```shell
git branch # list branches
git checkout - # change to last branch
```
To quickly list the 5 most recent branches, add the following to `.gitconfig` in the `[alias]` section:
```
last5 = "!git for-each-ref --sort=committerdate refs/heads/ --format='%(committerdate:short) %(refname:short)' | tail -5 | cut -c 12-"
To quickly list the 5 most recent branches, add the following to `.gitconfig`
in the `[alias]` section:
```shell
last5 = "!git for-each-ref --sort=committerdate refs/heads/ \
--format='%(committerdate:short) %(refname:short)' | tail -5 | cut -c 12-"
```
A nicely color-coded list, sorted in descending order by date, can be made by the following bash function:
```
A nicely color-coded list, sorted in descending order by date, can be made by
the following bash function:
```bash
git-list-branches-by-date() {
local current_branch=$(git rev-parse --symbolic-full-name --abbrev-ref HEAD)
local normal_text=$(echo -ne '\E[0m')
local yellow_text=$(echo -ne '\E[0;33m')
local yellow_bg=$(echo -ne '\E[7;33m')
git for-each-ref --sort=-committerdate \
--format=$' %(refname:short) \t%(committerdate:short)\t%(authorname)\t%(objectname:short)' refs/heads \
--format=$' %(refname:short) \
\t%(committerdate:short)\t%(authorname)\t%(objectname:short)' \
refs/heads \
| column -t -s $'\t' -n \
| sed -E "s:^ (${current_branch}) :* ${yellow_bg}\1${normal_text} :" \
| sed -E "s:^ ([^ ]+): ${yellow_text}\1${normal_text}:"
@ -57,30 +87,39 @@ git-list-branches-by-date() {
```
## Searching
Use `git-grep` instead of `grep` and `git-ls-files` instead of `find`, as these search only files in the index or _tracked_ files in the work tree, rather than all files in the work tree.
Note that `git-ls-files` is rather simpler than `find`, so you'll often need to use `xargs` instead of `-exec` if you want to process matching files.
Use `git-grep` instead of `grep` and `git-ls-files` instead of `find`, as these
search only files in the index or _tracked_ files in the work tree, rather than
all files in the work tree.
Note that `git-ls-files` is rather simpler than `find`, so you'll often need to
use `xargs` instead of `-exec` if you want to process matching files.
## Global changes
To make global changes across the source tree, it's often easiest to use `sed` with `git-ls-files`, using `-i` for in-place changing (this is generally safe, as we don't use symlinks much, but there are few places that do). Remember that you don't need to use `xargs`, since sed can take multiple input files. E.g., to strip trailing whitespace from C++ and header files:
```
sed -i -E 's/\s+$//' $(git ls-files '*.cpp' '*.h')
```
You may also find `git-grep` useful for limiting the scope of your changes, using `-l` for listing files.
```
sed -i -E '...' $(git grep -lw Foo '*.cpp' '*.h')
```
To make global changes across the source tree, it's often easiest to use `sed`
with `git-ls-files`, using `-i` for in-place changing (this is generally safe,
as we don't use symlinks much, but there are few places that do). Remember that
you don't need to use `xargs`, since sed can take multiple input files. E.g., to
strip trailing whitespace from C++ and header files:
sed -i -E 's/\s+$//' $(git ls-files '*.cpp' '*.h')
You may also find `git-grep` useful for limiting the scope of your changes,
using `-l` for listing files.
sed -i -E '...' $(git grep -lw Foo '*.cpp' '*.h')
Remember that you can restrict sed actions to matching (or non-matching) lines.
For example, to skip lines with a line comment, use the following:
'\,//, ! s/foo/bar/g'
Remember that you can restrict sed actions to matching (or non-matching) lines. For example, to skip lines with a line comment, use the following:
```
'\,//, ! s/foo/bar/g'
```
## Diffs
```
git diff --shortstat
```
git diff --shortstat
Displays summary statistics, such as:
```
2104 files changed, 9309 insertions(+), 9309 deletions(-)
```
2104 files changed, 9309 insertions(+), 9309 deletions(-)

@ -1,20 +1,30 @@
GN has several different ways to check dependencies. Many of them are checked by the `gn check` command. Running checks involve opening and scanning all source files so this isn't run every time a build is updated. To run check on an existing build:
```
gn check out/mybuild
```
# GN Check
To run the check as part of the "gen" command to update the build (this is what the bots do):
```
gn gen out/mybuild --check
```
GN has several different ways to check dependencies. Many of them are checked by
the `gn check` command. Running checks involve opening and scanning all source
files so this isn't run every time a build is updated. To run check on an
existing build:
# Concepts
gn check out/mybuild
## Visibility
To run the check as part of the "gen" command to update the build (this is what
the bots do):
Targets can control which other targets may depend on them by specifying `visibility`. Visibility is always checked when running any GN command (not just `gn check`.
gn gen out/mybuild --check
By default, targets are "public" meaning any target can depend on them. If you supply a list, visibility will be listed to those targets (possibly including wildcards):
[TOC]
## Concepts
### Visibility
Targets can control which other targets may depend on them by specifying
`visibility`. Visibility is always checked when running any GN command (not just
`gn check`.
By default, targets are "public" meaning any target can depend on them. If you
supply a list, visibility will be listed to those targets (possibly including
wildcards):
```
visibility = [
@ -26,11 +36,15 @@ visibility = [
See `gn help visibility` for more details and examples.
## Public header files
### Public header files
Targets can control which headers may be included by dependent targets so as to define a public API. If your target specifies only `sources`, then all headers listed there are public and can be included by all dependents.
Targets can control which headers may be included by dependent targets so as to
define a public API. If your target specifies only `sources`, then all headers
listed there are public and can be included by all dependents.
If your target defines a `public` variable, only the files listed in that list will be public. Files in `sources` but not `public` (they can be in both or only one) may not be included by dependent targets.
If your target defines a `public` variable, only the files listed in that list
will be public. Files in `sources` but not `public` (they can be in both or only
one) may not be included by dependent targets.
```
source_set("foo") {
@ -47,11 +61,15 @@ source_set("foo") {
}
```
## Public dependencies
### Public dependencies
In order to include files from your target, that target must be listed in your target's dependencies. By default, transitively depending on a target doesn't give your files this privilege.
In order to include files from your target, that target must be listed in your
target's dependencies. By default, transitively depending on a target doesn't
give your files this privilege.
If a target exposes a dependency as part of its public API, then it can list
that dependency as a `public_deps`:
If a target exposes a dependency as part of its public API, then it can list that dependency as a `public_deps`:
```
source_set("foo") {
sources = [ ... ]
@ -63,23 +81,32 @@ source_set("foo") {
]
}
```
Targets that depend on `foo` can include files from `base` but not from `doom_melon`. To include public headers from `doom\_melon, a target would need to depend directly on it.
Public dependencies work transitively, so listing a target as a public dependency also exposes that target's public dependencies. Along with the ability to include headers, public dependencies forward the `public_configs` which allow settings like defines and include directories to apply to dependents.
Targets that depend on `foo` can include files from `base` but not from
`doom_melon`. To include public headers from `doom\_melon, a target would need
to depend directly on it.
# Putting it all together
Public dependencies work transitively, so listing a target as a public
dependency also exposes that target's public dependencies. Along with the
ability to include headers, public dependencies forward the `public_configs`
which allow settings like defines and include directories to apply to
dependents.
## Putting it all together
In order to include a header from target Y in a file that is part of target X:
* X must be in Y's `visibility` list (or B must have no `visibility` defined).
* The header must be in Y's `public` headers (or Y must have no `public` variable defined).
* X must depend directly on Y, or there must be a path from X to Y following only public dependencies.
* X must be in Y's `visibility` list (or B must have no `visibility` defined).
* The header must be in Y's `public` headers (or Y must have no `public`
variable defined).
* X must depend directly on Y, or there must be a path from X to Y following
only public dependencies.
### What gets checked
Chrome currently doesn't come close to passing a `gn check` pass. You can check specific targets or subtrees for issues:
```
gn check out/mybuild //base
Chrome currently doesn't come close to passing a `gn check` pass. You can check
specific targets or subtrees for issues:
gn check out/mybuild "//mojo/*"
```
gn check out/mybuild //base
gn check out/mybuild "//mojo/*"

@ -1,34 +1,46 @@
# Introduction
# Graphical Debugging Aid for Chromium Views
A simple debugging tool exists to help visualize the views tree during debugging. It consists of 4 components:
## Introduction
1. The function `View::PrintViewGraph()` (already in the file **view.cc** if you've sync'd recently),
1. a gdb script file **viewg.gdb** (see below),
1. the graphViz package (http://www.graphviz.org/ - downloadable for Linux, Windows and Mac), and
1. an SVG viewer (_e.g._ Chrome).
A simple debugging tool exists to help visualize the views tree during
debugging. It consists of 4 components:
# Details
1. The function `View::PrintViewGraph()` (already in the file `view.cc` if
you've sync'd recently),
1. a gdb script file `viewg.gdb` (see below),
1. the graphViz package (http://www.graphviz.org/ - downloadable for Linux,
Windows and Mac), and
1. an SVG viewer (_e.g._ Chrome).
## Details
To use the tool,
1. Make sure you have 'dot' installed (part of graphViz),
1. define `TOUCH_DEBUG` and compile chrome with Views enabled,
1. run gdb on your build and
1. source **viewg.gdb** (this can be done automatically in **.gdbinit**),
1. stop at any breakpoint inside class `View` (or any derived class), and
1. type `viewg` at the gdb prompt.
1. Make sure you have 'dot' installed (part of graphViz),
1. define `TOUCH_DEBUG` and compile chrome with Views enabled,
1. run gdb on your build and
1. `source viewg.gdb` (this can be done automatically in `.gdbinit`),
1. stop at any breakpoint inside class `View` (or any derived class), and
1. type `viewg` at the gdb prompt.
This will cause the current view, and any descendants, to be described in a graph which is stored as **~/state.svg** (Windows users may need to modify the script slightly to run under CygWin). If **state.svg** is kept open in a browser window and refreshed each time `viewg` is run, then it provides a graphical representation of the state of the views hierarchy that is always up to date.
This will cause the current view, and any descendants, to be described in a
graph which is stored as `~/state.svg` (Windows users may need to modify the
script slightly to run under CygWin). If `state.svg` is kept open in a browser
window and refreshed each time `viewg` is run, then it provides a graphical
representation of the state of the views hierarchy that is always up to date.
It is easy to modify the gdb script to generate PDF in case viewing with evince (or other PDF viewer) is preferred.
It is easy to modify the gdb script to generate PDF in case viewing with evince
(or other PDF viewer) is preferred.
If you don't use gdb, you may be able to adapt the script to work with your favorite debugger. The gdb script invokes
```
this->PrintViewGraph(true)
```
on the current object, returning `std::string`, whose contents must then be saved to a file in order to be processed by dot.
If you don't use gdb, you may be able to adapt the script to work with your
favorite debugger. The gdb script invokes
# viewg.gdb
this->PrintViewGraph(true)
on the current object, returning `std::string`, whose contents must then be
saved to a file in order to be processed by dot.
## viewg.gdb
```
define viewg
@ -48,4 +60,4 @@ define viewg
set pagination on
end
end
```
```