.. index:: source management .. _Managing_Sources: **************** Managing Sources **************** This chapter covers how GPR locates source files: directory scanning, explicit file lists, exclusions, and naming conventions. Understanding these mechanisms lets you organize your source tree freely without forcing a particular directory layout. How source discovery works ========================== When a project is loaded, GPR tools scan every directory listed in ``Source_Dirs`` and collects all files whose extensions match the active languages. For Ada, the default extensions are ``.ads`` (specs) and ``.adb`` (bodies); for C, ``.c`` and ``.h``; and so on. Files that do not match any known extension for the declared languages are silently ignored. .. index:: Source_Dirs Source directories ================== ``Source_Dirs`` accepts a list of directory paths, relative to the project file. Glob patterns are expanded at load time: .. code-block:: gpr for Source_Dirs use ("src", "generated/src", "platform/" & Platform); The ``**`` pattern matches any number of directory levels, enabling a recursive scan: .. code-block:: gpr for Source_Dirs use ("src/**"); This collects sources from ``src/`` and every subdirectory beneath it, however deeply nested. To collect sources *only* from the project file's own directory, use a single dot: .. code-block:: gpr for Source_Dirs use ("."); .. index:: abstract project To declare a project with no sources - one that exists purely to share attributes with other projects - use the ``abstract`` qualifier: .. code-block:: gpr abstract project Support is -- no sources; attributes only end Support; An ``abstract`` project may not declare ``Main``, ``Object_Dir``, or ``Exec_Dir``; those attributes are meaningful only for projects that produce build artifacts. See :ref:`Project_Extension_UG` for a typical use of abstract projects. .. tip:: Avoid overlapping ``Source_Dirs`` between two projects in the same tree. If the same source file is visible to two projects, a duplicate-unit error is reported at load time. .. index:: Source_Files Explicit source lists ===================== For finer control, you can enumerate sources explicitly instead of scanning a directory. ``Source_Files`` lists individual file names (not paths) directly in the project file: .. code-block:: gpr for Source_Files use ("utils.ads", "utils.adb", "config.ads"); Only the named files are included, even if other source files exist in ``Source_Dirs``. For larger lists, ``Source_List_File`` points to a text file containing one file name per line: .. code-block:: gpr for Source_List_File use "sources.txt"; This is useful when the list is generated by a build script or version control system. .. index:: Excluded_Source_Files Excluding sources ================= ``Excluded_Source_Files`` removes specific files from an otherwise directory-scanned project: .. code-block:: gpr for Excluded_Source_Files use ("old_impl.adb", "stub.ads"); The complement of ``Source_List_File``, ``Excluded_Source_List_File`` points to a text file listing the files to exclude: .. code-block:: gpr for Excluded_Source_List_File use "excluded.txt"; Exclusions apply after the directory scan, so you can keep sources in the same directory without including all of them in the build. .. index:: naming convention, Languages Ada naming conventions ====================== The default naming convention for Ada follows the GNAT standard: - Specs use the ``.ads`` extension, bodies use ``.adb``. - Child unit names use ``-`` as the separator: the body of ``My_Lib.Utils`` lives in ``my_lib-utils.adb``. - Unit names map to file names in lower case. Ada source files and unit names are tightly coupled: when a file with the right suffix (``.ads`` or ``.adb``) is found in a source directory, GPR derives the corresponding unit name by reversing the naming convention (stripping the suffix, replacing the dot-replacement character back to ``.``, and so on). If the result is not a valid Ada identifier, the file is silently ignored. For example, ``my_source__unix.adb`` maps to ``my_source__unix`` - a name containing a double underscore, which is not valid in Ada. GPR will not recognize this file as an Ada source during directory scanning. .. tip:: To include a file whose name would otherwise be rejected, add an explicit per-unit mapping in the ``Naming`` package (see `Per-unit overrides`_ below). If your project uses a different convention, the ``Naming`` package lets you override it. Changing the dot replacement character -------------------------------------- To use ``__`` instead of ``-`` as the child-unit separator: .. code-block:: gpr package Naming is for Dot_Replacement use "__"; end Naming; With this setting, the body of ``My_Lib.Utils`` is expected in ``my_lib__utils.adb``. Changing the default suffixes ----------------------------- .. code-block:: gpr package Naming is for Spec_Suffix ("Ada") use ".1.ada"; for Body_Suffix ("Ada") use ".2.ada"; end Naming; Per-unit overrides ------------------ Individual units can be mapped to arbitrary file names: .. code-block:: gpr package Naming is for Spec ("My_Lib.Utils") use "ml_utils_s.ada"; for Body ("My_Lib.Utils") use "ml_utils_b.ada"; end Naming; Per-unit mappings take precedence over suffix rules. This is the mechanism GPRname uses when it generates a project file for a source tree with non-standard naming (see :ref:`Working_With_Tools`). Multiple suffixes per language ============================== ``Body_Suffix`` and ``Spec_Suffix`` accept a single value per language. A project that contains source files with different suffixes for the same language - for example ``.cc`` and ``.cpp`` both for C++ - cannot be described by a single suffix declaration. Two options are available: * **Rename all files to a common suffix.** This requires no project structure changes and is the simplest solution when the source tree is under your control. * **Split into two projects with** ``limited with``. Create a companion project that covers the extra suffix, sharing the same ``Source_Dirs`` and ``Object_Dir`` as the primary project. The companion imports the primary with a regular ``with``; the primary references the companion back with ``limited with`` to break what would otherwise be a circular dependency. The companion also sets ``Spec_Suffix`` to a value that matches no file, so it does not claim spec files already owned by the primary. The compiler settings are shared by renaming the package: .. code-block:: gpr -- prj.gpr (handles .cpp files) limited with "prj_cc_support"; project Prj is for Languages use ("C++"); for Source_Dirs use ("src"); for Object_Dir use "obj"; package Naming is for Body_Suffix ("C++") use ".cpp"; for Spec_Suffix ("C++") use ".h"; end Naming; package Compiler is for Switches ("C++") use ("-O2"); end Compiler; end Prj; .. code-block:: gpr -- prj_cc_support.gpr (handles .cc files) with "prj"; project Prj_Cc_Support is for Languages use ("C++"); for Source_Dirs use Prj'Source_Dirs; for Object_Dir use Prj'Object_Dir; package Naming is for Body_Suffix ("C++") use ".cc"; for Spec_Suffix ("C++") use ".no_match"; -- no .no_match files exist end Naming; package Compiler renames Prj.Compiler; end Prj_Cc_Support; Build with ``gprbuild -P prj.gpr``: GPRbuild loads both projects and compiles ``.cpp`` files via ``Prj`` and ``.cc`` files via ``Prj_Cc_Support``, depositing all objects in the shared ``obj/`` directory.