From Fedora Project Wiki

(→‎BuildRequires and Requires: document that -devel subpackages don't need Requires: gcc)
(→‎BuildRequires and Requires: add extra packages needed for building 32-bit on 64-bit)
Line 15: Line 15:
 
You need not include a <code>BuildRequires</code> or <code>Requires</code> on <code>glibc-headers</code>, or any other core C or C++ implementation package unless you have a specific and special need e.g. static compilation requires the <code>.*-static</code> library packages e.g. <code>BuildRequires: glibc-static</code>. The default use case of a dynamically compiled C or C++ application is taken care of by the <code>gcc</code>, <code>gcc-c++</code>, and <code>clang</code> packages.
 
You need not include a <code>BuildRequires</code> or <code>Requires</code> on <code>glibc-headers</code>, or any other core C or C++ implementation package unless you have a specific and special need e.g. static compilation requires the <code>.*-static</code> library packages e.g. <code>BuildRequires: glibc-static</code>. The default use case of a dynamically compiled C or C++ application is taken care of by the <code>gcc</code>, <code>gcc-c++</code>, and <code>clang</code> packages.
  
Your library's <code>-devel</code> sub-package should not have <code>Requires: gcc</code> or <code>Requires: glibc-headers%{?_isa}</code> or any similar requirements on core C or C++ implementation packages. In order to actually compile your library's headers a working build environment is needed, and so the standard C or C++ library headers will be present anyway. The less common case of wanting to use headers from some 32-bit <code>.*-devel</code> package to build a 32-bit program on a 64-bit system does require users to manually install the 32-bit <code>glibc-devel</code> package, but that's needed for all 32-bit compilation on 64-bit systems, even for a "Hello, world!" program that doesn't use headers from any <code>.*-devel</code> packages.
+
Your library's <code>-devel</code> sub-package should not have <code>Requires: gcc</code> or <code>Requires: glibc-headers%{?_isa}</code> or any similar requirements on core C or C++ implementation packages. In order to actually compile your library's headers a working build environment is needed, and so the standard C or C++ library headers will be present anyway. The less common case of wanting to use headers from some 32-bit <code>.*-devel</code> package to build a 32-bit program on a 64-bit system does require users to manually install the 32-bit <code>glibc-devel</code> and <code>libgcc</code> packages (and for C++ <code>libstdc++-devel</code>), but that's necessary for all 32-bit compilation on 64-bit systems, even for a "Hello, world!" program that doesn't use headers from any <code>.*-devel</code> packages.
  
 
Please refer to [https://fedoraproject.org/wiki/Packaging:Guidelines#Compiler Packaging:Guidelines Compiler] for the list of supported compilers for C and C++ compilers.
 
Please refer to [https://fedoraproject.org/wiki/Packaging:Guidelines#Compiler Packaging:Guidelines Compiler] for the list of supported compilers for C and C++ compilers.

Revision as of 07:23, 9 June 2016

Introduction

The C and C++ languages and runtimes are one of the most common development frameworks for packages in fedora. As such there is a wide variety of quality, style, and convention in all of those packages. The following document provides best practice for certain aspects of C and C++ packaging.

Packaging

BuildRequires and Requires

If your application is a C or C++ application you must list a BuildRequires against gcc, gcc-c++ or clang. Those packages will include everything that is required to build a standards conforming C or C++ application.

If your library includes standard C or C++ headers, you must list BuildRequires against gcc, gcc-c++, or clang to install the needed standards conforming headers.

If at runtime you use cpp to process C or C++ language headers then you have no choice but to use Requires for gcc, gcc-c++, or clang to install the required headers for a standard conforming C or C++ application. In the future this might change if a set of standard C or C++ language headers are provided by a special-purpose provides e.g. c-headers or c++-headers.

You need not include a BuildRequires or Requires on glibc-headers, or any other core C or C++ implementation package unless you have a specific and special need e.g. static compilation requires the .*-static library packages e.g. BuildRequires: glibc-static. The default use case of a dynamically compiled C or C++ application is taken care of by the gcc, gcc-c++, and clang packages.

Your library's -devel sub-package should not have Requires: gcc or Requires: glibc-headers%{?_isa} or any similar requirements on core C or C++ implementation packages. In order to actually compile your library's headers a working build environment is needed, and so the standard C or C++ library headers will be present anyway. The less common case of wanting to use headers from some 32-bit .*-devel package to build a 32-bit program on a 64-bit system does require users to manually install the 32-bit glibc-devel and libgcc packages (and for C++ libstdc++-devel), but that's necessary for all 32-bit compilation on 64-bit systems, even for a "Hello, world!" program that doesn't use headers from any .*-devel packages.

Please refer to Packaging:Guidelines Compiler for the list of supported compilers for C and C++ compilers.

Static Linking

You should avoid static linking if at all possible and review the guidelines regarding static libraries.

This section is not about bundling policy (static linking, library bundling, containers), but is about real technical limitations faced when statically linking against the C/C++ runtimes.

If you really need to use static linking, you should know that in Fedora there is no support for statically linking against the C/C++ runtime. This includes the use of the gcc, g++, clang, or ld options:

  • -static
  • -static-.* e.g. -static-libstdc++

The developers responsible for the C/C++ runtimes are working on a short term solution to document those functions which might be safe to use within a static linkage model, but no such documentation exists today. Therefore there is no support for statically linking against he C/C++ runtimes.

If you still need a statically linked application, please take the following into consideration: any C/C++ API which eventually calls dlopen is going to cause significant problems for your application. The use of dlopen within a statically linked application creates two distinct namespaces, the static one and the dynamic one. There is at present no coordination framework between these two namespace and as a result you may end up with threads crashing due to uninitialized locale information, errno not propagating to callers correctly on failure, and data races when locking is incorrectly elided. Unfortunately it is impossible to assure yourself that dlopen is never called by the underlying implementation (ELF symbol interposition will not help you since the runtime elides this for internal consistency).

In order to assist developers the following is a list of functions which are very likely going to work in the static linkage case:

  • File descriptor operations: open, close, read, write, dup, stat, etc.
  • String operations: strcpy, strncpy, strcmp, strncmp etc.
  • Memory operations: memcpy, memcpy, memmove, bcopy etc.
  • FILE * operations: fopen, fdopen, freopen, fprintf, etc., as long as the ccs= mode is not used while opening files.
  • Formatted output operations: printf, fprintf, dprintf, sprintf, snprintf etc.
  • Formatted input operations: scanf, fscanf, sscanf, vscanf, vsscanf, vfscanf, etc.

In general, functions which avoid process-global state are relatively safe to use.

The following is a list of functions which are very likely to fail:

  • All uses of dlopen, either direct or indirect:
    • Dynamic loading operations: dlopen, dlsym, dlvsym, dlclose etc.
    • NSS operations: getpwnam, getpwuid, getpwnam_r, getpwuid_r, getpwent, setpwent, end pwent etc.
    • Internationalized domain names: idna_to_ascii_4i, idna_to_unicode_44i, etc.
    • Character encoding conversions: iconv_open, iconv_close, iconv etc.
  • Thread cancellation operations: pthread_cancel etc.
  • Any threads created by statically linked code calling functions in dlopen'd libraries.

The most visible failure modes are application crashes in any of the functions which are likely to fail, but you may also get data corruption, data races, and undefined behaviour.

Dependencies for (sub)packages with a statically linked program

If you ship a statically linked program which uses dlopen (either directly or indirectly), you must specify a Require: dependency on the exact NEVRA of the glibc package your package was built against.

If you do not use dlopen, no such dependency is required. However, a future revision of these guidelines may add a requirement that the statically linked glibc version is expressed at the RPM level.

Dependencies for (sub)packages which provide static libraries

If your package ships a static library implemented in C or C++ (that is, an .a file), the development package which includes this library (usually, a -devel or -static package) must specify an RPM Requires: dependency on the exact NEVRA of the glibc-headers package which was used to compile the object files in the static library. The GNU C Library only provides ABI compatibility with dynamic linking; all static libraries have to be recompiled on every glibc update. This dependency is required even if the final executable links against glibc dynamically.

You may also consider shipping a statically linked library for use in PIC code (DSOs or PIE executable). Usually, such libraries have names ending in -pic.a. The same RPM dependency is required for them.

Packaging Q&A

Q: Do I need a Requires: glibc to ensure I have the C runtime installed for my application?

A: No. RPM will automatically determine what ELF libraries you need based on the binaries in your package. This is sufficient to cause glibc to be installed.

Q: Do I need to include a Requires: libgcc?

A: If you are using an API from libgcc directly, then yes, you must have a Requires: libgcc. In general though glibc requires libgcc, so it is always installed.

Libraries

Libraries should have unique shared object names (SONAMEs via -Wl,-soname=libfoo.so) that do not conflict with other library SONAMEs used in the distribution. For example there should be only one libfoo.so in the distribution. The exception is when there are multiple implementations of the same library libfoo.so provided by different authors and each conflicts with the other. In this case both libfoo.so must provide exactly the same interface, but with a different implementation. Having two libfoo.so each with a different API is bad practice and makes it harder to package and distribute those packages.

Libraries should versions all of their symbols using a version script. Versioning allows the library to avoid changing the SONAME when the API changes and instead compatibility functions can be written to provide backwards compatibility for older applications.

Applications

No additional suggestions are provided for applications at this time.