LINUX.ORG.RU

swig(c++ -> python) ошибка линковки

 , ,


1

1

code.cpp:

#include "code.h"
#include <iostream>

void foobar(void){
	std::cout<<"foobar()"<<std::endl;
}
code.h:
#ifndef _code
#define _code
int nx=8;
int ny=8;
int nz=8;
float dx=0.1;
float dy=0.1;
float dz=0.1;
void foobar(void);
#endif
code.i:
%module code
%{
#include "code.h"
%}
%include "code.h"
Компилирую:
g++ -std=c++11 -c -fPIC code.cpp
swig -c++ -python code.i
g++ -std=c++11 -c -fPIC code_wrap.cxx  -I/usr/include/python2.7 -I/usr/lib/python2.7
g++ -std=c++11 -shared -Wl,-soname,_code.so -o _code.so code.o code_wrap.o
и получаю ошибку линковки:
code_wrap.o:(.data+0x188): multiple definition of `nx'
code.o:(.data+0x0): first defined here
code_wrap.o:(.data+0x18c): multiple definition of `ny'
code.o:(.data+0x4): first defined here
code_wrap.o:(.data+0x190): multiple definition of `nz'
code.o:(.data+0x8): first defined here
code_wrap.o:(.data+0x194): multiple definition of `dx'
code.o:(.data+0xc): first defined here
code_wrap.o:(.data+0x198): multiple definition of `dy'
code.o:(.data+0x10): first defined here
code_wrap.o:(.data+0x19c): multiple definition of `dz'
code.o:(.data+0x14): first defined here
Какого хрена? И что тогда эта зараза не рушается на multiple definition of `void foobar(void)`?

★★★★★

А нефиг в хедере присваивать значение.

omnomnomnus ()

И что тогда эта зараза не рушается на multiple definition of `void foobar(void)`?

Если бы функция вызывалась в обоих файлах, так и было бы

annulen ★★★★★ ()
Ответ на: комментарий от omnomnomnus

Хотя нет, с инклудами всё нормально. А проблемы с линковкой из-за присвоенных значений в хидерах.

omnomnomnus ()
Ответ на: комментарий от omnomnomnus

Если не присваивать, то всё равно ругается же.

thunar ★★★★★ ()
Ответ на: комментарий от thunar

Глобальную переменную надо объявлять в .h и определять в .cpp, за исключением констант

annulen ★★★★★ ()

Вот упрощенный пример, иллюстирующий твою ошибку:

code.h:

#ifndef _code
#define _code
int foo = 3;
int foobar(int);
#endif

code.cpp:

#include "code.h"
int foobar(int bar) {
  return foo + bar;
}

main.cpp

#include "code.h"
int main() {
  return foobar(39);
}

Компиляция с ошибкой:

λ nameless@desktop /tmp → g++ -c main.cpp
λ nameless@desktop /tmp → g++ -c code.cpp
λ nameless@desktop /tmp → g++ code.cpp main.cpp -o main
/tmp/ccf9WSlI.o:(.data+0x0): multiple definition of `foo'
/tmp/ccShK7Rb.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status

Посмотрим, что с нашими файлами делает препроцессор:

λ nameless@desktop /tmp → cpp main.cpp | grep -vE '^(#.+)?$'
int foo = 3;
int foobar(int);
int main() {
  return foobar(39);
}
λ nameless@desktop /tmp → cpp code.cpp | grep -vE '^(#.+)?$'
int foo = 3;
int foobar(int);
int foobar(int bar) {
  return foo + bar;
}

Смотрим на объектные файлы:

λ nameless@desktop /tmp → objdump -t main.o | grep '\bfoo\b'
0000000000000000 g     O .data	0000000000000004 foo
λ nameless@desktop /tmp → objdump -t code.o | grep '\bfoo\b'
0000000000000000 g     O .data	0000000000000004 foo

Видим, что в каждой единице трансляции объявлен символ foo.

—————————

Чтобы поправить свой пример, делай так:

code.h:

#ifndef _code
#define _code

extern int nx;
extern int ny;
extern int nz;

extern float dx;
extern float dy;
extern float dz;

void foobar();
#endif

code.cpp:

#include <iostream>
#include "code.h"

int nx = 8;
int ny = 8;
int nz = 8;

float dx = 0.1;
float dy = 0.1;
float dz = 0.1;

void foobar() {
  std::cout << "foobar()" << std::endl;
}

Не нужно забывать, что препроцессор C/C++ буквально подставляет содержимое заголовочных файлов в место вызова #include ... (плюс выполняет раскрытие макросов). Это значит, что после работы препроцессора у тебя в каждой из единиц трансляции, в которых подключался “code.h”, будет определена своя копия nx, ny, nz и т.д., что и приводит тебя к сабжевой ошибке. Поэтому надо в заголовочном файле объявить переменную с помощью ключевого слова extern, а определение этой переменной засунуть в cpp-файл.

theNamelessOne ★★★★★ ()

И что тогда эта зараза не рушается на multiple definition of void foobar(void)?

Потому что определений foobar там ровно одно (в “code.cpp”), а в заголовочном файле — объявление.

theNamelessOne ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.