I am trying to compile some c based video decoder functions I found on github in order to run them as functions in python. Unfortunately, I'm running into gcc linker problems. I'm pretty flat on my face compiling c from the command line (I used to do it once in eclipse).
Here is what I am running from the command line
gcc -dynamiclib -I/usr/include/python2.7/ -lpython2.7 -o _decoder.dylib _decoder.c
I also tried to add these options to help the linker find, well, links to the .c and .h files which define the "missing" function (which are all in the same directory and whose path I will abbreviate to $PATHTOCFILESDIR)
-I/$PATHTOCFILESDIR/uvlc-decoder.c
-I/$PATHTOCFILESDIR/uvlc-decoder.h
Here is the Error:
Undefined symbols for architecture x86_64:
"_Video_uvlc_decode_frame", referenced from:
___decode_uvlc_frame in _decoder-db7728.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1
After reviewing with google, I looked through all of the other c and h files trying to find why gcc can't find the Video_uvlc_decode_frame function, but it is not immediately transparent to me. My only guess is (and this is shown below) I noticed a few lines throughout the files like "FE_INTERNAL" which I found outside of my knowledge of C. I believe this is for Sphinx which is not installed on my build. Would that cause these linker issues?
Here is a reduction of the relevant code:
Top portion of file which the linker is pointing to for an error:
_decoder.c
#include <string.h>
#include "idct8.h"
#include "uvlc-decoder.h"
#include "_decoder.h"
static PyObject *
__decode_uvlc_frame (
PyObject *self,
PyObject *args
)
{
PyObject *input_buffer;
if (!PyArg_ParseTuple(args, "S:decode_h263_uvlc", &input_buffer))
return NULL;
return Video_uvlc_decode_frame(input_buffer);
}
Declaration of the include file that (I thought) should point to the "missing" function:
uvlc-decoder.h
#ifndef __VIDEO_UVLC_DECODER_H__
#define __VIDEO_UVLC_DECODER_H__
#include <stdint.h>
#include <stdbool.h>
#include <Python.h>
#include "utils.h"
FE_INTERNAL
PyObject *
Video_uvlc_decode_frame (
PyObject *input_buffer
);
#endif
EDIT: I found the definition for FE_INTERNAL in another file in the directory:
utils.h
#ifdef __GNUC__
# define FE_LIKELY(x) __builtin_expect((x), 1)
# define FE_UNLIKELY(x) __builtin_expect((x), 0)
# define FE_INTERNAL __attribute__((visibility("hidden")))
#else
# define FE_LIKELY(x) (x)
# define FE_UNLIKELY(x) (x)
# define FE_INTERNAL
#endif
EDIT2: This wasn't transparent originally but there is one more file that I believe changes the answer. Here is the relevant info for that:
uvlc-decoder.c
#include <stdlib.h>
#include <string.h>
#include "idct8.h"
#include "uvlc-decoder.h"
#include "uvlc-decoder-priv.h"
/*
number of other functions defined here that have been removed for brevity
*/
PyObject *
Video_uvlc_decode_frame (
PyObject *input_buffer
)
{
__DecoderState dec_state;
PyObject *picture_desc = NULL;
dec_state.out_picture_buf = NULL;
dec_state.bitstream = FeDrone_BitStreamReader_new(input_buffer);
if (FE_LIKELY(__decoder_read_frame(&dec_state))) {
picture_desc = Py_BuildValue("(IIIs#)",
dec_state.pic_header.width,
dec_state.pic_header.height,
dec_state.pic_header.frame_nr,
(char *)dec_state.out_picture_buf,
(int)dec_state.out_picture_len);
}
PyMem_FREE(dec_state.out_picture_buf);
dec_state.out_picture_buf = NULL;
Video_BitStreamReader_free(dec_state.bitstream);
dec_state.bitstream = NULL;
return picture_desc;
}
EDIT3:
ultimate gcc command I used:
gcc -dynamiclib `python-config --cflags` `python-config --ldflags` -o _decoder.so *.c
This command will use the local build of the python framework I am developing on (macports build). The *.c is basically telling gcc to use all the .c files in the current folder when linking.