Aleph
Aleph

Reputation: 1373

Undefined symbols with add_swig_library

I tried to write a simple usage example of SWIG with CMake, but I get the following error message:

Undefined symbols for architecture x86_64:
"_My_variable", referenced from:
  _Swig_var_My_variable_get in examplePYTHON_wrap.c.o
  _Swig_var_My_variable_set in examplePYTHON_wrap.c.o
"_fact", referenced from:
  __wrap_fact in examplePYTHON_wrap.c.o
"_get_time", referenced from:
  __wrap_get_time in examplePYTHON_wrap.c.o
"_my_mod", referenced from:
  __wrap_my_mod in examplePYTHON_wrap.c.o
ld: symbol(s) not found for architecture x86_64

The CMake script is:

cmake_minimum_required(VERSION 3.8)

cmake_policy(SET CMP0078 OLD)
cmake_policy(SET CMP0086 OLD)

project(example C)

find_package(PythonLibs 3 REQUIRED)
find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} REQUIRED)

message(STATUS "Python executable is ${PYTHON_EXECUTABLE}")
message("PYTHONLIBS_VERSION_STRING: ${PYTHONLIBS_VERSION_STRING}")

include_directories(${PYTHON_INCLUDE_PATH} ${CMAKE_SOURCE_DIR})

find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})

message("CMAKE_SWIG_FLAGS: ${CMAKE_SWIG_FLAGS}")

swig_add_library(example TYPE SHARED LANGUAGE python SOURCES example.i)
swig_link_libraries(example ${PYTHON_LIBRARIES})

My SWIG example depends on two files.

First, there is a C file (example.c):

#include <time.h>

double My_variable = 3.0;

int fact(int n) 
{
  if (n <= 1)
    return 1;
  else
    return n * fact(n-1);
}

int my_mod(int x, int y)
{
  return (x%y);
}

char *get_time()
{
  time_t ltime;
  time(&ltime);
  return ctime(&ltime);
}

There is also a SWIG file (example.i):

%module example

%{
/* Put header files here or function declarations like below */
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
%}

extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();

For a reason I do not understand, functions and variables from example.c are not recognized when using CMake. However, everything works fine without CMake:

swig -python example.i
gcc -c example.c example_wrap.c -I<path_to_directory_containing_Python.h>
gcc -shared example.o example_wrap.o -o _example.so 

I tried to compare these lines with the verbose output of

make 

but the latter are far more complex than the former.

EDIT: This shows that CMake effectively calls swig:

 /usr/local/Cellar/cmake/3.15.3/bin/cmake -E env SWIG_LIB=/usr/local/Cellar/swig/4.0.1/share/swig/4.0.1 /usr/local/bin/swig -python -outdir /Users/myself/forexample/swig/build -interface _example -I/usr/local/Frameworks/Python.framework/Versions/3.7/include/python3.7m -I/Users/myself/forexample/swig -o /Users/myself/forexample/swig/build/CMakeFiles/_example.dir/examplePYTHON_wrap.c /Users/myself/forexample/swig/example.i

Upvotes: 1

Views: 474

Answers (1)

Kevin
Kevin

Reputation: 18243

Your CMake doesn't seem to reference example.c at all; this is why all your function definitions cannot be found. The error:

Undefined symbols for architecture x86_64:

is a red herring as there is not really an architecture mismatch; these symbols have not been defined at all. Try to modify your CMake to include a library for the C code, then link it to your SWIG library. Something like this should help resolve the errors:

cmake_minimum_required(VERSION 3.8)

cmake_policy(SET CMP0078 OLD)
cmake_policy(SET CMP0086 OLD)

project(example C)

find_package(PythonLibs 3 REQUIRED)
find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} REQUIRED)

message(STATUS "Python executable is ${PYTHON_EXECUTABLE}")
message("PYTHONLIBS_VERSION_STRING: ${PYTHONLIBS_VERSION_STRING}")

include_directories(${PYTHON_INCLUDE_PATH} ${CMAKE_SOURCE_DIR})

find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})

message("CMAKE_SWIG_FLAGS: ${CMAKE_SWIG_FLAGS}")

add_library(MyCLib example.c)

swig_add_library(example TYPE SHARED LANGUAGE python SOURCES example.i)
swig_link_libraries(example MyCLib ${PYTHON_LIBRARIES})

Upvotes: 2

Related Questions