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

gprbuild seems favour LLVM over GCC for C code and causing linking error for GtkAda #60

Closed qunying closed 5 years ago

qunying commented 5 years ago

Hi,

In Slackware-current, it has both llvm-8.0.0 and gcc-9.1.0 installed. After compiling/installing gprbuild (master trunk code), test build with gtkada (trunk code).

It compiles the C code in gtkada with llvm, and Ada part with gnat in GCC, which causing linking error.

If llvm is removed from the system, then everything is compiled fine.

What is the logic here to prefer llvm for C compilation? Is there a simple way to only use GCC in stead, or if Ada is compile with gnat then C should use gcc? Or it is a GtkAda configure problem?

t-14 commented 5 years ago

What is the logic here to prefer llvm for C compilation? Is there a simple way to only use GCC in stead, or if Ada is compile with gnat then C should use gcc? Or it is a GtkAda configure problem?

The logic is simply the PATH order. So swapping the two toolchains (or just hiding llvm one outright) is an easy way to get what you want. You can also use the following declaration to force gcc:

for Toolchain_Name ("C") use "GCC";

maxime-esa commented 3 years ago

Are you sure this is not a bug ? Why would you use clang based on PATH order (i.e. non-deterministically) ? GCC should be the default configuration unless specified otherwise, especially since the Toolchain_Name option is nearly undocumented. Adding "For Driver ("C") use "gcc", even if useful to enable Coverity checks, is also adding unnecessary noise to most project files, which are expected to work with the default Gnat toolchain, i.e. GCC.

I am not sure that you can just replace gcc with clang without side effects, as they sometimes have different behaviours

For example I get this errror:

clang: warning: argument unused during compilation: '-specs=/tmp/GNAT-TEMP-000010.TMP' [-Wunused-command-line-argument]

Because the specs file is ignored by clang, the include paths ("For Source_Dirs") are missing, and the build fails.

I suggest to consider re-opening this ticket and fixing the bug..

t-14 commented 3 years ago

Are you sure this is not a bug ?

Yes, we are sure. If you check the doc for the word "PATH" you will see it mentioned all over the place. This is by design.

Why would you use clang based on PATH order (i.e. non-deterministically) ?

There is nothing non-deterministic about PATH - it's a string! You probably mean that it can change from one call to the next - yes indeed, and is exactly the way we want it.

GCC should be the default configuration

No, gprbuild is not part of gcc collection to enforce such a default; besides - which gcc exactly should be the default? User system can have dozens...

especially since the Toolchain_Name option is nearly undocumented

If you feel that this attribute merits better documentation, feel free to propose a PR.

Adding "For Driver ("C") use "gcc"

It should be Toolchain_Name, not Driver. The two declarations have very different semantics. If you do the above you'll be configuring for clang and just replacing the compiler driver at the last moment.

I am not sure that you can just replace gcc with clang without side effects, as they sometimes have different behaviours

So do different versions of gcc; it's the knowledge base's responsibility to configure the toolchain correctly. The problem you are reporting suggests it's not working properly for LLVM, which is a different matter entirely - can you please open a new issue for that and we'll look into it.

I suggest to consider re-opening this ticket and fixing the bug.

There is no bug with respect to which toolchain gets selected, so please let's not recycle this issue to address an unrelated one.

t-14 commented 3 years ago

The problem you are reporting suggests it's not working properly for LLVM, which is a different matter entirely - can you please open a new issue for that and we'll look into it.

Note - please open it for gprconfig_kb project where KB is now maintained.

maxime-esa commented 3 years ago

Thank you for your quick answer.

Why would you use clang based on PATH order (i.e. non-deterministically) ?

There is nothing non-deterministic about PATH - it's a string! You probably mean that it can change from one call to the next - yes indeed, and is exactly the way we want it.

GCC should be the default configuration No, gprbuild is not part of gcc collection to enforce such a default; besides - which gcc exactly should be the default? User system can have dozens...

By non-deteministic I mean that the tool makes a choice not only based on the inputs you give (the gprfile and the tool's own configuration, i.e. the gpr knowledge base) but also based on random environment strings (random in the sense it depends on the order in which the user installed tools and updated the PATH). (and in that particular case clang and gcc are both in /usr/bin so the influence of the PATH string is not that obvious to me).

I think this non-determinism is a bug, and it would be solved by either setting a default Toolchain_Name (e.g. GCC) or having this parameter mandatory for the user to set (at the minimum a warning or info should be displayed to indicate which toolchain is used and why).

especially since the Toolchain_Name option is nearly undocumented

If you feel that this attribute merits better documentation, feel free to propose a PR.

Sure but it is a chicken and egg issue for me. The documentation that mentions this parameter (https://docs.adacore.com/gprbuild-docs/html/gprbuild_ug/gnat_project_manager.html) does not give the list of possible toolchain names, which is the information missing in the documentation, and does not tell where to find this information. I also don't know the history of this parameter, and in which version of gprbuild it was introduced, which would be also an essential information in the documentation.

t-14 commented 3 years ago

By non-deteministic I mean that the tool makes a choice not only based on the inputs you give (the gprfile and the tool's own configuration, i.e. the gpr knowledge base) but also based on random environment strings (random in the sense it depends on the order in which the user installed tools and updated the PATH).

But it's universally true - if the user is careless about setting up his environment, he is liable to not use the right toolchains. Even if we preferred gcc to other toolchains (which we have no practical means of doing short of hardcoding it in gprconfig), we still would in the general case have the issue of choosing between potentially several gcc toolchains.

Note that the user can preconfigure his build environment with explicit paths by calling gprconfig directly if he doesn't want to rely on PATH order.

(and in that particular case clang and gcc are both in /usr/bin so the influence of the PATH string is not that obvious to me).

Wait. If the two toolchains are in the same location, then PATH order is red herring. In this case toolchain will probably indeed be chosen non-deterministically (in the sense of "in arbitrary order").

I think this non-determinism is a bug

It really is not a bug but expected behavior. Either the user doesn't care about the toolchain that gets used, only for the final result, or he does; in the latter case, he has the means to enforce it.

and it would be solved by either setting a default Toolchain_Name (e.g. GCC)

We don't have a notion of "default toolchain" at the moment; implementing such a notion may indeed be beneficial but it is a major change (requires implementing fallback mechanism at a place where none exists at the moment). If you feel motivated, again, PR is probably the best way to see this enhancement implemented.

or having this parameter mandatory for the user to set (at the minimum a warning or info should be displayed to indicate which toolchain is used and why).

The former would be very unfriendly, to accomplish the later you can use -kargs -v (that will be somewhat verbose though...)

Sure but it is a chicken and egg issue for me. The documentation that mentions this parameter (https://docs.adacore.com/gprbuild-docs/html/gprbuild_ug/gnat_project_manager.html) does not give the list of possible toolchain names, which is the information missing in the documentation

Of course it doesn't - it's a property of the knowledge base, which is external to the tool and user-modifiable. Nothing prevents you from defining your own toolchain.

, and does not tell where to find this information.

This information is in the chapter about the knowledge base.

I also don't know the history of this parameter, and in which version of gprbuild it was introduced, which would be also an essential information in the documentation.

Not sure I understood that - you'd be documenting the current state of things, previous versions of gprbuild have past version of documentation so necessarily don't include the passage that doesn't even exist yet...

qunying commented 3 years ago

Indeed, this is not a path order issue, as both of the compiler resides at the same path (/usr/bin). And the system have only one gcc and one llvm, when Ada is compiled with gnat and C compiled with llvm looks weird without user direction.

maxime-esa commented 3 years ago

By non-deteministic I mean that the tool makes a choice not only based on the inputs you give (the gprfile and the tool's own configuration, i.e. the gpr knowledge base) but also based on random environment strings (random in the sense it depends on the order in which the user installed tools and updated the PATH).

But it's universally true - if the user is careless about setting up his environment, he is liable to not use the right toolchains. Even if we preferred gcc to other toolchains (which we have no practical means of doing short of hardcoding it in gprconfig), we still would in the general case have the issue of choosing between potentially several gcc toolchains.

What do you mean careless about setting up his environment? In a standard linux distribution you can install by default both GCC and LLVM from the repositories of the distribution, and you are in perfect control of your configuration. If for some reasons you need to have several versions of GCC you would typically use something like update-alternatives to select which version is linked to /usr/bin/gcc.

Note that the user can preconfigure his build environment with explicit paths by calling gprconfig directly if he doesn't want to rely on PATH order.

Indeed this seems to be the only workaround to get deterministic builds, since Toolchain_Name exists only in the very last versions of gprbuild (e.g. it does not exist in debian buster).

So basically the solution for x86 targets is to run:

gprconfig --batch --target=x86_64-pc-linux-gnu --config=Ada,,default,/usr/bin/,GNAT --config=C,,,/usr/bin/,GCC --config=C++,,,/usr/bin/,G++

in order to get a "default.cgpr" file in the same folder as the gpr file and make 100% sure it will never be built by LLVM. Correct?

I also don't know the history of this parameter, and in which version of gprbuild it was introduced, which would be also an essential information in the documentation.

Not sure I understood that - you'd be documenting the current state of things, previous versions of gprbuild have past version of documentation so necessarily don't include the passage that doesn't even exist yet...

This is just a suggestion, but from a practical point of view when you look for documentation nowadays, you tend to first google and check (in that case) the results from the Adacore page and you expect to find out what will work with your setup. If you look at the Python documentation, you immediately get the version where the feature is available, for example: image

Anyway that's off-topic, sorry.

t-14 commented 3 years ago

Indeed this seems to be the only workaround to get deterministic builds, since Toolchain_Name exists only in the very last versions of gprbuild (e.g. it does not exist in debian buster).

If you don't want to use the latest gprbuild version then nothing we do about this issue in the latest version will have an effect anyway ;)

That said, I agree that in the specific case of two toolchains in the same directory, the doc provides no guidance which one will be picked up, and the order looks suboptimal. We will investigate if there is an easy win here.

So basically the solution for x86 targets is to run:

gprconfig --batch --target=x86_64-pc-linux-gnu --config=Ada,,default,/usr/bin/,GNAT --config=C,,,/usr/bin/,GCC --config=C++,,,/usr/bin/,G++

in order to get a "default.cgpr" file in the same folder as the gpr file and make 100% sure it will never be built by LLVM. Correct?

Yes, that's correct.

This is just a suggestion, but from a practical point of view when you look for documentation nowadays, you tend to first google and check (in that case) the results from the Adacore page and you expect to find out what will work with your setup. If you look at the Python documentation, you immediately get the version where the feature is available, for example: image

Anyway that's off-topic, sorry.

Ok, I see what you mean. We don't have provision for that ATM.

GavinRay97 commented 1 year ago

@maxime-esa Thanks for your post with that line for configuring gprbuild.

I'm new to Ada, and have been trying to figure out how to use a locally-built version of GCC 13 dev I have at /usr/local/gcc-dev instead of the GCC 12 it picks up off my path. I found this GH issue from Google and your comment may have saved the day.

It seems like this is the trick?

gprconfig --batch \
  --target=x86_64-pc-linux-gnu \
  --config=Ada,,default,/usr/local/gcc-dev/bin,GNAT \
  --config=C,,,/usr/local/gcc-dev/bin,GCC \
  --config=C++,,,/usr/local/gcc-dev/bin,G++
t-14 commented 1 year ago

@GavinRay97 that's one way to do it; since it sounds like what you really want to tell gprconfig is "use toolchain of specific version and not any other" you can also make this explicit, with an option like --config=C,13.x.x (for the avoidance of doubt - "x" should be whatever minor and micro version you've got...); finally, another option is to just launch gprconfig without arguments, and then select the toolchains you need interactively...