-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathHACKING
330 lines (238 loc) · 11.7 KB
/
HACKING
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
#
# Copyright (C) 2013 Canonical Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Authored by: Michi Henning <[email protected]>
#
-------------------------------------------------------------------------------------
NOTE: Before making changes to the code, please read the README file in its entirety!
-------------------------------------------------------------------------------------
Building the code
-----------------
By default, the code is built in release mode. To build a debug version, use
$ mkdir builddebug
$ cd builddebug
$ cmake -DCMAKE_BUILD_TYPE=debug ..
$ make
For a release version, use -DCMAKE_BUILD_TYPE=release
Running the tests
-----------------
$ make
$ make test
Note that "make test" alone is dangerous because it does not rebuild
any tests if either the library or the test files themselves need
rebuilding. It's not possible to fix this with cmake because cmake cannot
add build dependencies to built-in targets. To make sure that everything
is up-to-date, run "make" before running "make test"!
Some tests are slow. If you want to skip them during development,
you can set the cmake option "slowtests" to OFF.
To run the tests with valgrind:
$ make valgrind
It doesn't make sense for some tests to run them with valgrind. For
example, the header compilation tests don't need valgrind because
we'd just be testing that Python doesn't leak. There are also some
tests that run too slow and time out under valgrind and, occasionally,
valgrind crashes for a particular test.
There are two ways to suppress tests:
You can add a test name to CTestCustom.cmake.in to suppress that
test completely. That makes sense for the header compilation tests,
for example.
If a specific test case in a test program causes a valgrind problem,
you can selectively disable a section of code like this:
#include <valgrind/valgrind.h>
if (!RUNNING_ON_VALGRIND)
{
// Code here crashes valgrind...
}
That way, the test will still be run as part of the normal "make test"
target, but will be ommitted when running "make valgrind".
Coverage
--------
To build with the flags for coverage testing enabled and get coverage:
$ mkdir buildcoverage
$ cd buildcoverage
$ cmake -DCMAKE_BUILD_TYPE=coverage
$ make
$ make test
$ make coverage
Unfortunately, it is not possible to get 100% coverage for some files,
mainly due to gcc's generation of two destructors for dynamic and non-
dynamic instances. For abstract base classes and for classes that
prevent stack and static allocation, this causes one of the destructors
to be reported as uncovered.
There are also issues with some functions in header files that are
incorrectly reported as uncovered due to inlining, as well as
the impossibility of covering defensive assert(false) statements,
such as an assert in the default branch of a switch, where the
switch is meant to handle all possible cases explicitly.
If you run a binary and get lots of warnings about a "merge mismatch for summaries",
this is caused by having made changes to the source that add or remove code
that was previously run, so the new coverage output cannot sensibly be merged
into the old coverage output. You can get rid of this problem by running
$ make clean-coverage
This deletes all the .gcda files, allowing the merge to (sometimes) succeed again.
If this doesn't work either, the only remedy is to do a clean build.
If lcov complains about unrecognized lines involving '=====',
you can patch geninfo and gcovr as explained here:
https://bugs.launchpad.net/gcovr/+bug/1086695/comments/2
To run the static C++ checks:
$ make cppcheck
Code style
----------
We use a format tool that fixes a whole lot of issues
regarding code style. The formatting changes made by
the tool are generally sensible (even though they may not be your
personal preference in all cases). If there is a case where the formatting
really messes things up, consider re-arranging the code to avoid the problem.
The convenience of running the entire code base through the pretty-printer
far outweighs any minor glitches with pretty printing, and it means that
we get consistent code style for free, rather than endlessly having to
watch out for formatting issues during code reviews.
As of clang-format-3.7, you can use
// clang-format off
void unformatted_code ;
// clang-format on
to suppress formatting for a section of code.
To format specific files:
${CMAKE_BINARY_DIR}/tools/formatcode x.cpp x.h
If no arguments are provided, formatcode reads stdin and writes
stdout, so you can easily pipe code into the tool from within an
editor. For example, to reformat the entire file in vi (assuming
${CMAKE_BINARY_DIR}/tools is in your PATH):
1G!Gformatcode
To re-format all source and header files in the tree:
$ make formatcode
Thread and address sanitizer
----------------------------
Set SANITIZER to "thread" or "address" to build with the
corresponding sanitizer enabled.
zmq (as 3.2.3 and 4.0.3) causes a large number of warnings from
thread sanitizer. It appears impossible to avoid these; they
are caused by issues in the zmq library. The tsan-suppress file
supresses the benign race conditions we currently know about. To
run the tests (from the build directory) with these suppressions
enabled, use:
$ TSAN_OPTIONS="suppressions=../tsan-suppress" make test
If a test runs too slowly under address sanitizer, you can
hide a section of code from address sanitzer with:
#if defined(__has_feature)
#if !__has_feature(address_sanitizer)
// Code here takes forever under address sanitizer...
#endif
#endif
ABI compatibility
-----------------
Version numbers for both libraries use <major>.<minor>.<micro>.
On Vivid, the soversion for the libraries are a single
integer, such as 3. That integer increments every time
the minor or major version is changed.
On Wily and later, the soversion is of the form <major>.<minor>.
The version numbers for the libraries are generated from files
in the debian directory. (See below for general rules on versioning.)
There are no version numbers defined in any of the MakeLists.txt files.
Instead, to change the version numbers, you must edit the following
files:
- VERSION
The full version number for libunity-scopes.
- QT-VERSION
The full version number for libunity-scopes-qt.
- *If* the soname changes, you need to add the outdated
versions to the "Replaces:" and "Conflicts:" entries
in control.in. (You need an extra entry for each Vivid and
Wily/Xenial and later.)
See bileto_pre_release_hook for the sed scripts that append a
line to the stanza if the soname is changed. This also may apply
if the soname of the Qt library changes, in which case
bileto_pre_release_hook needs a corresponding update.
- LAST_ABI_ADDITION_VERSION
The micro version at which we last added something
new to the libunity-scopes ABI (without breaking anything).
- LAST_ABI_ADDITION_QT-VERSION
The micro version at which we last added something
new to the libunity-scopes-qt ABI (without breaking anything).
The version files have the format
<major>.<minor>.<micro>
All three numbers must be present.
The soversion for each library is derived from the corresponding
version file so, unless the soversion changes, you don't need to
do anything special.
Versioning rules:
By definition, if a change is ABI compatible, you must increment
the micro version number. (Without this, we cannot
identify from the version number whether a particular fix
is in this build or not.) The best time to update the micro
version is when creating a silo for landing in the archives.
For changes in behavior that do *not* add anything new to the ABI, you must
increment the micro version in VERSION or QT-VERSION, but *not* the
version in LAST_ABI_ADDITION_VERSION or LAST_ABI_ADDITION_QT-VERSION.
For changes that add something to the ABI (without breaking it), you *must*
increment *both* VERSION and LAST_ABI_ADDITION_VERSION (or
QT-VERSION and LAST_ABI_ADDITION_QT-VERSION).
For ABI incompatible changes, either minor or major must be
incremented, and the lower-order version numbers must be reset to zero.
A change in major version number is meant to indicate major official releases.
What is "major" or "official" is somewhat arbitrary; unless we
are about to release a new Ubuntu version or there are major
feature changes in the scopes run time or API, incrementing
the minor version number is sufficient.
The .so version for the library is <major>.<minor>. For example,
version 1.3.1 has the name libunity-scopes.so.1.3. (On Vivid only,
for libunity-scopes.so only, the .so version is a single integer,
such as libunity-scopes.so.3. (It is derived from the minor version
number.)
When incrementing the minor or major version number, follow these steps:
1) Edit one or more of the version files, control, and control.in as
described above. Also verify that debian/bileto_pre_release_hook correctly
updates the "Replaces:" and "Conflicts:" entries.
2) Add an entry to debian/changelog with the new version number (for Wily).
3) Update RELEASE_NOTES.md
4) Add new ABI baseline files to test/abi-compliance/abi_dumps (see below).
ABI compliance test
-------------------
The tests include an ABI compliance test (for xenial and later). To run it:
$ cd test/abi-compliance
$ make test
The test is also automatically run as part of the test suite.
It takes a while to run. If you don't want to wait during local builds,
set the cmake "slowtests" option to OFF to skip the check.
The baseline ABI files for the test are in test/abi-compliance/abi_dumps.
There is a separate directory for each architecture.
The ABI dump files should never be updated or removed.
Instead, when the ABI changes, you need to add a new baseline
ABI file for each architecture. The easiest way to generate
these files is to make a branch with a modified install file
that installs the ABI dump in, say, /usr/lib. Then throw
the branch at a silo to get it built for all architectures.
Once all the packages are built, you can extract the ABI dump
files and add them to the corresponding directory in the source tree.
The abi compliance test produces a report in
libunity-scopes_<current-version>_abi-report.txt if anything unusual is detected.
Autopkg test suite
------------------
Scopes come with an autopkg smoke test.
http://packaging.ubuntu.com/html/auto-pkg-test.html
Running the test manually is simple. After building and installing the
new packages, just run 'sh debian/tests/scopebuild'.
To run the autopkg tests the same way Jenkins does, without installing
the packages, follow the instructions here:
http://packaging.ubuntu.com/html/auto-pkg-test.html
When adding new tests to debian/tests, be sure that the new tests
are built and run by adding them to tests/autopkg. Doing this doesn't
run the tests exactly the same way as on Jenkins because they will
be built and run against the headers and library in the build area,
rather than against the installed packages. But it provides a basic
sanity check for them. Without this, it's very easy to make a breaking
change to the API and forgetting to update the autopkg tests too,
meaning that the failure will show up only in Jenkins, but not
when running the tests locally.