Manual docs tweaks still in preparation for including docs with code pushes

This commit is contained in:
Gennadiy Civil 2019-07-18 15:27:51 -04:00
parent a743249a55
commit b77e5c7625
3 changed files with 111 additions and 103 deletions

View File

@ -174,9 +174,9 @@ We list the most frequently used macros below. For a complete list, see file
### Multi-threaded Tests
Google Test is thread-safe where the pthread library is available. After
`#include "gtest/gtest.h"`, you can check the `GTEST_IS_THREADSAFE` macro to see
whether this is the case (yes if the macro is `#defined` to 1, no if it's
undefined.).
`#include "gtest/gtest.h"`, you can check the
`GTEST_IS_THREADSAFE` macro to see whether this is the case (yes if the macro is
`#defined` to 1, no if it's undefined.).
If Google Test doesn't correctly detect whether pthread is available in your
environment, you can force it with

View File

@ -1,25 +1,24 @@
## Using GoogleTest from various build systems ##
## Using GoogleTest from various build systems
GoogleTest comes with pkg-config files that can be used to determine all
necessary flags for compiling and linking to GoogleTest (and GoogleMock).
Pkg-config is a standardised plain-text format containing
* the includedir (-I) path
* necessary macro (-D) definitions
* further required flags (-pthread)
* the library (-L) path
* the library (-l) to link to
* the includedir (-I) path
* necessary macro (-D) definitions
* further required flags (-pthread)
* the library (-L) path
* the library (-l) to link to
All current build systems support pkg-config in one way or another. For
all examples here we assume you want to compile the sample
All current build systems support pkg-config in one way or another. For all
examples here we assume you want to compile the sample
`samples/sample3_unittest.cc`.
### CMake ###
### CMake
Using `pkg-config` in CMake is fairly easy:
``` cmake
```cmake
cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0048 NEW)
@ -43,11 +42,10 @@ that all libraries have been compiled with threading enabled. In addition,
GoogleTest might also require `-pthread` in the compiling step, and as such
splitting the pkg-config `Cflags` variable into include dirs and macros for
`target_compile_definitions()` might still miss this). The same recommendation
goes for using `_LDFLAGS` over the more commonplace `_LIBRARIES`, which
happens to discard `-L` flags and `-pthread`.
goes for using `_LDFLAGS` over the more commonplace `_LIBRARIES`, which happens
to discard `-L` flags and `-pthread`.
### Autotools ###
### Autotools
Finding GoogleTest in Autoconf and using it from Automake is also fairly easy:
@ -77,8 +75,7 @@ testapp_CXXFLAGS = $(GTEST_CFLAGS)
testapp_LDADD = $(GTEST_LIBS)
```
### Meson ###
### Meson
Meson natively uses pkgconfig to query dependencies:
@ -96,13 +93,12 @@ testapp = executable(
test('first_and_only_test', testapp)
```
### Plain Makefiles
### Plain Makefiles ###
Since `pkg-config` is a small Unix command-line utility, it can be used in
handwritten `Makefile`s too:
Since `pkg-config` is a small Unix command-line utility, it can be used
in handwritten `Makefile`s too:
``` Makefile
```Makefile
GTEST_CFLAGS = `pkg-config --cflags gtest_main`
GTEST_LIBS = `pkg-config --libs gtest_main`
@ -120,12 +116,11 @@ testapp.o: samples/sample3_unittest.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $< -c -o $@ $(GTEST_CFLAGS)
```
### Help! pkg-config can't find GoogleTest! ###
### Help! pkg-config can't find GoogleTest!
Let's say you have a `CMakeLists.txt` along the lines of the one in this
tutorial and you try to run `cmake`. It is very possible that you get a
failure along the lines of:
tutorial and you try to run `cmake`. It is very possible that you get a failure
along the lines of:
```
-- Checking for one of the modules 'gtest_main'
@ -135,9 +130,9 @@ CMake Error at /usr/share/cmake/Modules/FindPkgConfig.cmake:640 (message):
These failures are common if you installed GoogleTest yourself and have not
sourced it from a distro or other package manager. If so, you need to tell
pkg-config where it can find the `.pc` files containing the information.
Say you installed GoogleTest to `/usr/local`, then it might be that the
`.pc` files are installed under `/usr/local/lib64/pkgconfig`. If you set
pkg-config where it can find the `.pc` files containing the information. Say you
installed GoogleTest to `/usr/local`, then it might be that the `.pc` files are
installed under `/usr/local/lib64/pkgconfig`. If you set
```
export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig

View File

@ -1,52 +1,51 @@
<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming.
# The Problem #
# The Problem
Template and macro libraries often need to define many classes,
functions, or macros that vary only (or almost only) in the number of
arguments they take. It's a lot of repetitive, mechanical, and
error-prone work.
Template and macro libraries often need to define many classes, functions, or
macros that vary only (or almost only) in the number of arguments they take.
It's a lot of repetitive, mechanical, and error-prone work.
Variadic templates and variadic macros can alleviate the problem.
However, while both are being considered by the C++ committee, neither
is in the standard yet or widely supported by compilers. Thus they
are often not a good choice, especially when your code needs to be
portable. And their capabilities are still limited.
Variadic templates and variadic macros can alleviate the problem. However, while
both are being considered by the C++ committee, neither is in the standard yet
or widely supported by compilers. Thus they are often not a good choice,
especially when your code needs to be portable. And their capabilities are still
limited.
As a result, authors of such libraries often have to write scripts to
generate their implementation. However, our experience is that it's
tedious to write such scripts, which tend to reflect the structure of
the generated code poorly and are often hard to read and edit. For
example, a small change needed in the generated code may require some
non-intuitive, non-trivial changes in the script. This is especially
painful when experimenting with the code.
As a result, authors of such libraries often have to write scripts to generate
their implementation. However, our experience is that it's tedious to write such
scripts, which tend to reflect the structure of the generated code poorly and
are often hard to read and edit. For example, a small change needed in the
generated code may require some non-intuitive, non-trivial changes in the
script. This is especially painful when experimenting with the code.
# Our Solution #
# Our Solution
Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta
Programming, or Practical Utility for Meta Programming, whichever you
prefer) is a simple meta-programming tool for C++. The idea is that a
programmer writes a `foo.pump` file which contains C++ code plus meta
code that manipulates the C++ code. The meta code can handle
iterations over a range, nested iterations, local meta variable
definitions, simple arithmetic, and conditional expressions. You can
view it as a small Domain-Specific Language. The meta language is
designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode,
for example) and concise, making Pump code intuitive and easy to
maintain.
Programming, or Practical Utility for Meta Programming, whichever you prefer) is
a simple meta-programming tool for C++. The idea is that a programmer writes a
`foo.pump` file which contains C++ code plus meta code that manipulates the C++
code. The meta code can handle iterations over a range, nested iterations, local
meta variable definitions, simple arithmetic, and conditional expressions. You
can view it as a small Domain-Specific Language. The meta language is designed
to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, for example) and
concise, making Pump code intuitive and easy to maintain.
## Highlights ##
## Highlights
* The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms.
* Pump tries to be smart with respect to [Google's style guide](https://github.com/google/styleguide): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly.
* The format is human-readable and more concise than XML.
* The format works relatively well with Emacs' C++ mode.
* The implementation is in a single Python script and thus ultra portable: no
build or installation is needed and it works cross platforms.
* Pump tries to be smart with respect to
[Google's style guide](https://github.com/google/styleguide): it breaks long
lines (easy to have when they are generated) at acceptable places to fit
within 80 columns and indent the continuation lines correctly.
* The format is human-readable and more concise than XML.
* The format works relatively well with Emacs' C++ mode.
## Examples ##
## Examples
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line):
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are
meta brackets, and `$$` starts a meta comment that ends with the line):
```
$var n = 3 $$ Defines a meta variable n.
@ -71,7 +70,7 @@ $if i == 0 [[
will be translated by the Pump compiler to:
``` cpp
```cpp
// Foo0 does blah for 0-ary predicates.
template <size_t N>
class Foo0 {
@ -105,9 +104,10 @@ Func($for i + [[a$i]]);
$$ The text between i and [[ is the separator between iterations.
```
will generate one of the following lines (without the comments), depending on the value of `n`:
will generate one of the following lines (without the comments), depending on
the value of `n`:
``` cpp
```cpp
Func(); // If n is 0.
Func(a1); // If n is 1.
Func(a1 + a2); // If n is 2.
@ -115,32 +115,38 @@ Func(a1 + a2 + a3); // If n is 3.
// And so on...
```
## Constructs ##
## Constructs
We support the following meta programming constructs:
| `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. |
|:----------------|:-----------------------------------------------------------------------------------------------|
| `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later. |
| `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. |
| `$($)` | Generates a single `$` character. |
| `$id` | Value of the named constant or iteration variable. |
| `$(exp)` | Value of the expression. |
| `$if exp [[ code ]] else_branch` | Conditional. |
| `[[ code ]]` | Meta lexical block. |
| `cpp_code` | Raw C++ code. |
| `$$ comment` | Meta comment. |
| `$var id = exp` | Defines a named constant value. `$id` is |
: : valid util the end of the current meta :
: : lexical block. :
| :------------------------------- | :--------------------------------------- |
| `$range id exp..exp` | Sets the range of an iteration variable, |
: : which can be reused in multiple loops :
: : later. :
| `$for id sep [[ code ]]` | Iteration. The range of `id` must have |
: : been defined earlier. `$id` is valid in :
: : `code`. :
| `$($)` | Generates a single `$` character. |
| `$id` | Value of the named constant or iteration |
: : variable. :
| `$(exp)` | Value of the expression. |
| `$if exp [[ code ]] else_branch` | Conditional. |
| `[[ code ]]` | Meta lexical block. |
| `cpp_code` | Raw C++ code. |
| `$$ comment` | Meta comment. |
**Note:** To give the user some freedom in formatting the Pump source
code, Pump ignores a new-line character if it's right after `$for foo`
or next to `[[` or `]]`. Without this rule you'll often be forced to write
very long lines to get the desired output. Therefore sometimes you may
need to insert an extra new-line in such places for a new-line to show
up in your output.
**Note:** To give the user some freedom in formatting the Pump source code, Pump
ignores a new-line character if it's right after `$for foo` or next to `[[` or
`]]`. Without this rule you'll often be forced to write very long lines to get
the desired output. Therefore sometimes you may need to insert an extra new-line
in such places for a new-line to show up in your output.
## Grammar ##
## Grammar
``` ebnf
```ebnf
code ::= atomic_code*
atomic_code ::= $var id = exp
| $var id = [[ code ]]
@ -159,19 +165,26 @@ else_branch ::= $else [[ code ]]
exp ::= simple_expression_in_Python_syntax
```
## Code ##
## Code
You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still
very unpolished and lacks automated tests, although it has been
successfully used many times. If you find a chance to use it in your
project, please let us know what you think! We also welcome help on
improving Pump.
You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py).
It is still very unpolished and lacks automated tests, although it has been
successfully used many times. If you find a chance to use it in your project,
please let us know what you think! We also welcome help on improving Pump.
## Real Examples ##
## Real Examples
You can find real-world applications of Pump in [Google Test](https://github.com/google/googletest/tree/master/googletest) and [Google Mock](https://github.com/google/googletest/tree/master/googlemock). The source file `foo.h.pump` generates `foo.h`.
You can find real-world applications of Pump in
[Google Test](https://github.com/google/googletest/tree/master/googletest) and
[Google Mock](https://github.com/google/googletest/tree/master/googlemock). The
source file `foo.h.pump` generates `foo.h`.
## Tips ##
## Tips
* If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1.
* To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line.
* If a meta variable is followed by a letter or digit, you can separate them
using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper`
generate `Foo1Helper` when `j` is 1.
* To avoid extra-long Pump source lines, you can break a line anywhere you
want by inserting `[[]]` followed by a new line. Since any new-line
character next to `[[` or `]]` is ignored, the generated code won't contain
this new line.