Information for GNU Gnulib maintainers and contributors ******************************************************* Using git ========= * We don't use topic branches. Changes are usually small enough that they can be committed directly to the master branch, after appropriate testing. * We maintain stable branches, though, as described in the documentation: https://www.gnu.org/software/gnulib/manual/html_node/Stable-Branches.html When backporting a commit to a stable branch of the last year, be sure to update the copyright year of each modified file (since we don't run "make update-copyright" on the stable branches). * We use a linear git history — no merges. To work in this setting, it's recommended that you configure git with 'git config pull.rebase = true'. * Before pushing a commit, it is highly recommended that you review it in its entirety. The easiest ways to do so are * to run $ git format-patch -1 and then read the patch in an editor that has syntax-colouring of patch files, or * to run $ gitk * We update the ChangeLog by hand. The commit message is usually identical to the ChangeLog entry, with the date and author line removed, with the leading tabs removed, and with a blank line after the commit's summary line. In order to work efficiently with ChangeLog files, it is recommended that you configure git to use the git-merge-changelog driver; see the instructions in the lib/git-merge-changelog.c file. Note: This driver reasonably keeps the ChangeLog entries together; however, it does not always keep them in the order you would desire. For example, when you had prepared a commit, you try to "git push" it but that fails due to someone else's commit that came earlier, what you need to do is: 1. $ git pull 2. Verify that your ChangeLog entry is still the top-most one. 3. If it is not, then edit ChangeLog to move it to the top, and $ git commit --amend ChangeLog 4. $ gitk 5. $ git push * When you commit a contributor's patch, please - add a reasonable ChangeLog entry in the usual style (meaningful summary line and detailed change list), - if the contribution is so small that it does not require a copyright assignment (cf. https://www.gnu.org/prep/maintain/html_node/Legally-Significant.html ) add a line: Copyright-paperwork-exempt: Yes - use the 'git commit' option --author="Contributor Name " License Notices =============== In *.m4 files, use a notice like this: dnl Copyright (C) YEARS Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl This file is offered as-is, without any warranty. In lib/, tests/, build-aux/ files, except those that are shared with glibc, use the license notices from etc/license-notices/ . This avoids gratuitous differences in wording, as well misunderstandings when a license notice would say "This program ...". Test Suite ========== When adding a module, add a unit test module as well. This is our best chance to catch portability problems. A unit test can have many sub-tests. Try to make the sub-tests independent of each other, so that it becomes easy to disable some sub-tests by enclosing them in #if 0 ... #endif. The main() function's exit code meaning is: - 0: PASS - 77: SKIP; you should print the reason why the test is skipped. - 99: ERROR, i.e. test framework error - any other exit code < 126: FAIL In tests that #include "macros.h" and use the ASSERT macro: The main() function should, before it returns 0 (for PASS) or 77 (for SKIP) test the value of test_exit_status and return that instead. So: - not return 0; but instead return test_exit_status; - not return result; // where result can be 0 or 1 but instead return (result ? result : test_exit_status); - not fputs ("Skipping test: \n", stderr); return 77; but instead if (test_exit_status != EXIT_SUCCESS) return test_exit_status; fputs ("Skipping test: \n", stderr); return 77; Only at the beginning of the main() function, when ASSERT has not yet been invoked, we know that test_exit_status must be zero and can therefore write fputs ("Skipping test: \n", stderr); return 77; directly. Maintaining high quality ======================== It is a good idea to occasionally create a testdir of all of Gnulib: $ rm -rf ../testdir-all; ./gnulib-tool --create-testdir --dir=../testdir-all --with-c++-tests --without-privileged-tests `./all-modules` and test this directory on various platforms: - Linux/glibc systems, - Linux/musl systems, - macOS, - FreeBSD, - NetBSD, - OpenBSD, - AIX, - Solaris 10 and 11, - Cygwin, - Haiku, - Android, - and other platforms of your choice. There are two continuous integrations that regularly perform this testing: * On a Linux/glibc system only: https://gitlab.com/gnulib/gnulib-ci This one will catch only the most blatant mistakes. * On many platforms: https://github.com/gnu-gnulib/ci-testdir-check/actions This one runs on many platforms, currently (as of June 2024): - Ubuntu GNU/Linux 22.04 - CentOS GNU/Linux 7 - Alpine Linux - macOS 11, 12, 13 (all x86_64) - macOS 14 (arm64) - FreeBSD 14.0 - NetBSD 10.0 - OpenBSD 7.5 - Solaris 11.4 - Solaris 11 OmniOS - Cygwin 3.3.6 (32 bit) and 3.5.3 (64 bit) - mingw (32 bit and 64 bit) - MSVC (32 bit and 64 bit) and also - on Ubuntu GNU/Linux 22.04 with clang's UBSAN and ASAN sanitizers. This one catches real portability problems. Note that the following platforms are not covered and thus still require occasional manual testing: - AIX - Solaris 10 - Haiku - Android - and other platforms of your choice. Warning Options =============== For packages that use Gnulib, we recommend to use the 'warnings' or 'manywarnings' module, as documented in https://www.gnu.org/software/gnulib/manual/html_node/warnings.html https://www.gnu.org/software/gnulib/manual/html_node/manywarnings.html When building Gnulib testdirs, e.g. when preparing a Gnulib patch, there are three possible approaches: * The simplest approach, which warns about the most common mistakes, is to use GCC's -Wall option, both for C and C++ compilation units. Just set $ ./configure CPPFLAGS="-Wall" $ make You should generally fix all compiler warnings that you see from this approach. * If you are developing on a glibc system and have GCC version 15 binaries available, here's a recipe that will find more mistakes, but is nearly as easy to use. Here, different warning options are needed for C and for C++: $ WARN_GCC15=`echo ' -fanalyzer -Wall -Warith-conversion -Wcast-align=strict -Wdate-time -Wduplicated-cond -Wextra -Wflex-array-member-not-at-end -Wformat-signedness -Winit-self -Winvalid-pch -Wlogical-op -Wmaybe-musttail-local-addr -Wmissing-include-dirs -Wopenmp-simd -Woverlength-strings -Wpacked -Wpointer-arith -Wstrict-overflow -Wsuggest-final-methods -Wsuggest-final-types -Wsync-nand -Wsystem-headers -Wtrampolines -Wuninitialized -Wunknown-pragmas -Wunsafe-loop-optimizations -Wvariadic-macros -Wvector-operation-performance -Wwrite-strings -Warray-bounds=2 -Wattribute-alias=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wshift-overflow=2 -Wunused-const-variable=2 -Wvla-larger-than=4031 -Wno-empty-body -Wno-analyzer-allocation-size -Wno-analyzer-fd-double-close -Wno-analyzer-double-fclose -Wno-analyzer-double-free -Wno-analyzer-fd-leak -Wno-analyzer-fd-use-after-close -Wno-analyzer-fd-use-without-check -Wno-analyzer-free-of-non-heap -Wno-analyzer-malloc-leak -Wno-analyzer-mismatching-deallocation -Wno-analyzer-null-argument -Wno-analyzer-null-dereference -Wno-analyzer-out-of-bounds -Wno-analyzer-possible-null-argument -Wno-analyzer-possible-null-dereference -Wno-analyzer-use-after-free -Wno-analyzer-use-of-pointer-in-stale-stack-frame -Wno-analyzer-use-of-uninitialized-value -Wno-analyzer-va-arg-type-mismatch -Wno-attribute-warning -Wno-cast-align -Wno-clobbered -Wno-dangling-pointer -Wno-format -Wno-implicit-fallthrough -Wno-maybe-uninitialized -Wno-missing-field-initializers -Wno-restrict -Wno-sign-compare -Wno-switch -Wno-type-limits -Wno-unused-parameter ' | tr -d '\n' | sed -e 's/ */ /g'` $ WARN_CFLAGS_GCC15="$WARN_GCC15 -Wmissing-variable-declarations -Wnested-externs -Wshadow=local -Wno-discarded-qualifiers" $ WARN_CXXFLAGS_GCC15="$WARN_GCC15 -Wno-cpp" $ ./configure CFLAGS="-O2 -g $WARN_CFLAGS_GCC15" CXXFLAGS="-O2 -g $WARN_CXXFLAGS_GCC15" $ make You should generally fix all compiler warnings that you see from this approach, or report when this approach produced a pointless warning (so that we can fix the value of WARN_GCC15 above). * If you are developing on a glibc system and have GCC version 15 binaries available: Here's a recipe that will find even more mistakes, but it requires that you are willing to filter out and ignore pointless warnings. $ WARN_GCC15=`echo ' -fanalyzer -Wall -Warith-conversion -Wcast-align=strict -Wdate-time -Wduplicated-cond -Wextra -Wflex-array-member-not-at-end -Wformat-signedness -Winit-self -Winvalid-pch -Wlogical-op -Wmaybe-musttail-local-addr -Wmissing-include-dirs -Wnull-dereference -Wopenmp-simd -Woverlength-strings -Wpacked -Wpointer-arith -Wstrict-overflow -Wsuggest-attribute=format -Wsuggest-final-methods -Wsuggest-final-types -Wsync-nand -Wsystem-headers -Wtrampolines -Wuninitialized -Wunknown-pragmas -Wunsafe-loop-optimizations -Wvariadic-macros -Wvector-operation-performance -Wwrite-strings -Warray-bounds=2 -Wattribute-alias=2 -Wformat-overflow=2 -Wformat=2 -Wformat-truncation=2 -Wimplicit-fallthrough=5 -Wshift-overflow=2 -Wunused-const-variable=2 -Wvla-larger-than=4031 -Wno-empty-body -Wno-analyzer-double-fclose -Wno-analyzer-double-free -Wno-analyzer-free-of-non-heap -Wno-analyzer-malloc-leak -Wno-analyzer-null-argument -Wno-analyzer-null-dereference -Wno-analyzer-use-after-free -Wno-attribute-warning -Wno-cast-align -Wno-clobbered -Wno-format-nonliteral -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter ' | tr -d '\n' | sed -e 's/ */ /g'` $ WARN_CFLAGS_GCC15="$WARN_GCC15 -Wmissing-variable-declarations -Wnested-externs -Wshadow=local" $ WARN_CXXFLAGS_GCC15="$WARN_GCC15 -Wno-cpp" $ ./configure CFLAGS="-O2 -g $WARN_CFLAGS_GCC15" CXXFLAGS="-O2 -g $WARN_CXXFLAGS_GCC15" $ make With this approach, use your own judgement whether to fix warnings arising from your new code or not. Do *not* submit patches to silence warnings from existing code: - For these warnings, often the cure will be worse than the disease. - Some of the warnings are false positives. Rather than silencing these warnings, we prefer to report them in the GCC bug tracker and wait until they are fixed in a future GCC release. Similarly, for clang version 20 you can use the following recipe, that uses selected warning options from https://releases.llvm.org/20.1.0/tools/clang/docs/DiagnosticsReference.html : $ WARN_CLANG20=`echo ' -Wall -Wanon-enum-enum-conversion -Warc-repeated-use-of-weak -Warray-bounds-pointer-arithmetic -Warray-parameter -Watomic-properties -Wauto-decl-extensions -Wbinary-literal -Wbit-int-extension -Wbitfield-enum-conversion -Wbitwise-op-parentheses -Wbool-operation -Wc++-compat -Wc23-compat -Wc23-extensions -Wc2x-compat -Wc2x-extensions -Wc23-extensions -Wc99-compat -Wc99-designator -Wc99-extensions -Wcalled-once-parameter -Wcast-function-type -Wchar-subscripts -Wcomment -Wcompletion-handler -Wcomplex-component-init -Wcompound-token-split -Wconsumed -Wconversion -Wcstring-format-directive -Wcuda-compat -Wdate-time -Wdelimited-escape-sequence-extension -Wdeprecated -Wdeprecated-dynamic-exception-spec -Wdeprecated-implementations -Wdeprecated-this-capture -Wdeprecated-writable-strings -Wdirect-ivar-access -Wdocumentation -Wdocumentation-deprecated-sync -Wdocumentation-html -Wdocumentation-pedantic -Wdocumentation-unknown-command -Wdollar-in-identifier-extension -Wduplicate-decl-specifier -Wduplicate-enum -Wduplicate-method-arg -Wduplicate-method-match -Wdynamic-exception-spec -Wembedded-directive -Wempty-init-stmt -Wempty-translation-unit -Wenum-compare-conditional -Wenum-conversion -Wenum-enum-conversion -Wenum-float-conversion -Wexit-time-destructors -Wexpansion-to-defined -Wexplicit-ownership-type -Wextra -Wextra-semi -Wflexible-array-extensions -Wfloat-overflow-conversion -Wfloat-zero-conversion -Wfor-loop-analysis -Wformat -Wformat-pedantic -Wformat-type-confusion -Wformat=2 -Wfour-char-constants -Wframe-address -Wfuse-ld-path -Wfuture-attribute-extensions -Wgcc-compat -Wgnu -Wgnu-anonymous-struct -Wgnu-auto-type -Wgnu-case-range -Wgnu-complex-integer -Wgnu-compound-literal-initializer -Wgnu-conditional-omitted-operand -Wgnu-designator -Wgnu-empty-initializer -Wgnu-empty-struct -Wgnu-flexible-array-initializer -Wgnu-flexible-array-union-member -Wgnu-folding-constant -Wgnu-imaginary-constant -Wgnu-label-as-value -Wgnu-line-marker -Wgnu-null-pointer-arithmetic -Wgnu-offsetof-extensions -Wgnu-pointer-arith -Wgnu-redeclared-enum -Wgnu-statement-expression -Wgnu-statement-expression-from-macro-expansion -Wgnu-union-cast -Wgnu-zero-line-directive -Wgnu-zero-variadic-macro-arguments -Wheader-hygiene -Widiomatic-parentheses -Wignored-qualifiers -Wimplicit -Wimplicit-fallthrough -Wimplicit-fallthrough-per-function -Wimplicit-function-declaration -Wimplicit-int -Wimplicit-retain-self -Wimport-preprocessor-directive-pedantic -Wincomplete-module -Winconsistent-missing-destructor-override -Winfinite-recursion -Wint-in-bool-context -Winvalid-or-nonexistent-directory -Winvalid-utf8 -Wkeyword-macro -Wlanguage-extension-token -Wlocal-type-template-args -Wlogical-op-parentheses -Wlong-long -Wloop-analysis -Wmain -Wmax-tokens -Wmethod-signatures -Wmicrosoft -Wmicrosoft-anon-tag -Wmicrosoft-charize -Wmicrosoft-comment-paste -Wmicrosoft-cpp-macro -Wmicrosoft-end-of-file -Wmicrosoft-enum-value -Wmicrosoft-exception-spec -Wmicrosoft-fixed-enum -Wmicrosoft-flexible-array -Wmicrosoft-redeclare-static -Wmisleading-indentation -Wmismatched-tags -Wmissing-braces -Wmissing-method-return-type -Wmost -Wmove -Wnested-anon-types -Wnewline-eof -Wnon-gcc -Wnon-modular-include-in-framework-module -Wnon-modular-include-in-module -Wnon-virtual-dtor -Wnonportable-system-include-path -Wnull-pointer-arithmetic -Wnull-pointer-subtraction -Wnullability-extension -Wnullable-to-nonnull-conversion -Wopenmp -Wover-aligned -Woverlength-strings -Woverloaded-virtual -Woverriding-method-mismatch -Wpacked -Wpacked-non-pod -Wparentheses -Wpedantic -Wpedantic-core-features -Wpessimizing-move -Wpointer-arith -Wpoison-system-directories -Wpragma-pack -Wpragma-pack-suspicious-include -Wpragmas -Wpre-c11-compat -Wpre-c23-compat -Wpre-c2x-compat -Wpre-c2y-compat -Wpre-openmp-51-compat -Wprofile-instr-missing -Wquoted-include-in-framework-header -Wrange-loop-analysis -Wrange-loop-bind-reference -Wrange-loop-construct -Wreceiver-forward-class -Wredundant-move -Wredundant-parens -Wreorder -Wreorder-ctor -Wreserved-attribute-identifier -Wreserved-user-defined-literal -Wretained-language-linkage -Wselector -Wselector-type-mismatch -Wself-assign -Wself-assign-overloaded -Wself-move -Wsemicolon-before-method-body -Wshadow-all -Wshadow-field -Wshadow-field-in-constructor -Wshadow-field-in-constructor-modified -Wshadow-uncaptured-local -Wshift-sign-overflow -Wsigned-enum-bitfield -Wsometimes-uninitialized -Wsource-uses-openacc -Wsource-uses-openmp -Wspir-compat -Wstatic-in-inline -Wstrict-potentially-direct-selector -Wstrict-selector-match -Wstring-concatenation -Wstring-conversion -Wsuggest-destructor-override -Wsuggest-override -Wsuper-class-method-mismatch -Wtautological-bitwise-compare -Wtautological-compare -Wtautological-constant-in-range-compare -Wtautological-negation-compare -Wtautological-overlap-compare -Wtautological-type-limit-compare -Wtautological-unsigned-char-zero-compare -Wtautological-unsigned-enum-zero-compare -Wtautological-unsigned-zero-compare -Wtautological-value-range-compare -Wthread-safety -Wthread-safety-analysis -Wthread-safety-attributes -Wthread-safety-beta -Wthread-safety-negative -Wthread-safety-precise -Wthread-safety-reference -Wthread-safety-verbose -Wtype-limits -Wunaligned-access -Wundeclared-selector -Wundef-prefix -Wundefined-func-template -Wundefined-internal-type -Wundefined-reinterpret-cast -Wunguarded-availability -Wuninitialized -Wuninitialized-const-reference -Wunknown-pragmas -Wunnamed-type-template-args -Wunneeded-internal-declaration -Wunneeded-member-function -Wunreachable-code-fallthrough -Wunreachable-code-loop-increment -Wunsupported-dll-base-class-template -Wunused -Wunused-but-set-parameter -Wunused-but-set-variable -Wunused-const-variable -Wunused-exception-parameter -Wunused-function -Wunused-label -Wunused-lambda-capture -Wunused-local-typedef -Wunused-member-function -Wunused-private-field -Wunused-property-ivar -Wunused-template -Wunused-variable -Wvariadic-macros -Wvector-conversion -Wvla-cxx-extension -Wweak-template-vtables -Wweak-vtables -Wzero-length-array -Wno-bitwise-instead-of-logical -Wno-c11-extensions -Wno-cast-function-type-strict -Wno-float-conversion -Wno-format-nonliteral -Wno-gnu-include-next -Wno-implicit-float-conversion -Wno-implicit-int-conversion -Wno-implicit-int-float-conversion -Wno-include-next-absolute-path -Wno-missing-field-initializers -Wno-reserved-macro-identifier -Wno-shadow -Wno-shorten-64-to-32 -Wno-sign-compare -Wno-sign-conversion -Wno-strict-prototypes -Wno-switch -Wno-unused-parameter -Wno-tautological-constant-out-of-range-compare -Wno-tautological-type-limit-compare -Wno-tautological-unsigned-zero-compare -Wno-tautological-value-range-compare -Wno-unused-command-line-argument -Wno-user-defined-warnings ' | tr -d '\n' | sed -e 's/ */ /g'` $ ./configure CFLAGS="-O2 -g $WARN_CLANG20" CXXFLAGS="-O2 -g $WARN_CLANG20" $ make Again, use your own judgement to determine whether to fix or ignore a specific warning. Maintaining link dependencies ============================= Each module has a section "Link:", that contains the linker options that a program, that makes use of the module, needs to use, in order to avoid a link error. Unless empty, this field contains one or more variable references, because linker options are platform dependent. A gnulib-tool invocation lists these linker options to the package maintainer, so that they can make use of these options in the *_LDFLAGS in their package's Makefile.am. Of course, the unit tests uses these linker options. Often the link dependencies for module 'foo' follows this naming convention: $(FOO_LIB). For example, there are variables references $(MBRTOWC_LIB) $(SETLOCALE_LIB). Typically, when you make a code change in a module and accordingly define a variable for its linker options in the corresponding *.m4 file, you also need to update the linker options of all modules that depend on it: $ ./gnulib-tool --extract-dependents foo and the linker options of all modules that depend on these, etc.: $ ./gnulib-tool --extract-recursive-dependents foo The use of a variable per module avoids the need for an avalanche of changes. When you notice a link error of a program, you typically fix it in three steps: 1. Ask "Which library does the program need to link with?" You answer this by consulting documentation and man pages, as well as by use of "nm --dynamic /lib/libxyz.so". 2. Ask "From which autoconf variable do I get this library option?" You answer this by searching the *LIB* values in config.status: $ grep LIB config.status 3. Finally you add a reference to that variable to the *_LIB variable of your module. Or, if your module does not have such a variable so far, you introduce such a variable and make sure to update all dependents to make use of it (see above). Information for gnulib-tool maintenance *************************************** Running the unit tests ====================== The unit tests of gnulib-tool reside in the maint-tools repository, that is a satellite repository of the main gnulib repository. Instructions how to obtain it are in https://savannah.gnu.org/git/?group=gnulib . To run the unit tests of gnulib-tool.sh: $ cd maint-tools/gnulib-tool-tests/ $ GNULIB_TOOL_IMPL=sh ./test-all.sh To run the unit tests of gnulib-tool.py: $ cd maint-tools/gnulib-tool-tests/ $ GNULIB_TOOL_IMPL=py ./test-all.sh It is *mandatory* that you run the test suite before pushing any change to gnulib-tool.sh or gnulib-tool.py! If you fail to do so, and your change contains a bug, it will start to affect users immediately. Debugging the Python implementation of gnulib-tool ================================================== With Eclipse and PyDev as IDE ----------------------------- * Download and configuration: - Eclipse IDE from https://www.eclipse.org/downloads/packages/ (either the build for Java or for C/C++ should work fine; either use the Eclipse Installer program at the top of the page, or one of the individual download links below). - PyDev from https://www.pydev.org/download.html section "Install as Plugin". (Don't use LiClipse, since the license costs money.) - Follow https://www.pydev.org/manual_101_install.html, replacing http://www.pydev.org/updates with https://www.pydev.org/updates - Once installed, restart the IDE. - Window > Preferences > PyDev > Interpreters > Python Interpreter: New > path: /usr/bin/python3 - Window > Preferences > PyDev > Editor > Code Analysis: Others > Redefinition of builtin symbols: Ignore * Create a project: Let GNULIB_DIR be my gnulib checkout. - File > New > Project... > PyDev > PyDev Project. Call it 'gnulib-tool'. Note that this is a project inside the Eclipse workspace, so far unrelated to the GNULIB_DIR. - Popup menu > New > Link to Existing Source Name: gnulib Path: * Create a run configuration: - Run > Run Configurations... > Python Run Popup menu > New configuration Name: gnulib-tool.py Main > Project: gnulib-tool Main > Main Module: ${workspace_loc:gnulib-tool/gnulib/.gnulib-tool.py} Arguments > Program arguments: --help - Test it: Run this configuration. * Create a debug configuration: - Run > Debug Configurations... > gnulib-tool.py Popup menu > Duplicate - In the duplicate, set Arguments > Working directory: /tmp/oath-toolkit/lib Arguments > Program arguments: --add-import * Debug it: - Open GLImport.py. - On the left-hand border of this editor, do "Add breakpoint". - Run > Debug Configurations... > pick the duplicate. Press Debug. Maintaining high quality ======================== There is a continuous integration of gnulib-tool.py that runs the unit tests, at https://gitlab.com/gnulib/gnulib-tool-ci/ .