HACKING 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. Coreutils Contribution Guidelines
  2. Prerequisites
  3. =============
  4. You will need the "git" version control tools.
  5. On Fedora-based systems, do "yum install git".
  6. On Debian-based ones install the "git-core" package.
  7. Then run "git --version". If that says it's older than
  8. version 1.4.4, then you'd do well to get a newer version.
  9. At worst, just download the latest stable release from
  10. https://git-scm.com/ and build from source.
  11. For details on building the programs in this package, see
  12. the file, README-hacking.
  13. Use the latest upstream sources
  14. ===============================
  15. Base any changes you make on the latest upstream sources.
  16. You can get a copy of the latest with this command:
  17. git clone git://git.sv.gnu.org/coreutils
  18. cd coreutils
  19. That downloads the entire repository, including revision control history
  20. dating back to 1991. The repository (the part you download, and which
  21. resides in coreutils/.git) currently weighs in at about 30MB. So you
  22. don't want to download it more often than necessary. Once downloaded,
  23. you can get incremental updates by running one of these commands from
  24. inside your new coreutils/ directory:
  25. If you have made *no* changes:
  26. git pull
  27. If you *have* made changes and mistakenly committed them to "master",
  28. do the following to put your changes on a private branch, "br", and
  29. to restore master to its unmodified (relative-to-upstream) state:
  30. git checkout -b br
  31. git checkout master
  32. git reset --hard origin
  33. Then "git pull" should work.
  34. *Before* you commit changes
  35. ===========================
  36. In this project, we much prefer patches that automatically record
  37. authorship. That is important not just to give credit where due, but
  38. also from a legal standpoint (see below). To create author-annotated
  39. patches with git, you must first tell git who you are. That information
  40. is best recorded in your ~/.gitconfig file. Edit that file, creating
  41. it if needed, and put your name and email address in place of these
  42. example values:
  43. [user]
  44. name = Joe X. User
  45. email = joe.user@example.com
  46. Your first commit: the quick and dirty way
  47. ==========================================
  48. First of all, realize that to "commit" a change in git is a purely
  49. local operation. It affects only the local repository (the .git/ dir)
  50. in your current coreutils/ hierarchy.
  51. To try this out, modify a file or two. If you create a new file, you'll
  52. need to tell git about it with "git add new-file.c". Commit all changes
  53. with "git commit -a". That prompts you for a log message, which should
  54. include a one-line summary, a blank line, and ChangeLog-style entries
  55. for all affected files. More on that below.
  56. Once your change is committed, you can create a proper patch that includes
  57. a log message and authorship information as well as any permissions
  58. changes. Use this command to save that single, most-recent change set:
  59. git format-patch --stdout -1 > DIFF
  60. The trouble with this approach is that you've just checked in a change
  61. (remember, it's only local) on the "master" branch, and that's where new
  62. changes would normally appear when you pull the latest from "upstream".
  63. When you "pull" from a remote repository to get the latest, your local
  64. changes on "master" may well induce conflicts. For this reason, you
  65. may want to keep "master" free of any local changes, so that you can
  66. use it to track unadulterated upstream sources.
  67. However, if your cloned directory is for a one-shot patch submission and
  68. you're going to remove it right afterwards, then this approach is fine.
  69. Otherwise, for a more sustainable (and more generally useful, IMHO)
  70. process, read on about "topic" branches.
  71. Make your changes on a private "topic" branch
  72. =============================================
  73. So you checked out coreutils like this:
  74. git clone git://git.sv.gnu.org/coreutils
  75. Now, cd into the coreutils/ directory and run:
  76. git checkout -b my-topic
  77. That creates the my-topic branch and puts you on it.
  78. To see which branch you're on, type "git branch".
  79. Right after the clone, you were on "master" (aka the trunk).
  80. To get back to the trunk, do this:
  81. git checkout master
  82. Note 1:
  83. Be careful to run "git pull" only when on the "master" branch,
  84. not when on a branch. With newer versions of git, you can't cause
  85. trouble if you forget, so this is a good reason to ensure you're
  86. using 1.5.3.1 or newer.
  87. Note 2:
  88. It's best not to try to switch from one branch to another if
  89. you have pending (uncommitted) changes. Sometimes it works,
  90. sometimes the checkout will fail, telling you that your local
  91. modifications conflict with changes required to switch branches.
  92. However, in any case, you will *not* lose your uncommitted changes.
  93. Run "git stash" to temporarily hide uncommitted changes in your
  94. local directory, restoring a clean working directory.
  95. Anyhow, get back onto your just-created branch:
  96. git checkout my-topic
  97. Now, modify some file and commit it:
  98. git commit some-file.c
  99. Personally, no matter what package I'm working on, I find it useful to
  100. put the ChangeLog entries *only* in the commit log, initially, unless
  101. I plan to commit/push right away. Otherwise, I tend to get unnecessary
  102. merge conflicts with each rebase (see below). In coreutils, I've gone
  103. a step further, and no longer maintain an explicit ChangeLog file in
  104. version control. Instead, in a git working directory, you can view
  105. ChangeLog information via "git log". However, each distribution tarball
  106. does include a ChangeLog file that is automatically generated from the
  107. git logs.
  108. So, you've committed a change. But it's only in your local repository,
  109. and only on your "my-topic" branch. Let's say you wait a day, and
  110. then see that someone else changed something and pushed it to the
  111. public repository. Now, you want to update your trunk and "rebase"
  112. your changes on the branch so that they are once again relative to the
  113. tip of the trunk. Currently, your branch is attached to the trunk at
  114. the next-to-last change set.
  115. First: update the trunk from the public repo:
  116. [you've first made sure that "git diff" produces no output]
  117. git checkout master
  118. git pull
  119. Now, return to your branch, and "rebase" relative to trunk (master):
  120. git checkout my-topic
  121. git rebase master
  122. If there are no conflicts, this requires no more work from you.
  123. However, let's say there was one in ChangeLog, since you didn't
  124. follow my advice and modified it anyway.
  125. git rebase will tell you there was a conflict and in which
  126. file, and instruct you to resolve it and then resume with
  127. "git rebase --continue" once that's done.
  128. So you resolve as usual, by editing ChangeLog (which has the
  129. usual conflict markers), then type "git rebase --continue".
  130. That will fail, with a diagnostic telling you to mark
  131. the file as "conflict resolved" by doing this:
  132. git add ChangeLog
  133. Then, finally, you can proceed (possibly onto more conflict resolution,
  134. if there are conflicts in other files):
  135. git rebase --continue
  136. Once it finishes, your changes on the branch are now relative to
  137. the tip of the trunk.
  138. Now use git format-patch, as above.
  139. Amending the most recent change on your private branch
  140. ======================================================
  141. Let's say you've just committed a change on your private
  142. branch, and then realize that something about it is not right.
  143. It's easy to adjust:
  144. edit your files # this can include running "git add NEW" or "git rm BAD"
  145. git commit --amend -a
  146. git format-patch --stdout -1 > your-branch.diff
  147. That replaces the most recent change-set with the revised one.
  148. Coreutils-specific:
  149. No more ChangeLog files
  150. =======================
  151. Do not modify any of the ChangeLog files in coreutils. Starting in
  152. 2008, the policy changed. Before, we would insert the exact same text
  153. (or worse, sometimes slightly differing) into both the ChangeLog file
  154. and the commit log. Now we put that information only in the commit log,
  155. and generate the top-level ChangeLog file from logs at "make dist" time.
  156. As such, there are strict requirements on the form of the commit log
  157. messages.
  158. Commit log requirements
  159. =======================
  160. Your commit log should always start with a one-line summary, the second
  161. line should be blank, and the remaining lines are usually ChangeLog-style
  162. entries for all affected files. However, it's fine -- even recommended --
  163. to write a few lines of prose describing the change, when the summary
  164. and ChangeLog entries don't give enough of the big picture. Omit the
  165. leading TABs that you're used to seeing in a "real" ChangeLog file, but
  166. keep the maximum line length at 72 or smaller, so that the generated
  167. ChangeLog lines, each with its leading TAB, will not exceed 80 columns.
  168. As for the ChangeLog-style content, please follow these guidelines:
  169. https://www.gnu.org/prep/standards/standards.html#Change-Logs
  170. Try to make the summary line fit one of the following forms:
  171. program_name: change-description
  172. prog1, prog2: change-description
  173. doc: change-description
  174. tests: change-description
  175. build: change-description
  176. maint: change-description
  177. If your commit fixes a bug, try to find the commit that introduced that
  178. bug. If you do that, add a note in your new commit log saying something
  179. like "Introduced by commit v8.12-103-g54cbe6e." and add something like
  180. [bug introduced in coreutils-8.13] in the corresponding NEWS blurb.
  181. Assuming you found the bug in commit 54cbe6e6, "git describe 54cbe6e6"
  182. will print the longer tag-relative string that you'll need.
  183. Note that we used to use an 8-byte SHA1 prefix like "54cbe6e6", because
  184. that was automatically rendered as a clickable link by "gitk", but with
  185. git-1.7.10, the more descriptive version-containing "git describe" format
  186. that we now require is also highlighted.
  187. Curly braces: use judiciously
  188. =============================
  189. Omit the curly braces around an "if", "while", "for" etc. body only when
  190. that body occupies a single line. In every other case we require the braces.
  191. This ensures that it is trivially easy to identify a single-*statement* loop:
  192. each has only one *line* in its body.
  193. Omitting braces with a single-line body is fine:
  194. while (expr)
  195. single_line_stmt ();
  196. However, the moment your loop/if/else body extends onto a second line,
  197. for whatever reason (even if it's just an added comment), then you should
  198. add braces. Otherwise, it would be too easy to insert a statement just
  199. before that comment (without adding braces), thinking it is already a
  200. multi-statement loop:
  201. while (true)
  202. /* comment... */ // BAD: multi-line body without braces
  203. single_line_stmt ();
  204. Do this instead:
  205. while (true)
  206. { /* Always put braces around a multi-line body. */
  207. /* explanation... */
  208. single_line_stmt ();
  209. }
  210. There is one exception: when the second body line is not at the same
  211. indentation level as the first body line.
  212. if (expr)
  213. error (0, 0, _("a diagnostic that would make this line"
  214. " extend past the 80-column limit"));
  215. It is safe to omit the braces in the code above, since the
  216. further-indented second body line makes it obvious that this is still
  217. a single-statement body.
  218. To reiterate, don't do this:
  219. if (expr)
  220. while (expr_2) // BAD: multi-line body without braces
  221. {
  222. ...
  223. }
  224. Do this, instead:
  225. if (expr)
  226. {
  227. while (expr_2)
  228. {
  229. ...
  230. }
  231. }
  232. However, there is one exception in the other direction, when even a
  233. one-line block should have braces. That occurs when that one-line,
  234. brace-less block is an "else" block, and the corresponding "then" block
  235. *does* use braces. In that case, either put braces around the "else"
  236. block, or negate the "if"-condition and swap the bodies, putting the
  237. one-line block first and making the longer, multi-line block be the
  238. "else" block.
  239. if (expr)
  240. {
  241. ...
  242. ...
  243. }
  244. else
  245. x = y; // BAD: braceless "else" with braced "then"
  246. This is preferred, especially when the multi-line body is more than a
  247. few lines long, because it is easier to read and grasp the semantics of
  248. an if-then-else block when the simpler block occurs first, rather than
  249. after the more involved block:
  250. if (!expr)
  251. x = y; /* more readable */
  252. else
  253. {
  254. ...
  255. ...
  256. }
  257. If you'd rather not negate the condition, then add braces:
  258. if (expr)
  259. {
  260. ...
  261. ...
  262. }
  263. else
  264. {
  265. x = y;
  266. }
  267. Use SPACE-only indentation in all[*] files
  268. ==========================================
  269. We use space-only indentation in nearly all files.
  270. If you use Emacs and your coreutils working directory name matches,
  271. this code enables the right mode:
  272. ;; In coreutils, indent with spaces everywhere (not TABs).
  273. ;; Exceptions: Makefile and ChangeLog modes.
  274. (add-hook 'find-file-hook '(lambda ()
  275. (if (and buffer-file-name
  276. (string-match "/coreutils\\>" (buffer-file-name))
  277. (not (string-equal mode-name "Change Log"))
  278. (not (string-equal mode-name "Makefile")))
  279. (setq indent-tabs-mode nil))))
  280. If you use vim (7+ compiled with autocommands), and coreutils working
  281. directory name also matches, add the following in ~/.vimrc:
  282. " Set GNU style indentation, spaces instead of TABs
  283. function! CoreutilsIndent()
  284. " Check if 'coreutils' is part of the current working directory
  285. if match(getcwd(), "coreutils") > 0
  286. " The next 3 lines below set the GNU indentation
  287. setlocal cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1
  288. setlocal shiftwidth=2
  289. setlocal tabstop=8
  290. " Coreutils specific, expand TABs with spaces
  291. setlocal expandtab
  292. endif
  293. endfunction
  294. autocmd BufEnter *.c,*.h call CoreutilsIndent()
  295. [*] Makefile and ChangeLog files are exempt, of course.
  296. Send patches to the address listed in --help output
  297. ===================================================
  298. Please follow the guidelines in the "Sending your patches." section of
  299. git's own SubmittingPatches:
  300. https://github.com/git/git/blob/master/Documentation/SubmittingPatches
  301. Add documentation
  302. =================
  303. If you add a feature or change some user-visible aspect of a program,
  304. document it. If you add an option, document it both in --help output
  305. (i.e., in the usage function that generates the --help output) and in
  306. doc/*.texi. The man pages are generated from --help output, so
  307. you shouldn't need to change anything under man/. User-visible changes
  308. are usually documented in NEWS, too.
  309. When writing prose (documentation, comments, log entries), use an
  310. active voice, not a passive one. I.e., say "print the frobnozzle",
  311. not "the frobnozzle will be printed".
  312. Please add comments per the GNU Coding Standard:
  313. https://www.gnu.org/prep/standards/html_node/Comments.html
  314. Minor syntactic preferences
  315. ===========================
  316. [I hesitate to write this one down, because it appears to be an
  317. acquired taste, at least for native-English speakers. It seems odd
  318. (if not truly backwards) to nearly anyone who doesn't have a strong
  319. mathematics background and perhaps a streak of something odd in their
  320. character ;-) ]
  321. In writing arithmetic comparisons, use "<" and "<=" rather than
  322. ">" and ">=". For some justification, read this:
  323. http://www.gelato.unsw.edu.au/archives/git/0505/4507.html
  324. const placement:
  325. Write "Type const *var", not "const Type *var".
  326. FIXME: dig up justification
  327. Be nice to translators
  328. ======================
  329. Don't change translatable strings if you can avoid it.
  330. If you must rearrange individual lines (e.g., in multi-line --help
  331. strings), extract and create new strings, rather than extracting
  332. and moving into existing blocks. This avoids making unnecessary
  333. work for translators.
  334. Add tests
  335. ==========
  336. Nearly every significant change must be accompanied by a test suite
  337. addition that exercises it. If you fix a bug, add at least one test that
  338. fails without the patch, but that succeeds once your patch is applied.
  339. If you add a feature, add tests to exercise as much of the new code
  340. as possible. If you add a new test file (as opposed to adding a test to
  341. an existing test file) add the new test file to 'tests/local.mk'.
  342. Note to run tests/misc/new-test in isolation you can do:
  343. make check TESTS=tests/misc/new-test SUBDIRS=. VERBOSE=yes
  344. Variables that are significant for tests with their default values are:
  345. VERBOSE=yes
  346. RUN_EXPENSIVE_TESTS=no
  347. RUN_VERY_EXPENSIVE_TESTS=no
  348. SHELL=/bin/sh
  349. NON_ROOT_USERNAME=nobody
  350. NON_ROOT_GID=$(id -g $NON_ROOT_USERNAME)
  351. COREUTILS_GROUPS=$(id -G)
  352. There are hundreds of tests in the tests/ directories. You can use
  353. tests/sample-test as a template, or one of the various Perl-based ones
  354. in tests/misc.
  355. If writing tests is not your thing, don't worry too much about it,
  356. but do provide scenarios, input/output pairs, or whatever, along with
  357. examples of running the tool to demonstrate the new or changed feature,
  358. and someone else will massage that into a test (writing portable tests
  359. can be a challenge).
  360. Copyright assignment
  361. ====================
  362. If your change is significant (i.e., if it adds more than ~10 lines),
  363. then you'll have to have a copyright assignment on file with the FSF.
  364. Since that involves first an email exchange between you and the FSF,
  365. and then the exchange (FSF to you, then back) of an actual sheet of paper
  366. with your signature on it, and finally, some administrative processing
  367. in Boston, the process can take a few weeks.
  368. The forms to choose from are in gnulib's doc/Copyright/ directory.
  369. If you want to assign a single change, you should use the file,
  370. doc/Copyright/request-assign.changes:
  371. https://www.gnu.org/software/gnulib/Copyright/request-assign.changes
  372. If you would like to assign past and future contributions to a project,
  373. you'd use doc/Copyright/request-assign.future:
  374. https://www.gnu.org/software/gnulib/Copyright/request-assign.future
  375. You may make assignments for up to four projects at a time.
  376. In case you're wondering why we bother with all of this, read this:
  377. https://www.gnu.org/licenses/why-assign.html
  378. Run "make syntax-check", or even "make distcheck"
  379. ================================================
  380. Making either of those targets runs many integrity and
  381. project-specific policy-conformance tests. For example, the former
  382. ensures that you add no trailing blanks and no uses of certain deprecated
  383. functions. The latter performs all "syntax-check" tests, and also
  384. ensures that the build completes with no warnings when using a certain
  385. set of gcc -W... options. Don't even bother running "make distcheck"
  386. unless you have a reasonably up to date installation including recent
  387. versions of gcc and the linux kernel, and modern GNU tools.
  388. Ensure that your changes are indented properly.
  389. ===============================================
  390. Format the code the way GNU indent does.
  391. Filtering most source files through "indent --no-tabs" should
  392. induce no change in indentation. Try not to add any more.
  393. Avoid trailing white space
  394. ==========================
  395. You may notice that the only trailing blanks in coreutils'
  396. version-controlled files are in a single directory: tests/pr,
  397. which contains expected output from various invocations of pr.
  398. Do not add any more trailing blanks anywhere. While "make syntax-check"
  399. will alert you if you slip up, it's better to nip any problem in the
  400. bud, as you're typing. A good way to help you adapt to this rule is
  401. to configure your editor to highlight any offending characters in the
  402. files you edit. If you use Emacs, customize its font-lock mode
  403. or use its WhiteSpace mode:
  404. https://www.emacswiki.org/emacs/WhiteSpace
  405. If you use vim, add this to ~/.vimrc:
  406. let c_space_errors=1
  407. highlight RedundantSpaces ctermbg=red guibg=red
  408. match RedundantSpaces /\s\+$\| \+\ze\t/
  409. Git can help too, by stopping you from committing any change that would
  410. add trailing blanks. The example pre-commit hook contains code to check
  411. for trailing whitespace and spaces before tabs; enable it by moving it
  412. to the right place and making sure it is executable:
  413. mv .git/hooks/pre-commit.sample .git/hooks/pre-commit
  414. With a repository created by git-1.5.6 or older, use this command:
  415. chmod +x .git/hooks/pre-commit
  416. To manually check for whitespace errors before committing, you can use
  417. git diff --check
  418. Git also has some settings to enable suitable internal whitespace checks.
  419. See the manpage for git-apply for details.
  420. -------------------------------------------
  421. Miscellaneous useful git commands
  422. =================================
  423. * gitk: give a graphical view of the revision graph of the current branch
  424. * gitk --all: same, but display all branches
  425. * git log: to get most of the same info in text form
  426. * git log -p: same as above, but with diffs
  427. * git log -p SOME_FILE: same as above, but limit to SOME_FILE
  428. * git log -p -2 SOME_FILE: same as above, but print only two deltas
  429. * git log -p -1: print the most recently committed change set
  430. * git format-patch --stdout -1 > FILE: output the most recently committed
  431. change set, in a format suitable to be submitted and/or applied via
  432. "git am FILE".
  433. * git reset --soft HEAD^: Commit the delta required to restore
  434. state to the revision just before HEAD (i.e., next-to-last).
  435. * git rebase -i master: run this from on a branch, and it gives
  436. you an interface with which you can reorder and modify arbitrary
  437. change sets on that branch.
  438. * if you "misplace" a change set, i.e., via git reset --hard ..., so that
  439. it's no longer reachable by any branch, you can use "git fsck" to find
  440. its SHA1 and then tag it or cherry-pick it onto an existing branch.
  441. For example, run this:
  442. git fsck --lost-found HEAD && cd .git/lost-found/commit \
  443. && for i in *; do git show $i|grep SOME_IDENTIFYING_STRING \
  444. && echo $i; done
  445. The "git fsck ..." command creates the .git/lost-found/... hierarchy
  446. listing all unreachable objects. Then the for loop
  447. print SHA1s for commits that match via log or patch.
  448. For example, say that found 556fbb57216b119155cdda824c98dc579b8121c8,
  449. you could run "git show 556fbb57216b119" to examine the change set,
  450. or "git checkout -b found 556fbb5721" to give it a branch name.
  451. Finally, you might run "git checkout master && git cherry-pick 556fbb5721"
  452. to put that change on the tip of "master".
  453. -------------------------------------------
  454. Finding things to do
  455. ====================
  456. If you don't know where to start, check out the TODO file for projects
  457. that look like they're at your skill-/interest-level. Another good
  458. option is always to improve tests. You never know what you might
  459. uncover when you improve test coverage, and even if you don't find
  460. any bugs your contribution is sure to be appreciated.
  461. A good way to quickly assess current test coverage, for standard
  462. and root only tests, is to follow these steps (requires lcov to be installed):
  463. # Do a standard run as the current user
  464. make -j$(nproc) coverage
  465. # Add the root only tests
  466. sudo make -j$(nproc) build-coverage NON_ROOT_USERNAME=$USER SUBDIRS=.
  467. # Generate the report with the combined results
  468. make gen-coverage
  469. # view the HTML report:
  470. xdg-open doc/coverage/index.html
  471. ========================================================================
  472. Copyright (C) 2009-2018 Free Software Foundation, Inc.
  473. Permission is granted to copy, distribute and/or modify this document
  474. under the terms of the GNU Free Documentation License, Version 1.3 or
  475. any later version published by the Free Software Foundation; with no
  476. Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
  477. Texts. A copy of the license is included in the "GNU Free
  478. Documentation License" file as part of this distribution.