Search code examples
cgocompiler-errorscgomath.h

How do you use Golang's cgo with C libraries that link to math.h?


I'm currently trying to build a Golang wrapper for the NOVAS C package (an astrometry/astronomy package) by using cgo. NOVAS is essentially 'installed' by placing the source files in whatever directory you happen to be working in (no compiled library files present), hence I believe I need to include the .c files I will be using (which is in a folder one directory down from the .go file.

As such, I'm trying to test this by creating a test .go program which itself calls a function within novas.c. However, the program fails to compile, apparently because there are multiple undefined references to functions present within math.h; this is strange because math.h is included both in my .go file and the C files I intend to use.

go run novasTest.go 
# command-line-arguments
/tmp/go-build681583835/b001/_x002.o: In function `equ2gal':
./Cdist/novas.c:1995: undefined reference to `sincos'
./Cdist/novas.c:1996: undefined reference to `sincos'
./Cdist/novas.c:2033: undefined reference to `atan2'
./Cdist/novas.c:2025: undefined reference to `atan2'
./Cdist/novas.c:2022: undefined reference to `sqrt'
/tmp/go-build681583835/b001/_x002.o: In function `era':
./Cdist/novas.c:3242: undefined reference to `fmod'
./Cdist/novas.c:3242: undefined reference to `fmod'
...(etcetera)

I'm running on Ubuntu 18.04 (x64) within a VirtualBox VM instance. Am I missing a specific line here?

My go program looks like this:

package main

/*
#include "Cdist/novas.h"
#include "Cdist/novas.c"
#include "Cdist/novascon.c"
#include "Cdist/nutation.c"
#include <math.h>
*/
import "C"
import "log"  

func main() {
    log.Println("Test of NOVAS function")
    var JulianHigh C.double
    var JulianLow C.double
    ...
    var Z C.double

    // Test values
    JulianHigh = 2458953.5 
    JulianLow = 1.0
    ...
    Z = -1.437110810486059E+03

    vCel := make([]C.double,0) //Create the array to pass to the function.
    vCel = append(vCel, X)
    ...
    vTerFirst := &(vTer[0])

    C.cel2ter(JulianHigh,JulianLow,DeltaT,Method,Accuracy,Option,PolarX,PolarY,vCelFirst,vTerFirst)

    log.Println("C function completed processing.")
}

The C program is too large to include, so I will instead show the relevant parts of the novas.h file and novas.c file.

C File:

/*
  ...
  novas.c: Main library
  ...
*/

#ifndef _NOVAS_
   #include "novas.h"
#endif

#include <math.h>
... //(other functions follow until the necessary one)
/********cel2ter */

short int cel2ter (double jd_ut_high, double jd_ut_low, double delta_t,
                   short int method, short int accuracy, short int option,
                   double xp, double yp, double *vec1,

                   double *vec2)
/*
------------------------------------------------------------------------

   PURPOSE:
      This function...

Note that the function itself relies on functions that make calls from the other files I included.

.h file:

/*
  ...
  novas.h: Header file for novas.c
  ...
*/

#ifndef _NOVAS_
   #define _NOVAS_

   #ifndef __STDIO__
      #include <stdio.h>
   #endif

   #ifndef __MATH__
      #include <math.h>
   #endif

   #ifndef __STRING__
      #include <string.h>
   #endif
   ...

Solution

  • You need a directive to tell the go linker to link with c's math library. The header math.h doesn't contain implementations of the math functions: only their declarations (to a first approximation).

    Anyway, you need to add this line in a comment in your go file:

    #cgo LDFLAGS: -lm
    

    -l means "link with this library", and m is the name of C's maths library.