1

So, this is a bit of a crap shot, but I have a .gpr file that came as part of a legacy code package. There is a considerable amount of C and C++ code that is linked in during the build.

By itself, the package works just fine. However, if I change the Main file from the current main to a different main -- one that incidentally has a certain apparently unnecessary with statement in it, the project build fails with the following message:

Error Message:

gprbuild: link of test_main.2.ada failed

Besides different code in the Main procedure itself (the code is not part of the problem), the only difference between the two files is the removal of this single with directive. If it's there, the build succeeds. If I comment it out, the build fails. Note that the compiler doesn't notice a problem, because none of the code in Main appears to need it.

Any idea why this is?

theMayer
  • 15,456
  • 7
  • 58
  • 90
  • As long as you do not show any code (e.g. the project file, the main, the `with`'d file), answering this question can only be done by wild-guessing. – flyx Nov 29 '17 at 16:31
  • I'm not sure what use the code would be... would there be something in here you are looking for? I can't paste the code without changing it as it is export controlled. – theMayer Nov 29 '17 at 16:50
  • 1
    My point is more that if you cannot give enough information for other users to [reproduce your problem](https://stackoverflow.com/help/mcve), the probability of getting useful answers is significantly lower. – flyx Nov 29 '17 at 16:55
  • 1
    I think you have to take the failing case and simplify Main as far as you can without the build succeeding to generate an [MCVE] as flyx suggests. Another line of approach is to try running the failing linker command standalone in a terminal, with verbose options, to find in more detail how it is failing. –  Nov 29 '17 at 17:12
  • 1
    Also, does any of the C/C++ call back to Ada code? Ada is designed to track all project dependencies automatically (eliminating major "Make" headachery) but it can't track Ada dependencies sneaking in by the backdoor via the C interface. –  Nov 29 '17 at 17:15
  • It is possible. The C/C++ code base is over 1M lines, so I don't know where I would even go to find such a thing. And there is no way that I could put a MCV example in here- since this is kind of an oddball issue, I'm looking for perhaps something simple or something common that I may have overlooked. – theMayer Nov 29 '17 at 17:48
  • Well the legacy C++ side may be difficult to deal with, but the Ada side would export anything callable via its foreign language interface., so you could look for that - search for `with interfaces.c;` may yield some clues; ditto `pragma export` (often followed by `(convention => "C")` see also this rather old Q&A https://stackoverflow.com/questions/255741/can-you-call-ada-functions-from-c –  Nov 29 '17 at 18:18
  • I already know the Ada code is calling the C and C++. The issue appears to be some cross-linked dependencies that don't get properly resolved unless with file is "with'd" in the main program... – theMayer Nov 29 '17 at 18:23
  • No, I'm asking if the Ada side exports any of its own code to be called from C/C++. That can't be directly tracked as a dependency by the Ada compiler, so should properly be tracked via the C compilation process and its means for handling dependencies (i.e. "make", or something in the gpr file). If there's a failure here (and "make" dependencies are IMO a mess) I'm speculating in the absence of anything substantive, that a spurious "with" clause may hide the failure somehow. –  Nov 29 '17 at 18:30
  • `test_main.2.ada` is a weird name for an Ada file, though. The default GNAT naming convention would be `.adb`. And what is that `.2` doing there? – egilhh Nov 29 '17 at 18:36
  • @egilhh, that’s Rational Apex naming - `.1.ada` for a spec, `.2.ada` for a body (and maybe other cases too, e.g. separates) – Simon Wright Nov 29 '17 at 19:31
  • @SimonWright, OK, the OP mentioned using `.gpr` files and gprbuild, so I just assumed GNAT... – egilhh Nov 29 '17 at 19:34
  • Does doing the linking verbosely (gprbuild options `-largs -v`) add anything? You might even try `-Wl,-v` to add the verbose option to the system linker call. – Simon Wright Nov 29 '17 at 19:34
  • A main `with` might be there to call in a library-level package that’s the instigator for some important functionality. For example, [here](https://github.com/simonjwright/Certyflie/blob/ravenscar-cf-stable/src/main.adb#L35), [package Tasks](https://github.com/simonjwright/Certyflie/blob/ravenscar-cf-stable/src/tasks.ads) brings in all the independent tasks that compose the system. Mind, in that case, commenting-out the apparently superfluous `with` results in a (smaller) build - which doesn’t work, of course. – Simon Wright Nov 29 '17 at 19:47
  • @SimonWright - could you please post that as an answer so I can give you some points? I think that is the type of information I was looking for. Bonus points if there are any mitigating actions that can be taken. – theMayer Nov 29 '17 at 20:46
  • And just to be clear, yes we are using gprbuild, but at one point in the past this codebase was done in Rational Apex. This is a 25-year-old codebase. – theMayer Nov 29 '17 at 20:47

2 Answers2

2

Not much to go on in your question, but one possibility could be a pragma Linker_Options in the withed package, if another package also depends on certain linker options, but does not specify that pragma itself. In that case, you could either

  • copy the pragma to the other package, or
  • modify the Default_Switches in the package Linker in the gpr file to include the options
egilhh
  • 6,464
  • 1
  • 18
  • 19
  • There are no pragmas in the Main file. The .gpr file is identical except for the line telling it to use a different main file. – theMayer Nov 29 '17 at 17:50
  • I didn't say Main... I said `with`ed file. Which includes both `.ads` and `.adb` (so I updated my answer to say `package` instead) – egilhh Nov 29 '17 at 17:52
  • The with'd file has one pragma use - `pragma Priority (System.Priority'Last);` - could this somehow be related to my issue? – theMayer Nov 29 '17 at 17:57
  • The file in question is nearly 3k lines sadly. – theMayer Nov 29 '17 at 17:59
2

One reason for having a with in your main program where there's no obvious need for it is when you have a library-level component, probably involving a task (hinted at by your pragma Priority (System.Priority'Last);), which is logically at top-level in your design, so isn't naturally referenced by anything else.

Such a library-level component might look like (warning, Ada2012 here)

package Top with Elaborate_Body is
end Top;

with ...;
with System;
package body Top is

   task Processing with Priority => System.Priority'Last;

   task body Processing is
   ...

end Top;

and then

with Top;
pragma Unreferenced (Top);
procedure Main is
...

(the pragma Unreferenced is to stop GNAT warning you that Top isn't used).

It's not obvious how this would lead to a link failure, though. Maybe (your equivalent of) Top, or something that only it references, has a pragma Linker_Options that calls in a library that's needed by other part of the system?

Simon Wright
  • 25,108
  • 2
  • 35
  • 62