More power to GPRbuild

As somebody who just studies a whole Ada ecosystem I am learning a lot about GPRbuild and its language. I find this is a pretty interesting build system with features many other build systems do not have.

Looking at alire repository, however, I find that many projects also use GNU make as a kind of frontend to build and install things, sometimes even as a simple wrapper to GPRbuild. I’ve run into problems trying to make alire index more portable and those problems have been easily solved somewhere else.

I consider make ugly and GPRbuild nice and I was wondering why some projects still prefer make.

So the project idea is this:

  1. Identify most common reasons to use make instead of GPRbuild
  2. Consider additional features that should be added to the GPR language
  3. Implement them (preferably also in the older GPRbuild 1)
  4. Stop using make as a frontend

So far I have identified the following reasons:

  1. Convenience loops - it is easy for example to build 3 versions of a library looping around multiple gprbuild invocations with different -P parameters. Gem #158: GPRinstall - Part 1 | AdaCore gem suggests to simply run gprbuild/gprinstall in sequence to have a library built for three object format variants. I believe we could support something like this in GPR without introducing general purpose loops (which I think has been avoided on purpose)
  2. Building multiple projects - a variant of above if make is used to invoke multiple GPR projects within the same repository. If aggregate projects are too limited to achieve this, we should figure out what are the obstacles here.
  3. C language libraries - additional code like GNU autoconf and similar can be used to detect additional external libraries and feed them to the GPR processing. My proposal to solve the most typical use case is to integrate GPR tigher with pkgconf - to allow for example setting linker flags from within the GPR without resorting to the need to provide them externally.
  4. Code generation - there could be an additional phase before the compilation phase to invoke some additional code generators. I think LangKit based projects and maybe asn1scc should be used to make sure the feature is generic enough to support various code generators. I read somewhere (in the Lisp community) that if code generation is needed, this means that the abstractions that the programming language provides are not rich enough [citation needed], but solving this is definitely out of scope here.
  5. ….

A special mention goes to LangKit’s manage.py which is used for various aspects of building/confguration. I understand that this might be because some other non-Ada projects might want to use the library.

A major benefit of this is simplification of a whole ecosystem and lowering barriers of entry. Cargo users need only to use cargo. I believe alire is a wrong place to solve this problem. I’d rather be programming GPR than TOML if you ask me.We also do not want to convert the alire index to a full feature ports tree such as ravenports.

Solving all this requires some architectural discussion about where the GPR language should evolve. I am not sure where to start such a discussion, so I am trying here.

Difficulty to solve all of this is hard, but once the design directions are clear this might actually proceed. Good thing here is that we can devise smaller sub-projects to deal with various aspects of this issue.

For myself, I think that adding some kind of pkgconf integration should be easy enough for a newcomer like me to get started.

My apologies if this has been discussed extensively already, but I could not find much references to this, even with some LLM-based tools to search the Internet.

1 Like

I read somewhere that AdaCore will release a GPRBuild2. It will be interesting to see what new features it will provide

1 Like

Gprbuild is an extremely useful and powerful tool that exceeds make and cmake in every possible aspect. The reason why people use make is same why they use C. You will never get them back. Citing Dijkstra:

It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.

My issues with grpbuild are far more modest:

  • String and string list expressions: slicing substituting etc, preferably in Ada syntax.
  • Use (as a subproject) vs build (as a library) projects. Presently they must be different. It would be nice to have a single project file for both scenarios.
  • Predefined built-in variables/attributes/values identifying the operating system, machine, language standard version.

I also wished AdaCore actively promoted gprbuild. It is an excellent product useful far beyond Ada community. Once I was confronted by huge pile of cmake files and source directories for a legacy C++ project. The stuff just refused to build and nobody knew how to fix it. Coprology is not my thing, so I wrote a gpr-file. It took a half of a day and worked straight out the box.

That is why TOML must be placed into XML and that into JSON all parsed from Python. You cannot properly appreciate it without having all four at once… :grinning:

I’ve resorted to just converting makefiles to standalone Ada files when the build process gets too unwieldy for a makefile and doesn’t work well with gprbuild. Here’s one as an example, you might be able to pull some useful feature ideas from here: prunt/prebuild.adb at 3754d8fa4d32f8c3fa9fea054087fa968cebacf8 · Prunt3D/prunt · GitHub

Don’t mind the awful commit history on that branch, it’s all going to be squashed once it’s done, it only exists so I can grep older changes temporarily.

I don’t prefer make, but maybe it is my inexperience with GPRBuild, there are things I want to do that I haven’t figured out how to do in GPRBuild. For example, if I just want to execute a sequence of command line OS commands (Even Alire has some weaknesses here, though I’ve been more successful doing this in Alire), that is easy to do in Make, but I have not yet figured out how to do that in GPRBuild.

So until I get smarter, I’m still a bit forced to use make. Eventually I’m sure I’ll figure out everything.

On the flip side, I use GPRBuild to build embedded projects for a C compiler I have (with no Ada alternative currently availalbe). I’ve even integrated Alire with it for some nice setup.

1 Like

Don’t understand why people hate Make.

Make had existed for decades, managing nearly every codebase and is still alive. Make scales, starting from compiling a single file up to Linux kernel. Never seen a project that Make could not afford.

Make is just unbeatable, and every attempt to create something better, in the end generates some higher-level artifact that uses (and masks) the Make philosophy in some form.

A makefile inevitably turns in to something like this on any large project: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=Makefile.in;h=110fa63c10ccde884c97ed5bc00155e2154a503e;hb=refs/heads/master

That is a generated file, but the big pile of source files that generate it are not much better.

Edit: See also a human written makefile: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/Makefile.in;h=775080ef0f3df956746d89d35b4fe89015369355;hb=refs/heads/master

1 Like

That is the point. It is a different abstraction level. The gpr-language to OS commands is like Ada to machine code. The approach is not to stuff some scripts into the project but rather tell what these scripts are supposed to do and generalize it at the language level, like built-in gpr-packages Compiler, Linker etc do. One could consider adding user-defined packages if there is a convincing use case.

I like make. I use it every day (for example for FreeBSD ports collection). BSD make has a pretty nice structure of pre-defined sub-makefiles, so it is possible to simply say

PROG=cmd
SRCS=cmd.c
.include <bsd.prog.mk>

and it will compile, link and build a manpage for cmd

My point is, GPRbuild is so much better for Ada and I really do not want to use two or three (if you include Alire) for the job.

For many projects I have built manually recently it was enough to say make and make install

It should be possible to say gprbuild and gprinstall, that’s it!

I think the whole GNAT project world wants to be very portable, so you can run gprbuild the same way on lots of different platforms and running “some commands” is not a good idea unless we are sure the exist and behave the same on every platform. What are your commands used for?

1 Like

I am working with libgpr2 and gprbuild 2 in parallel and I think the project is more about switching the internals to use better language parsing infrastructure, so that (in the future) it will be easier to read not only Ada code but also other programming languages. Possibly with GPR2 it will be easier to extend the GPR language itself.

Today it is not able to build most of the projects I have tried, so they work in reaching the feature parity with gprbuild first generation if I get things right (from reading the code, not from talking to developers).

Several reasons, but here’s a few:

  1. Significant whitespace, eg the tab,
  2. Non-standard, despite the common availability something like Borland make is vastly different from GNU make.
  3. Magic tools/settings (ie “it works on my computer” syndrome), granted this is getting into non-make territory such as environment-variables, etc.
  4. Auto-tools.
  5. Utter-unhelpful generality. — with a more structured form, your tool could guide you into correct settings, example: imagine a GPR/GPRBuild built using Ada’s extant ‘circuitry’ and leveraging generics to provide the variables: your tool would then “know the type” of the parameter and guide you to a proper setting/value.
1 Like
  1. The TAB is just a symbol that you can replace. It’s kinda the braces in a random language. It’s a structure element.
  2. Make is something of POSIX.
  3. Magic tools/settings are not Make’s, are orrible shells and OS bugs to deal with. If you want to use GPRbuild, you have first to port GNAT, then GPRbuild. Then, who knows.
  4. Auto-tools is package manager and configuration. This is the tool that lets you build GCC and use Ada in your computer.
  5. Didn’t understand very well this point. I think it’s getting too abstract.

Being said that, I wonder how the software world could be without Make.

Build systems are super important but most build work is effectively useless work for the end customer. I want to spend my time on the problem, not setting up a build on a new project for the umpteeth time. GPRbuild is a bespoke syntax based on Ada that acted as an additional hurdle when I was learning Ada. LLMs might have mitigated this a bit, as well has having a forum to ask questions, but it was frustrating dealing with GPRbuild while learning the language and intimidating giving the complexity of the docs.

I could quibble about the settings, but Alire gives a “good enough” setup in a single command.

I use make for fast setup of quick things, but once I get to needing multiple configurations or need it to work on Windows, I tend to move to something else.

A lot of the C++ ecosystem has settled on CMake, but it’s a generator frontend for multiple build systems (e.g. ninja, Makefiles, etc.) with a bespoke syntax. LLMs are pretty good at it, and the CLion support is great, but it’s real killer feature is the ability to generate Visual Studio solutions (and Xcode projects).

There are other options I’d rather use: Buck2, Bazel, FASTBuild. Even before you look at scaling, and multi-language coverage, Buck2 and Bazel both use Starlark for syntax, a python subset that I’d expect most engineers to be comfortable working in. FASTBuild also has bespoke syntax, but it’s minimal and you can read the entire docs in an afternoon (or less).

Once I start passing 100k lines of code, there’s the question of remote execution and local caching. FASTBuild has this built-in and my testing showed about a 4x speed improvement over Makefiles on one project I converted. It also has remote execution, as does Buck2 and Bazel.

Alire softens the onboarding onto the ecosystem, which is why I’ve been such an advocate for it. GPRbuild is still there, and the TOML exposed dials help simplify things. If you really need to get more involved with the build you can, but if you just want to pull in a few libraries and build something, that’s usually straightforward. That gets people building with the language and driving it around the block before having to pop open the hood on “how does the build work?”

2 Likes

Assuming that deployment and maintenance are out of scope of your problem, then what is wrong with:

gnatmake my_problem.adb

Or two lines harder

   project My_Problem is
      for Main use ("my_problem.adb");
   end My_Problem;

Is make file shorter, clearer, more portable?

The actual problem is attitude to software design in general. Ada is meant for large scale software engineering. That requires a lot of upfront work: requirements, specifications, developing infrastructure etc. If you want to use Ada as if it were bash or Python, yes, you will be disappointed. However, in my experience Ada and grpbuild always pay off.

P.S. I remember hot debates about students incapable to learn Ada because Hello-World required

with Text_IO; use Text_IO; -- Ada 83

To auto generate ancillary files after compilation like specially formatted ASM listings, HEX files, and such. Some commands I can get to work, others do not seem doable in either GPRBuild or Alire, so I use Make instead.

1 Like
project Hello is
   for Main use ("hello.adb");
   package Compiler is
      for Default_Switches ("Ada") use ("--save-temps");
   end Compiler;
end Hello;

That doesn’t generate the right kind of files for what I need. These aren’t intermediate files but ones that are generated after the fact to get a specific output format

Honestly, much better than what we have.
A lot of programming (as-a-practice) has been kneecapped by C/Unix and it’s retarded fascination with text-first approaches. — Consider, just for a moment, the implications of the “Unix way” of “piping together small tools to solve a problem”. Because this is done in text, it forces all such construction inputs to parse outputs of the nodes, moreover it “bakes in” formatting. As an example consider a ‘program’ that operates on ls and assumes some format, which is then changed (by environment) or which ‘breaks’ some assumption. (A trivial [and obviously wrong] example would be a new programmer assuming there’s no such thing as a size 0 file and programming that in as an assumption for parsing the inputs; yes this is such an ‘observably wrong’ example as to possibly be regarded as a strawman: but to do so is ignoring the point, which is assumptions of outputs/formats.)

A good example of how text-first is stupid is considering diff and how “Jimmy’s editor converted tabs to spaces, so we don’t know what he changed to introduce the error” is just stupid. It simply doesn’t matter on a “structural diff” where the diff is operating on the semantics of the language rather than [plain] text. — Yet many programmers rush to defend “plain text” and “files”.

Another thing to consider is how this way of construction is wasteful of time/energy. Example: a number known in one program has to be rendered to text, then emitted, then consumed, then parsed back into a number; but with the caveat that all constraint information is lost! (This is true for all types rendered to plain-text and forced to ad hoc parse/consume.)

  1. You’re missing the point: significant whitespace is inviting errors for the simple fact that it is not (typically) displayed. For example, looking only at your monitor, can you tell the difference between echo/cat on something.ads (using tabs), and something.ads (using spaces)?
  2. Not everyone likes POSIX, and even if you consider POSIX to be a standardization it is typically regarded as a “Unix-like standard”. And even if you grant that, it doesn’t address the implementation differences brought up: Borland’s make is substantially different than GNU’s make is substantially different from Microsoft’s. (See Wikipedia.)
  3. While magic tools/settings are not actually part of make, they can be (and are) often assumed by the creator of the makefile.
  4. Autotools is configeration, yes; it often is used to generate a makefile, often with the abovementioned assumptions.
  5. By being overly-general, make eliminated the ability for the tool (the executable) to help guide the programmer. It’s the difference between C’s allowance of integers in conditionals and (eg) C#'s restriction to booleans.

Well, fortunately the whole world thought different, since they adopted Make.

I find really offensive to blame Make AFTER it helped the software community. So you are considering computer programmers of the ‘50s sorta of stupid primitive beasts, since they programmed only in assembler ?

In the meantime, I will sit and wait for tools able to build GCC or the Linux kernel.

And yes, even before those precious tools will reach that point, probably AI will write something that overcome everything.