1

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.

1 Answer 1

1

you need a body for

FE_INTERNAL
PyObject *
Video_uvlc_decode_frame (
    PyObject *input_buffer
);

like

 PyObject *
    Video_uvlc_decode_frame (
        PyObject *input_buffer
    )
{
 return input_buffer;
}
Sign up to request clarification or add additional context in comments.

7 Comments

produces a warning: ./uvlc-decoder.h:17:1: warning: control reaches end of non-void function [-Wreturn-type] }
PyObject * Video_uvlc_decode_frame ( PyObject *input_buffer ) { return input_buffer; }
Awesome. Thanks. All working. Would you mind explaining why that is needed?
The message you are getting actually comes from the linker, not from the compiler. After all of the input files have been read and all symbol resolution is complete, the link-editor searches the internal symbol table for any symbol references that have not been bound to symbol definitions. These symbol references are referred to as undefined symbols. Undefined symbols can affect the link-edit process according to the type of symbol, together with the type of output file being generated.
It means you haven't written a function, or you haven't created a variable, or you haven't linked against the library or object code that contains the missing function or variable. It means the linker has looked through all the compiled code you told it to, and it still can't find what it's looking for.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.