AdaCore / gprbuild

GPRbuild is an advanced build system designed to help automate the construction of multi-language systems.
Other
65 stars 21 forks source link

Issue with libraries that contain implementation variants and are installed with the `-m` option. #138

Closed dvraaij closed 1 year ago

dvraaij commented 1 year ago

Consider a library project that contains only one package Foo. This package has two implementation variants that can be selected with a scenario variable.

library project Foo is

   type Variant_Type is ("variant1", "variant2");
   Variant : Variant_Type := External ("VARIANT", "variant1");

   for Library_Kind use "relocatable";
   for Library_Dir  use "lib";
   for Library_Name use "foo";

   for Source_Dirs use ("src");
   for Object_Dir use "obj";

   --  Select body for foo.ads.
   package Naming is
      case Variant is
         when "variant1" => for Body ("Foo") use "foo__variant1.adb";
         when "variant2" => for Body ("Foo") use "foo__variant2.adb";
      end case;
   end Naming;

end Foo;

One can now subsequently build and then install the project, and use the -m option of GPRinstall to (quote from the manual) "Install only the interface sources (minimal set of sources)":

$ gprbuild -XVARIANT="variant2" -P foo.gpr
$ gprinstall --prefix=$HOME/usr -m -p -XVARIANT="variant2" -P foo.gpr

The installation will then look something like this (note in particular the name of the ALI file in usr/lib/foo)

usr
├── include
│   └── foo
│       └── foo.ads
├── lib
│   ├── foo
│   │   ├── foo__variant2.ali
│   │   └── libfoo.so
│   └── libfoo.so -> ../lib/foo/libfoo.so
└── share
    └── gpr
        └── foo.gpr

However, attempting to use this library

with "usr/share/gpr/foo.gpr";

project Bar is
   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("main.adb");
end Bar;

will result in an error

$ gprbuild bar.gpr
Compile
   [Ada]          main.adb
Bind
   [gprbind]      main.bexch
   [Ada]          main.ali
error: "foo.ali" not found, "foo.ads" must be compiled
gprbind: invocation of gnatbind failed
gprbuild: unable to bind main.adb

So, at first sight, it seems that there is an issue with using the -m option when installing libraries that contain packages that have multiple implementation variants (bodies): GPRinstall does not properly rename the ALI file during installation.

On the other hand, it may also be an issue with the generation of the ALI files itself. As both package specs and bodies may have variants, maybe an ALI file should always be named after the compilation unit itself (e.g., the package name or the name of the subprogram) instead of being named after a source code file within the compilation unit. The filenames of the sources are already embedded in the ALI file anyway so no information is lost. The issue would then be related to the gnatbind program, I think.

The problem was found in a build of the GPRbuild Community 23.0.0 release published on GitHub. The issue could be reproduced with both GCC 12 and 13 (prerelease):

gcc (GCC) 12.2.1 20221121 (Red Hat 12.2.1-4)
gcc (GCC) 13.0.1 20230221 (Red Hat 13.0.1-0)
t-14 commented 1 year ago

Yes, this is unfortunately a particularity of the gnat compilation model, object and ali file names being constructed by stripping the extension of the body file rather than using the unit name, which gprinstall doesn't properly take into account. We are currently working on a workaround for this in the new gpr rewrite, but we won't backport it here. As a workaround, have your source variants differ by extension instead:

         when "variant1" => for Body ("Foo") use "foo.adb__variant1";
         when "variant2" => for Body ("Foo") use "foo.adb__variant2";