1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
-
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
|
<h1>Hacker's Guide</h1>
# Hacker's Guide
See also: [building], [AmalgamationBuild]
See also: [](building), [](AmalgamationBuild)
This page primarily contains notes for anyone who's actively hacking on libfossil internals, e.g. changing <tt>fsl_cx</tt>'s structure.
An <em>exceedingly brief</em> intro to the source tree:
* The primary "exported" distributable is the [AmalgamationBuild]. The other sources and headers are essentially components for creating that deliverable.
* Public headers go in <tt>include/fossil-scm/</tt>. There is at least one pseudo-private header (<tt>fossil-internal.h</tt>) there as well, but that one is under consideration for being moved to...
* Private impl files and headers go in <tt>src/</tt>.
* Demo/test apps can be found in <tt>f-apps/</tt>.
* The truly adventurous might wand to explore the other various subdirs, like <tt>sql/</tt> (schema files), <tt>cpp/</tt> (one potential C++ binding) and <tt>s2/</tt> (script bindings).
* The primary "exported" distributable is the [](AmalgamationBuild). The other sources and headers are essentially components for creating that deliverable.
* Public headers go in `include/fossil-scm/`. There is at least one pseudo-private header (`fossil-internal.h`) there as well, but that one is under consideration for being moved to...
* Private impl files and headers go in [src/](/dir/src).
* Demo/test apps can be found in [f-apps/])/dir/f-apps).
* The truly adventurous might want to explore the other various subdirs, like [sql/](/dir/sql) (schema files - these get compiled into the library as C code), [bindings/cpp/](/dir/bindings/cpp) (one of any number of potential C++ bindings) and [bindings/s2/](/dir/bindings/s2) (one of any number of potential script bindings).
* The "native" build platform requires GNU Make 3.81 or higher and the conventional set of Unix-side build tools. Contributions of control files (or READMEs) for other build platforms are of course welcomed.
* The overall style is a direct artifact (as it were) of fossil(1), and we ask that all contributors maintain the general overall style. We are <em>not</em> picky about placement of spaces around parenthesis and whatnot, mainly just the overall indentation and <tt>{</tt>bracing<tt>}</tt> styles, as well as the naming style for public symbols (e.g. a prefix of "fsl_" on most symbols). The one notable exception is how APIs are documented: libfossil uses Doxygen style (and Doxygen cannot swallow fossil's native comment style).
* The overall style is a direct artifact (as it were) of fossil(1), and we ask that all contributors maintain the _general overall_ style. We are _not_ picky about placement of spaces around parenthesis and whatnot, mainly just the overall 2-space indentation and `{` bracing `}` styles, as well as the naming style for public symbols (e.g. a prefix of `fsl_` on most symbols). The one notable exception is how APIs are documented: libfossil uses Doxygen style and Doxygen cannot swallow fossil's native comment style.
## Getting it Running Locally (on Unix-like systems)
Because of where the libs live vs where the binaries live, the easiest ways to get the source tree running its test apps are...
The following text assumes the `{CHECKOUT}` is the top-most directory of this source tree's checkout and that the tree has been built already.
First, and simplest, is to add `{CHECKOUT}/src` to one's `$LD_LIBRARY_PATH` and `{CHECKOUT}/bin` to the `$PATH`. `libfossil.*` lives, as of this writing, in the `src` dir, but building from the top-most directory will also symlink those there.
Slightly more elaborate is to...
1) From a directory in the `$LD_LIBRARY PATH`, type: `ln -s {CHECKOUT}/src/libfossil.* .`
2) Symlink all of the [f-apps](/dir/f-apps/) to a directory in the `$PATH`. For example:
```
cd ~/bin
for i in {CHECKOUT}/f-apps/f-*; do
test -x $i || continue # filter out .o/.c files
ln -s $i .
done
```
As new f-apps are added, add a symlink to the appropriate directory.
<h2>An Introduction to structs...</h2>
## An Introduction to structs...
All (or almost all) structs in the library are accompanied by other constructs which help ensure (insure?) consistency regarding how library-level structs are to be initialized. The general pattern looks like this:
All (or almost all) structs in the library are accompanied by other constructs which help ensure consistency regarding how library-level structs are to be initialized. The general pattern looks like this:
<nowiki><pre>
```
struct fsl_foo { ... };
typedef struct fsl_foo fsl_foo;
extern const fsl_foo_empty;
#define fsl_foo_empty_m { ...member initializers... }
</pre></nowiki>
```
The purpose of the "empty_m" macro is to define a cleanly-initialized const state for that struct. The <tt>fsl_foo_empty</tt> instance is guaranteed to be initialized using <tt>fsl_foo_empty_m</tt>, but both the "empty" and "empty_m" variants are provided because code requires different initializers in different contexts (examples are provided below).
The purpose of the `_empty_m` macro is to define a cleanly-initialized const state for that struct. The `fsl_foo_empty` instance is guaranteed to be initialized using `fsl_foo_empty_m`, but both the `empty` and `empty_m` variants are provided because code requires different initializers in different contexts (examples are provided below).
The "_m" suffix denotes "macro", by the way.
The `_m` suffix denotes "macro", by the way.
All non-opaque structs can and should be initialized in code like this:
<nowiki><pre>
```
fsl_buffer buf = fsl_buffer_empty;
fsl_deck deck = fsl_deck_empty;
// The "empty_m" macros are required mainly for in-struct initialization:
struct {
fsl_buffer buf;
fsl_deck deck;
} foo = {
fsl_buffer_empty_m,
fsl_deck_empty_m
};
</pre></nowiki>
```
That ensures (insures?) that all struct members get set to known default values (which need not be NULL/0), and helps harden the code against uninitialized memory access (since all members get initialized to whatever the struct developer deemed sensible, and NULL is generally the sensible default for pointer members).
That ensures that all struct members get set to known default values (which need not be NULL/0), and helps harden the code against uninitialized memory access (since all members get initialized to whatever the struct developer deemed sensible, and NULL is generally the sensible default for pointer members).
<h2>When updating structs...</h2>
## When updating structs...
When changing the members of structs, it is <em>critical</em> that the accompanying "empty_m" macro (described above) also be updated. Failing to do so can lead to undefined results (best case is a compilation failure when the shared struct "empty" instance is initialized from the "empty_m" macro).
When changing the members of structs, it is _critical_ that the accompanying `empty_m` macro (described above) also be updated. Failing to do so can lead to undefined results (best case is a compilation failure when the shared struct `empty` instance is initialized from the `empty_m` macro).
After changing a struct, make sure to do a full/clean rebuild or you might see <em>really</em> weird results in code compiled against older struct.
After changing a struct, make sure to do a full/clean rebuild or you might see _really_ weird results in code compiled against older struct.
<nowiki><pre>
</pre></nowiki>
|