2

I need to use an externally built C library doing some calculation with trigonometric services to my Ada program. I do it well using an stm32 bb runtime (SFP) but when trying to do the same in a native environment using the default Ada runtime, I end up with linking problems. Hope I can find some help here.

I tried several configurations of project files (gpr) solutions and I always end up with the same kind of linking error:

Memory region         Used Size  Region Size  %age Used/opt/gnat/gnat_native/bin/../libexec/gcc/x86_64-pc-linux-gnu/7.3.1/ld: /home/pulsar/repos/pulsar-software/something/lib_c/libC.a(something.o): in function `compute':
(.text+0xa5): undefined reference to `sin'
collect2: error: ld returned 1 exit status

Here is what I've got so far.

The C library build sequence is as follows (confirmed by the library provider):

$ gcc -c something.c -o something.o
$ ar -r libsomethingLib.a something.o

The C library gpr file something_lib_c.gpr:

library project Something_Lib_C is
   for Languages        use ("C");
   for Externally_Built use "true";
   for Source_Dirs      use ("src_c");
   for Library_Dir      use "lib_c";
   for Library_Name     use "somethingLib";
   for Library_Kind     use "static";
end Geocaging_Lib_C;

In the lib_c directory, I have the actual library libsomethingLib.a

In the src_c directory, I have the header API to use the C library (something.h):

#ifndef _GEOCAGING_H
#define _GEOCAGING_H

typedef struct something_s something_t;

extern void compute(something_t* const self);

#endif // _GEOCAGING_H

Then here is the Ada project file that wraps the C library something_lib.gpr:

with "something_lib_c.gpr";

project Something_Lib extends "../settings.gpr" is

   for Languages   use ("Ada");
   for Source_Dirs use ("./src_ada");
   for Object_Dir  use "obj" & "/" & Target & "/" & Build;

end Geocaging_Lib;

In the directory src_ada, I have the Ada API wrapper (something_api.ads):

with Interfaces;   use Interfaces;
with Interfaces.C; use Interfaces.C;

package Something_API is

   type T_Something is null record;

   procedure Compute (Something : access T_Something);
   with Import => True,
        Convention => C,
        External_Name => "compute";

end Something_API;

And finally, I call the compute service from my Ada program by with-ing the Ada API wrapper.

Once again, when building/linking the whole thing for an arm-eabi target, using an stm32-full or stm32-sfp Ada runtime, everything runs well and the behavior of the library is validated.

The whole point is I'd like to do the thing in a native environment in order to run CI tests on it and I can't find a way to pass the link stage.

Last thing, in the Settings.gpr generic project file contains some common Ada build/bind/build switches that I can provide if necessary. But I can't see how this could work in arm and not in native with the same options. This HAS to be linked to the default Ada runtime thing...

Any idea?

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
ezwiebel
  • 31
  • 4
  • Possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – S.S. Anne Oct 07 '19 at 15:23
  • Link with the math library: `gcc ... -lm` – S.S. Anne Oct 07 '19 at 15:23
  • @JL2210, Thanks for the answer. I can't produce the C library myself, it's a third party library. And I don't want the producer to embed their math library, I want to use mine (i.e. the ada runtime math library). This is why a archive with no partial link is produced actually. – ezwiebel Oct 08 '19 at 09:27

2 Answers2

3

If you were building with a C main program, what would you have to do to bring in the maths libraries at link time? ... possibly something like

gcc foo.c -l somethingLib -lm

What you need to do is to arrange for the -lm to be included whenever you call in something_lib_c.gpr.

I think that what you need to do is to modify library project Something_Lib_C to include the line

for Library_Options use ("-lm");
Simon Wright
  • 25,108
  • 2
  • 35
  • 62
  • Since it seems OP has some elaborate build system, and error only appear when building native, maybe wrap that around a switch case depending on target ? `case target is when "xxx" => null; when "native" => for Library_Options use ("-lm"); end case;` or somehting in that flavor – LoneWanderer Oct 07 '19 at 20:18
  • @LoneWanderer, you're right and this is how I'll deal with this once the issue is solved. But at the moment I need to figure out what's happening on native side... – ezwiebel Oct 08 '19 at 09:29
  • @Simon Wright, Thanks for the answer but it doesn't seem to work... I get the exact same error. What really bugs me out is the fact that it works in the arm environment. – ezwiebel Oct 08 '19 at 09:45
  • @ezwiebel Is it possible that your math library does not provide `sin`? – S.S. Anne Oct 08 '19 at 11:01
  • @JL2210, would have loved it to be that simple. I use the sin example but in fact many other math services are used and "missing" to the linker (cos, asin, atan2,...) in the real program. I'm currently trying to see exactly which libraries are fetched from the native runtime and I might have found something related to libc... I'll keep you posted. – ezwiebel Oct 08 '19 at 12:35
  • @ezwiebel Do you link the math library before or after your main executable? – S.S. Anne Oct 08 '19 at 14:47
1

OK, my HUGE apologies to all of you who tried to help... The solution was more obvious than I thought, I was just too obsessed with the thing working in arm and not in native.

BUT, the solution was simply to add the -lm switch to the global linker switches. Hence:

   Ada_Switches_Linker_Native := (
        "-Wl,--gc-sections"
        ,"-Wl,--verbose"
        ,"-Wl,-lm"
      );

   package Linker is
      case Target is
         when "native" =>
            for Switches ("Ada") use Ada_Switches_Linker_Native;

      ...

      end case;
   end Linker;

In case it could be of interest for someone else, the fact that it works straightforward in arm environment and not in native is because the default runtime does not embed a specific mathematical library and you are supposed to use the C one provided by gcc, linking through the -lm switch.

In the contrary, when using a target specific runtime like arm (for stm32f4 for example), the correct mathematical libraries are provided, selected and automatically linked depending on your compilation options (-mhard-float, -msoft-float, etc.).

Sorry again and thank you very much for your time.

ezwiebel
  • 31
  • 4